Merge RQ1A.210205.004 to stage-aosp-master - DO NOT MERGE

Merged-In: I17685f12959251d0974d727ba348221bfb693495
Change-Id: I775a1697595929aaf1258d48f45676ec18065cff
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+  license_type: NOTICE
+}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 0473bb8..9cab9b4 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,6 +8,7 @@
                include/input/
                libs/binder/fuzzer/
                libs/binder/ndk/
+               libs/binder/tests/fuzzers/
                libs/binderthreadstate/
                libs/graphicsenv/
                libs/gui/
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index 102c3f1..f9a12ef 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -17,10 +17,10 @@
 # Provides overrides to configure the Dalvik heap for a standard high density
 # phone with around 512MB total RAM.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapgrowthlimit=48m \
-    dalvik.vm.heapsize=128m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapgrowthlimit?=48m \
+    dalvik.vm.heapsize?=128m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/build/phone-hdpi-dalvik-heap.mk b/build/phone-hdpi-dalvik-heap.mk
index cc0ac90..71cce74 100644
--- a/build/phone-hdpi-dalvik-heap.mk
+++ b/build/phone-hdpi-dalvik-heap.mk
@@ -16,9 +16,9 @@
 
 # Provides overrides to configure the Dalvik heap for a standard high density phone.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapsize=32m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapsize?=32m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/build/phone-xhdpi-1024-dalvik-heap.mk b/build/phone-xhdpi-1024-dalvik-heap.mk
index 221227d..a522a7d 100644
--- a/build/phone-xhdpi-1024-dalvik-heap.mk
+++ b/build/phone-xhdpi-1024-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a xhdpi phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=96m \
-    dalvik.vm.heapsize=256m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=96m \
+    dalvik.vm.heapsize?=256m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/phone-xhdpi-2048-dalvik-heap.mk b/build/phone-xhdpi-2048-dalvik-heap.mk
index 7ccfc13..f38d2f2 100644
--- a/build/phone-xhdpi-2048-dalvik-heap.mk
+++ b/build/phone-xhdpi-2048-dalvik-heap.mk
@@ -17,10 +17,10 @@
 # Provides overrides to configure the Dalvik heap for a 2GB phone
 # 192m of RAM gives enough space for 5 8 megapixel camera bitmaps in RAM.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/phone-xhdpi-4096-dalvik-heap.mk b/build/phone-xhdpi-4096-dalvik-heap.mk
index 2b84841..a6ff5a8 100644
--- a/build/phone-xhdpi-4096-dalvik-heap.mk
+++ b/build/phone-xhdpi-4096-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 4GB phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.6 \
-    dalvik.vm.heapminfree=8m \
-    dalvik.vm.heapmaxfree=16m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.6 \
+    dalvik.vm.heapminfree?=8m \
+    dalvik.vm.heapmaxfree?=16m
diff --git a/build/phone-xhdpi-6144-dalvik-heap.mk b/build/phone-xhdpi-6144-dalvik-heap.mk
index 2bacc4a..f08830b 100644
--- a/build/phone-xhdpi-6144-dalvik-heap.mk
+++ b/build/phone-xhdpi-6144-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 6GB phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=256m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.5 \
-    dalvik.vm.heapminfree=8m \
-    dalvik.vm.heapmaxfree=32m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=256m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.5 \
+    dalvik.vm.heapminfree?=8m \
+    dalvik.vm.heapmaxfree?=32m
diff --git a/build/tablet-10in-xhdpi-2048-dalvik-heap.mk b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
index 1721fcc..48c6ea6 100644
--- a/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
+++ b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-7in-hdpi-1024-dalvik-heap.mk b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
index 7fd34b5..d0027dc 100644
--- a/build/tablet-7in-hdpi-1024-dalvik-heap.mk
+++ b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=80m \
-    dalvik.vm.heapsize=384m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=80m \
+    dalvik.vm.heapsize?=384m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-7in-xhdpi-2048-dalvik-heap.mk b/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
index e0f20c1..7c06b4b 100644
--- a/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
+++ b/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 320dpi 7" tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-dalvik-heap.mk b/build/tablet-dalvik-heap.mk
index f577fb8..1688665 100644
--- a/build/tablet-dalvik-heap.mk
+++ b/build/tablet-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapgrowthlimit=48m \
-    dalvik.vm.heapsize=256m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapgrowthlimit?=48m \
+    dalvik.vm.heapsize?=256m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 28fdaa4..2519ffa 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -124,6 +124,7 @@
     { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
     { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
     { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
+    { "sysprop",    "System Property",          ATRACE_TAG_SYSPROP, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
@@ -172,6 +173,8 @@
         { OPT,      "events/clk/clk_enable/enable" },
         { OPT,      "events/power/cpu_frequency_limits/enable" },
         { OPT,      "events/power/suspend_resume/enable" },
+        { OPT,      "events/cpuhp/cpuhp_enter/enable" },
+        { OPT,      "events/cpuhp/cpuhp_exit/enable" },
     } },
     { "membus",     "Memory Bus Utilization", 0, {
         { REQ,      "events/memory_bus/enable" },
@@ -239,6 +242,10 @@
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
         { OPT,      "events/ion/ion_stat/enable" },
     } },
+    { "thermal",  "Thermal event", 0, {
+        { REQ,      "events/thermal/thermal_temperature/enable" },
+        { OPT,      "events/thermal/cdev_update/enable" },
+    } },
 };
 
 struct TracingVendorCategory {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f442dae..db3a314 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -47,6 +47,10 @@
     chmod 0666 /sys/kernel/tracing/events/power/clock_set_rate/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
     chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter/enable
+    chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_enter/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_exit/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
     chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
@@ -166,6 +170,12 @@
     chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
     chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
 
+    # thermal
+    chmod 0666 /sys/kernel/debug/tracing/events/thermal/thermal_temperature/enable
+    chmod 0666 /sys/kernel/tracing/events/thermal/thermal_temperature/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable
+    chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable
+
 # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
     write /sys/kernel/tracing/tracing_on 0
@@ -210,6 +220,67 @@
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
 
+on post-fs-data
+# Create MM Events Tracing Instance for Kmem Activity Trigger
+    mkdir /sys/kernel/debug/tracing/instances/mm_events 0755 system system
+    mkdir /sys/kernel/tracing/instances/mm_events 0755 system system
+
+# Read and set per CPU buffer size
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/buffer_size_kb
+
+# Read and enable tracing
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/tracing_on
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/tracing_on
+
+# Read and truncate kernel trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/trace
+
+# Enable trace events
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/events/compaction/mm_compaction_begin/enable
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/events/compaction/mm_compaction_begin/enable
+
+# Read and clear per-CPU raw kernel trace
+# Cannot use wildcards in .rc files. Update this if there is a phone with
+# more CPUs.
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu0/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu0/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu1/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu1/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu2/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu2/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu3/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu3/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu4/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu4/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu5/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu5/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu6/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu6/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu7/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu7/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu8/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu8/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu9/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu9/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu10/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu10/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu11/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu11/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu12/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu12/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu13/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu13/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu14/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu14/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu15/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu15/trace
+
 on property:persist.debug.atrace.boottrace=1
     start boottrace
 
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
index 840ae47..f81994b 100644
--- a/cmds/bugreport/bugreport.cpp
+++ b/cmds/bugreport/bugreport.cpp
@@ -14,83 +14,19 @@
  * limitations under the License.
  */
 
-#include <errno.h>
 #include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-// This program will trigger the dumpstate service to start a call to
-// dumpstate, then connect to the dumpstate local client to read the
-// output. All of the dumpstate output is written to stdout, including
-// any errors encountered while reading/writing the output.
+// Only prints a warning redirecting to bugreportz.
 int main() {
+    fprintf(stderr,
+            "=============================================================================\n");
+    fprintf(stderr, "WARNING: Flat (text file, non-zipped) bugreports are deprecated.\n");
+    fprintf(stderr, "WARNING: Please generate zipped bugreports instead.\n");
+    fprintf(stderr, "WARNING: On the host use: adb bugreport filename.zip\n");
+    fprintf(stderr, "WARNING: On the device use: bugreportz\n");
+    fprintf(stderr, "WARNING: bugreportz will output the filename to use with adb pull.\n");
+    fprintf(stderr,
+            "=============================================================================\n\n\n");
 
-  fprintf(stderr, "=============================================================================\n");
-  fprintf(stderr, "WARNING: flat bugreports are deprecated, use adb bugreport <zip_file> instead\n");
-  fprintf(stderr, "=============================================================================\n\n\n");
-
-  // Start the dumpstate service.
-  property_set("ctl.start", "dumpstate");
-
-  // Socket will not be available until service starts.
-  int s = -1;
-  for (int i = 0; i < 20; i++) {
-    s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                            SOCK_STREAM);
-    if (s >= 0)
-      break;
-    // Try again in 1 second.
-    sleep(1);
-  }
-
-  if (s == -1) {
-    printf("Failed to connect to dumpstate service: %s\n", strerror(errno));
-    return 1;
-  }
-
-  // Set a timeout so that if nothing is read in 3 minutes, we'll stop
-  // reading and quit. No timeout in dumpstate is longer than 60 seconds,
-  // so this gives lots of leeway in case of unforeseen time outs.
-  struct timeval tv;
-  tv.tv_sec = 3 * 60;
-  tv.tv_usec = 0;
-  if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
-    printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));
-  }
-
-  while (1) {
-    char buffer[65536];
-    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
-    if (bytes_read == 0) {
-      break;
-    } else if (bytes_read == -1) {
-      // EAGAIN really means time out, so change the errno.
-      if (errno == EAGAIN) {
-        errno = ETIMEDOUT;
-      }
-      printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno));
-      break;
-    }
-
-    ssize_t bytes_to_send = bytes_read;
-    ssize_t bytes_written;
-    do {
-      bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
-                                               buffer + bytes_read - bytes_to_send,
-                                               bytes_to_send));
-      if (bytes_written == -1) {
-        printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
-               bytes_read, bytes_to_send, strerror(errno));
-        return 1;
-      }
-      bytes_to_send -= bytes_written;
-    } while (bytes_written != 0 && bytes_to_send > 0);
-  }
-
-  close(s);
-  return 0;
+    return 0;
 }
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index ded0ed3..203d748 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#include "bugreportz.h"
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -22,11 +26,6 @@
 
 #include <string>
 
-#include <android-base/file.h>
-#include <android-base/strings.h>
-
-#include "bugreportz.h"
-
 static constexpr char BEGIN_PREFIX[] = "BEGIN:";
 static constexpr char PROGRESS_PREFIX[] = "PROGRESS:";
 
@@ -70,6 +69,30 @@
     }
     // Process final line, in case it didn't finish with newline
     write_line(line, show_progress);
+    return EXIT_SUCCESS;
+}
 
+int bugreportz_stream(int s) {
+    while (1) {
+        char buffer[65536];
+        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
+        if (bytes_read == 0) {
+            break;
+        } else if (bytes_read == -1) {
+            // EAGAIN really means time out, so change the errno.
+            if (errno == EAGAIN) {
+                errno = ETIMEDOUT;
+            }
+            printf("FAIL:Bugreport read terminated abnormally (%s)\n", strerror(errno));
+            return EXIT_FAILURE;
+        }
+
+        if (!android::base::WriteFully(android::base::borrowed_fd(STDOUT_FILENO), buffer,
+                                       bytes_read)) {
+            printf("Failed to write data to stdout: trying to send %zd bytes (%s)\n", bytes_read,
+                   strerror(errno));
+            return EXIT_FAILURE;
+        }
+    }
     return EXIT_SUCCESS;
 }
diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h
index 7af289b..cdeceae 100644
--- a/cmds/bugreportz/bugreportz.h
+++ b/cmds/bugreportz/bugreportz.h
@@ -19,4 +19,8 @@
 // Ownership of the socket is not transferred.
 int bugreportz(int s, bool show_progress);
 
+// Calls dumpstate using the given socket and write the file content to stdout
+// instead of file location. Ownership of the socket is not transferred.
+int bugreportz_stream(int s);
+
 #endif  // BUGREPORTZ_H
diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp
index 40346be..cd2652c 100644
--- a/cmds/bugreportz/main.cpp
+++ b/cmds/bugreportz/main.cpp
@@ -26,13 +26,14 @@
 
 #include "bugreportz.h"
 
-static constexpr char VERSION[] = "1.1";
+static constexpr char VERSION[] = "1.2";
 
 static void show_usage() {
     fprintf(stderr,
-            "usage: bugreportz [-h | -v]\n"
+            "usage: bugreportz [-hpsv]\n"
             "  -h: to display this help message\n"
             "  -p: display progress\n"
+            "  -s: stream content to standard output\n"
             "  -v: to display the version\n"
             "  or no arguments to generate a zipped bugreport\n");
 }
@@ -43,10 +44,11 @@
 
 int main(int argc, char* argv[]) {
     bool show_progress = false;
+    bool stream_data = false;
     if (argc > 1) {
         /* parse arguments */
         int c;
-        while ((c = getopt(argc, argv, "hpv")) != -1) {
+        while ((c = getopt(argc, argv, "hpsv")) != -1) {
             switch (c) {
                 case 'h':
                     show_usage();
@@ -54,6 +56,9 @@
                 case 'p':
                     show_progress = true;
                     break;
+                case 's':
+                    stream_data = true;
+                    break;
                 case 'v':
                     show_version();
                     return EXIT_SUCCESS;
@@ -64,12 +69,22 @@
         }
     }
 
+    // We don't support any non-option arguments.
+    if (optind != argc) {
+        show_usage();
+        return EXIT_FAILURE;
+    }
+
     // TODO: code below was copy-and-pasted from bugreport.cpp (except by the
     // timeout value);
     // should be reused instead.
 
     // Start the dumpstatez service.
-    property_set("ctl.start", "dumpstatez");
+    if (stream_data) {
+        property_set("ctl.start", "dumpstate");
+    } else {
+        property_set("ctl.start", "dumpstatez");
+    }
 
     // Socket will not be available until service starts.
     int s = -1;
@@ -97,7 +112,12 @@
                 strerror(errno));
     }
 
-    int ret = bugreportz(s, show_progress);
+    int ret;
+    if (stream_data) {
+        ret = bugreportz_stream(s);
+    } else {
+        ret = bugreportz(s, show_progress);
+    }
 
     if (close(s) == -1) {
         fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index acca11a..80d14ac 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -105,34 +105,27 @@
     name: "dumpstate",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "DumpPool.cpp",
+        "TaskQueue.cpp",
         "dumpstate.cpp",
         "main.cpp",
     ],
     required: [
         "atrace",
-        "df",
-        "getprop",
         "ip",
         "iptables",
-        "ip6tables",
-        "kill",
         "librank",
         "logcat",
         "lpdump",
         "lpdumpd",
-        "lsmod",
-        "lsof",
-        "netstat",
-        "printenv",
         "procrank",
         "screencap",
         "showmap",
         "ss",
         "storaged",
-        "top",
-        "uptime",
+        "toolbox",
+        "toybox",
         "vdc",
-        "vril-dump",
     ],
     init_rc: ["dumpstate.rc"],
 }
@@ -141,6 +134,8 @@
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "DumpPool.cpp",
+        "TaskQueue.cpp",
         "dumpstate.cpp",
         "tests/dumpstate_test.cpp",
     ],
@@ -157,10 +152,14 @@
     name: "dumpstate_smoke_test",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "DumpPool.cpp",
+        "TaskQueue.cpp",
         "dumpstate.cpp",
         "tests/dumpstate_smoke_test.cpp",
     ],
     static_libs: ["libgmock"],
+    test_config: "dumpstate_smoke_test.xml",
+    test_suites: ["device-tests"],
 }
 
 
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
new file mode 100644
index 0000000..e15ac3f
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpPool.h"
+
+#include <array>
+#include <thread>
+
+#include <log/log.h>
+
+#include "dumpstate.h"
+#include "DumpstateInternal.h"
+#include "DumpstateUtil.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
+
+DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
+        log_duration_(true) {
+    assert(!tmp_root.empty());
+    deleteTempFiles(tmp_root_);
+}
+
+DumpPool::~DumpPool() {
+    shutdown();
+}
+
+void DumpPool::start(int thread_counts) {
+    assert(thread_counts > 0);
+    assert(threads_.empty());
+    if (thread_counts > MAX_THREAD_COUNT) {
+        thread_counts = MAX_THREAD_COUNT;
+    }
+    MYLOGI("Start thread pool:%d", thread_counts);
+    shutdown_ = false;
+    for (int i = 0; i < thread_counts; i++) {
+        threads_.emplace_back(std::thread([=]() {
+            setThreadName(pthread_self(), i + 1);
+            loop();
+        }));
+    }
+}
+
+void DumpPool::shutdown() {
+    std::unique_lock lock(lock_);
+    if (shutdown_ || threads_.empty()) {
+        return;
+    }
+    while (!tasks_.empty()) tasks_.pop();
+    futures_map_.clear();
+
+    shutdown_ = true;
+    condition_variable_.notify_all();
+    lock.unlock();
+
+    for (auto& thread : threads_) {
+        thread.join();
+    }
+    threads_.clear();
+    deleteTempFiles(tmp_root_);
+    MYLOGI("shutdown thread pool");
+}
+
+void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
+        int out_fd) {
+    DurationReporter duration_reporter("Wait for " + task_name, true);
+    auto iterator = futures_map_.find(task_name);
+    if (iterator == futures_map_.end()) {
+        MYLOGW("Task %s does not exist", task_name.c_str());
+        return;
+    }
+    Future future = iterator->second;
+    futures_map_.erase(iterator);
+
+    std::string result = future.get();
+    if (result.empty()) {
+        return;
+    }
+    DumpFileToFd(out_fd, title, result);
+    if (unlink(result.c_str())) {
+        MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+    }
+}
+
+void DumpPool::deleteTempFiles() {
+    deleteTempFiles(tmp_root_);
+}
+
+void DumpPool::setLogDuration(bool log_duration) {
+    log_duration_ = log_duration;
+}
+
+template <>
+void DumpPool::invokeTask<std::function<void()>>(std::function<void()> dump_func,
+        const std::string& duration_title, int out_fd) {
+    DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
+            /*verbose =*/false, out_fd);
+    std::invoke(dump_func);
+}
+
+template <>
+void DumpPool::invokeTask<std::function<void(int)>>(std::function<void(int)> dump_func,
+        const std::string& duration_title, int out_fd) {
+    DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
+            /*verbose =*/false, out_fd);
+    std::invoke(dump_func, out_fd);
+}
+
+std::unique_ptr<DumpPool::TmpFile> DumpPool::createTempFile() {
+    auto tmp_file_ptr = std::make_unique<TmpFile>();
+    std::string file_name_format = "%s/" + PREFIX_TMPFILE_NAME + "XXXXXX";
+    snprintf(tmp_file_ptr->path, sizeof(tmp_file_ptr->path), file_name_format.c_str(),
+             tmp_root_.c_str());
+    tmp_file_ptr->fd.reset(TEMP_FAILURE_RETRY(
+            mkostemp(tmp_file_ptr->path, O_CLOEXEC)));
+    if (tmp_file_ptr->fd.get() == -1) {
+        MYLOGE("open(%s, %s)\n", tmp_file_ptr->path, strerror(errno));
+        tmp_file_ptr = nullptr;
+        return tmp_file_ptr;
+    }
+    return tmp_file_ptr;
+}
+
+void DumpPool::deleteTempFiles(const std::string& folder) {
+    std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+            &closedir);
+    if (!dir_ptr) {
+        MYLOGE("Failed to opendir (%s): %s\n", folder.c_str(), strerror(errno));
+        return;
+    }
+    int dir_fd = dirfd(dir_ptr.get());
+    if (dir_fd < 0) {
+        MYLOGE("Failed to get fd of dir (%s): %s\n", folder.c_str(),
+               strerror(errno));
+        return;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(dir_ptr.get()))) {
+        if (de->d_type != DT_REG) {
+            continue;
+        }
+        std::string file_name(de->d_name);
+        if (file_name.find(PREFIX_TMPFILE_NAME) != 0) {
+            continue;
+        }
+        if (unlinkat(dir_fd, file_name.c_str(), 0)) {
+            MYLOGE("Failed to unlink (%s): %s\n", file_name.c_str(),
+                   strerror(errno));
+        }
+    }
+}
+
+void DumpPool::setThreadName(const pthread_t thread, int id) {
+    std::array<char, 15> name;
+    snprintf(name.data(), name.size(), "dumpstate_%d", id);
+    pthread_setname_np(thread, name.data());
+}
+
+void DumpPool::loop() {
+    std::unique_lock lock(lock_);
+    while (!shutdown_) {
+        if (tasks_.empty()) {
+            condition_variable_.wait(lock);
+            continue;
+        } else {
+            std::packaged_task<std::string()> task = std::move(tasks_.front());
+            tasks_.pop();
+            lock.unlock();
+            std::invoke(task);
+            lock.lock();
+        }
+    }
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
new file mode 100644
index 0000000..0c3c2cc
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+
+#include <future>
+#include <map>
+#include <queue>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/macros.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+class DumpPoolTest;
+
+/*
+ * A thread pool with the fixed number of threads to execute multiple dump tasks
+ * simultaneously for the dumpstate. The dump task is a callable function. It
+ * could include a file descriptor as a parameter to redirect dump results, if
+ * it needs to output results to the bugreport. This can avoid messing up
+ * bugreport's results when multiple dump tasks are running at the same time.
+ * Takes an example below for the usage of the DumpPool:
+ *
+ * void DumpFoo(int out_fd) {
+ *     dprintf(out_fd, "Dump result to out_fd ...");
+ * }
+ * ...
+ * DumpPool pool(tmp_root);
+ * pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
+ * ...
+ * pool.waitForTask("TaskName");
+ *
+ * DumpFoo is a callable function included a out_fd parameter. Using the
+ * enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
+ * std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
+ */
+class DumpPool {
+  friend class android::os::dumpstate::DumpPoolTest;
+
+  public:
+    /*
+     * Creates a thread pool.
+     *
+     * |tmp_root| A path to a temporary folder for threads to create temporary
+     * files.
+     */
+    explicit DumpPool(const std::string& tmp_root);
+    ~DumpPool();
+
+    /*
+     * Starts the threads in the pool.
+     *
+     * |thread_counts| the number of threads to start.
+     */
+    void start(int thread_counts = MAX_THREAD_COUNT);
+
+    /*
+     * Requests to shutdown the pool and waits until all threads exit the loop.
+     */
+    void shutdown();
+
+    /*
+     * Adds a task into the queue of the thread pool.
+     *
+     * |task_name| The name of the task. It's also the title of the
+     * DurationReporter log.
+     * |f| Callable function to execute the task.
+     * |args| A list of arguments.
+     *
+     * TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
+     */
+    template<class F, class... Args> void enqueueTask(const std::string& task_name, F&& f,
+            Args&&... args) {
+        std::function<void(void)> func = std::bind(std::forward<F>(f),
+                std::forward<Args>(args)...);
+        futures_map_[task_name] = post(task_name, func);
+        if (threads_.empty()) {
+            start();
+        }
+    }
+
+    /*
+     * Adds a task into the queue of the thread pool. The task takes a file
+     * descriptor as a parameter to redirect dump results to a temporary file.
+     *
+     * |task_name| The name of the task. It's also the title of the
+     * DurationReporter log.
+     * |f| Callable function to execute the task.
+     * |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
+     * argument needs to be included here.
+     */
+    template<class F, class... Args> void enqueueTaskWithFd(const std::string& task_name, F&& f,
+            Args&&... args) {
+        std::function<void(int)> func = std::bind(std::forward<F>(f),
+                std::forward<Args>(args)...);
+        futures_map_[task_name] = post(task_name, func);
+        if (threads_.empty()) {
+            start();
+        }
+    }
+
+    /*
+     * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+     */
+    void waitForTask(const std::string& task_name) {
+        waitForTask(task_name, "", STDOUT_FILENO);
+    }
+
+    /*
+     * Waits until the task is finished. Dumps the task results to the specified
+     * out_fd.
+     *
+     * |task_name| The name of the task.
+     * |title| Dump title string to the out_fd, an empty string for nothing.
+     * |out_fd| The target file to dump the result from the task.
+     */
+    void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
+
+    /*
+     * Deletes temporary files created by DumpPool.
+     */
+    void deleteTempFiles();
+
+    static const std::string PREFIX_TMPFILE_NAME;
+
+  private:
+    using Task = std::packaged_task<std::string()>;
+    using Future = std::shared_future<std::string>;
+
+    template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
+
+    template<class T> Future post(const std::string& task_name, T dump_func) {
+        Task packaged_task([=]() {
+            std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
+            if (!tmp_file_ptr) {
+                return std::string("");
+            }
+            invokeTask(dump_func, task_name, tmp_file_ptr->fd.get());
+            fsync(tmp_file_ptr->fd.get());
+            return std::string(tmp_file_ptr->path);
+        });
+        std::unique_lock lock(lock_);
+        auto future = packaged_task.get_future().share();
+        tasks_.push(std::move(packaged_task));
+        condition_variable_.notify_one();
+        return future;
+    }
+
+    typedef struct {
+      android::base::unique_fd fd;
+      char path[1024];
+    } TmpFile;
+
+    std::unique_ptr<TmpFile> createTempFile();
+    void deleteTempFiles(const std::string& folder);
+    void setThreadName(const pthread_t thread, int id);
+    void loop();
+
+    /*
+     * For test purpose only. Enables or disables logging duration of the task.
+     *
+     * |log_duration| if true, DurationReporter is initiated to log duration of
+     * the task.
+     */
+    void setLogDuration(bool log_duration);
+
+  private:
+    static const int MAX_THREAD_COUNT = 4;
+
+    /* A path to a temporary folder for threads to create temporary files. */
+    std::string tmp_root_;
+    bool shutdown_;
+    bool log_duration_; // For test purpose only, the default value is true.
+    std::mutex lock_;  // A lock for the tasks_.
+    std::condition_variable condition_variable_;
+
+    std::vector<std::thread> threads_;
+    std::queue<Task> tasks_;
+    std::map<std::string, Future> futures_map_;
+
+    DISALLOW_COPY_AND_ASSIGN(DumpPool);
+};
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
+
+#endif //FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index bbc724c..3091f6b 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -69,7 +69,7 @@
 
     static const std::vector<std::string> group_names{
         "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats",
-            "readproc", "bluetooth", "wakelock"};
+            "readproc", "bluetooth", "wakelock", "nfc"};
     std::vector<gid_t> groups(group_names.size(), 0);
     for (size_t i = 0; i < group_names.size(); ++i) {
         grp = getgrnam(group_names[i].c_str());
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index bfcc058..ba25a5a 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -39,8 +39,13 @@
     std::string calling_package;
 };
 
-static binder::Status exception(uint32_t code, const std::string& msg) {
-    MYLOGE("%s (%d) ", msg.c_str(), code);
+static binder::Status exception(uint32_t code, const std::string& msg,
+                                const std::string& extra_msg = "") {
+    if (extra_msg.empty()) {
+        MYLOGE("%s (%d) ", msg.c_str(), code);
+    } else {
+        MYLOGE("%s %s (%d) ", msg.c_str(), extra_msg.c_str(), code);
+    }
     return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
 }
 
@@ -60,7 +65,7 @@
 
 }  // namespace
 
-DumpstateService::DumpstateService() : ds_(nullptr) {
+DumpstateService::DumpstateService() : ds_(nullptr), calling_uid_(-1), calling_package_() {
 }
 
 char const* DumpstateService::getServiceName() {
@@ -131,6 +136,10 @@
     ds_->SetOptions(std::move(options));
     ds_->listener_ = listener;
 
+    // Track caller info for cancellation purposes.
+    calling_uid_ = calling_uid;
+    calling_package_ = calling_package;
+
     DumpstateInfo* ds_info = new DumpstateInfo();
     ds_info->ds = ds_;
     ds_info->calling_uid = calling_uid;
@@ -149,8 +158,20 @@
     return binder::Status::ok();
 }
 
-binder::Status DumpstateService::cancelBugreport() {
+binder::Status DumpstateService::cancelBugreport(int32_t calling_uid,
+                                                 const std::string& calling_package) {
     std::lock_guard<std::mutex> lock(lock_);
+    if (calling_uid != calling_uid_ || calling_package != calling_package_) {
+        // Note: we use a SecurityException to prevent BugreportManagerServiceImpl from killing the
+        // report in progress (from another caller).
+        return exception(
+            binder::Status::EX_SECURITY,
+            StringPrintf("Cancellation requested by %d/%s does not match report in "
+                         "progress",
+                         calling_uid, calling_package.c_str()),
+            // Sharing the owner of the BR is a (minor) leak, so leave it out of the app's exception
+            StringPrintf("started by %d/%s", calling_uid_, calling_package_.c_str()));
+    }
     ds_->Cancel();
     return binder::Status::ok();
 }
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index ac8d3ac..3ec8471 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -44,8 +44,7 @@
                                   const sp<IDumpstateListener>& listener,
                                   bool is_screenshot_requested) override;
 
-    // No-op
-    binder::Status cancelBugreport();
+    binder::Status cancelBugreport(int32_t calling_uid, const std::string& calling_package);
 
   private:
     // Dumpstate object which contains all the bugreporting logic.
@@ -53,6 +52,8 @@
     // one bugreport.
     // This service does not own this object.
     Dumpstate* ds_;
+    int32_t calling_uid_;
+    std::string calling_package_;
     std::mutex lock_;
 };
 
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 4b69607..c833d0e 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -124,6 +124,12 @@
     return *this;
 }
 
+CommandOptions::CommandOptionsBuilder&
+CommandOptions::CommandOptionsBuilder::CloseAllFileDescriptorsOnExec() {
+    values.close_all_fds_on_exec_ = true;
+    return *this;
+}
+
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Log(
     const std::string& message) {
     values.logging_message_ = message;
@@ -137,6 +143,7 @@
 CommandOptions::CommandOptionsValues::CommandOptionsValues(int64_t timeout_ms)
     : timeout_ms_(timeout_ms),
       always_(false),
+      close_all_fds_on_exec_(false),
       account_mode_(DONT_DROP_ROOT),
       output_mode_(NORMAL_OUTPUT),
       logging_message_("") {
@@ -157,6 +164,10 @@
     return values.always_;
 }
 
+bool CommandOptions::ShouldCloseAllFileDescriptorsOnExec() const {
+    return values.close_all_fds_on_exec_;
+}
+
 PrivilegeMode CommandOptions::PrivilegeMode() const {
     return values.account_mode_;
 }
@@ -180,6 +191,7 @@
 std::string PropertiesHelper::build_type_ = "";
 int PropertiesHelper::dry_run_ = -1;
 int PropertiesHelper::unroot_ = -1;
+int PropertiesHelper::parallel_run_ = -1;
 
 bool PropertiesHelper::IsUserBuild() {
     if (build_type_.empty()) {
@@ -202,6 +214,14 @@
     return unroot_ == 1;
 }
 
+bool PropertiesHelper::IsParallelRun() {
+    if (parallel_run_ == -1) {
+        parallel_run_ = android::base::GetBoolProperty("dumpstate.parallel_run",
+                /* default_value = */true) ? 1 : 0;
+    }
+    return parallel_run_ == 1;
+}
+
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
     if (fd.get() < 0) {
@@ -268,7 +288,8 @@
         MYLOGI(logging_message.c_str(), command_string.c_str());
     }
 
-    bool silent = (options.OutputMode() == REDIRECT_TO_STDERR);
+    bool silent = (options.OutputMode() == REDIRECT_TO_STDERR ||
+                   options.ShouldCloseAllFileDescriptorsOnExec());
     bool redirecting_to_fd = STDOUT_FILENO != fd;
 
     if (PropertiesHelper::IsDryRun() && !options.Always()) {
@@ -305,7 +326,27 @@
             return -1;
         }
 
-        if (silent) {
+        if (options.ShouldCloseAllFileDescriptorsOnExec()) {
+            int devnull_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
+            TEMP_FAILURE_RETRY(dup2(devnull_fd, STDIN_FILENO));
+            close(devnull_fd);
+            devnull_fd = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY));
+            TEMP_FAILURE_RETRY(dup2(devnull_fd, STDOUT_FILENO));
+            TEMP_FAILURE_RETRY(dup2(devnull_fd, STDERR_FILENO));
+            close(devnull_fd);
+            // This is to avoid leaking FDs that, accidentally, have not been
+            // marked as O_CLOEXEC. Leaking FDs across exec can cause failures
+            // when execing a process that has a SELinux auto_trans rule.
+            // Here we assume that the dumpstate process didn't open more than
+            // 1000 FDs. In theory we could iterate through /proc/self/fd/, but
+            // doing that in a fork-safe way is too complex and not worth it
+            // (opendir()/readdir() do heap allocations and take locks).
+            for (int i = 0; i < 1000; i++) {
+                if (i != STDIN_FILENO && i!= STDOUT_FILENO && i != STDERR_FILENO) {
+                    close(i);
+                }
+            }
+        } else if (silent) {
             // Redirects stdout to stderr
             TEMP_FAILURE_RETRY(dup2(STDERR_FILENO, STDOUT_FILENO));
         } else if (redirecting_to_fd) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index b7ac25c..b00c46e 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -80,6 +80,7 @@
 
         int64_t timeout_ms_;
         bool always_;
+        bool close_all_fds_on_exec_;
         PrivilegeMode account_mode_;
         OutputMode output_mode_;
         std::string logging_message_;
@@ -112,6 +113,13 @@
         CommandOptionsBuilder& DropRoot();
         /* Sets the command's OutputMode as `REDIRECT_TO_STDERR` */
         CommandOptionsBuilder& RedirectStderr();
+        /* Closes all file descriptors before exec-ing the target process. This
+         * includes also stdio pipes, which are dup-ed on /dev/null. It prevents
+         * leaking opened FDs to the target process, which in turn can hit
+         * selinux denials in presence of auto_trans rules.
+         */
+        CommandOptionsBuilder& CloseAllFileDescriptorsOnExec();
+
         /* When not empty, logs a message before executing the command.
          * Must contain a `%s`, which will be replaced by the full command line, and end on `\n`. */
         CommandOptionsBuilder& Log(const std::string& message);
@@ -130,6 +138,8 @@
     int64_t TimeoutInMs() const;
     /* Checks whether the command should always be run, even on dry-run mode. */
     bool Always() const;
+    /* Checks whether all FDs should be closed prior to the exec() calls. */
+    bool ShouldCloseAllFileDescriptorsOnExec() const;
     /** Gets the PrivilegeMode of the command. */
     PrivilegeMode PrivilegeMode() const;
     /** Gets the OutputMode of the command. */
@@ -176,10 +186,18 @@
      */
     static bool IsUnroot();
 
+    /*
+     * Whether or not the parallel run is enabled. Setting the system property
+     * 'dumpstate.parallel_run' to false to disable it, otherwise it returns
+     * true by default.
+     */
+    static bool IsParallelRun();
+
   private:
     static std::string build_type_;
     static int dry_run_;
     static int unroot_;
+    static int parallel_run_;
 };
 
 /*
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 083944f..839a2c3 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -1,7 +1,28 @@
 {
   "presubmit": [
     {
+      "name": "BugreportManagerTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        }
+      ]
+    },
+    {
+      "name": "dumpstate_smoke_test"
+    },
+    {
       "name": "dumpstate_test"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "BugreportManagerTestCases"
+    }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/base/packages/Shell"
+    }
   ]
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/TaskQueue.cpp b/cmds/dumpstate/TaskQueue.cpp
new file mode 100644
index 0000000..8550aec
--- /dev/null
+++ b/cmds/dumpstate/TaskQueue.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TaskQueue.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+TaskQueue::~TaskQueue() {
+    run(/* do_cancel = */true);
+}
+
+void TaskQueue::run(bool do_cancel) {
+    std::unique_lock lock(lock_);
+    while (!tasks_.empty()) {
+        auto task = tasks_.front();
+        tasks_.pop();
+        lock.unlock();
+        std::invoke(task, do_cancel);
+        lock.lock();
+    }
+}
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
diff --git a/cmds/dumpstate/TaskQueue.h b/cmds/dumpstate/TaskQueue.h
new file mode 100644
index 0000000..b7e72f1
--- /dev/null
+++ b/cmds/dumpstate/TaskQueue.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
+#define FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
+
+#include <mutex>
+#include <queue>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+/*
+ * A task queue for dumpstate to collect tasks such as adding file to the zip
+ * which are needed to run in a single thread. The task is a callable function
+ * included a cancel task boolean parameter. The TaskQueue could
+ * cancel the task in the destructor if the task has never been called.
+ */
+class TaskQueue {
+  public:
+    TaskQueue() = default;
+    ~TaskQueue();
+
+    /*
+     * Adds a task into the queue.
+     *
+     * |f| Callable function to execute the task. The function must include a
+     *     boolean parameter for TaskQueue to notify whether the task is
+     *     cancelled or not.
+     * |args| A list of arguments.
+     */
+    template<class F, class... Args> void add(F&& f, Args&&... args) {
+        auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
+        std::unique_lock lock(lock_);
+        tasks_.emplace([=](bool cancelled) {
+            std::invoke(func, cancelled);
+        });
+    }
+
+    /*
+     * Invokes all tasks in the task queue.
+     *
+     * |do_cancel| true to cancel all tasks in the queue.
+     */
+    void run(bool do_cancel);
+
+  private:
+    using Task = std::function<void(bool)>;
+
+    std::mutex lock_;
+    std::queue<Task> tasks_;
+
+    DISALLOW_COPY_AND_ASSIGN(TaskQueue);
+};
+
+}  // namespace dumpstate
+}  // namespace os
+}  // namespace android
+
+#endif //FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index ba008bb..0793f0b 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2016, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,9 @@
 import android.os.IDumpstateListener;
 
 /**
-  * Binder interface for the currently running dumpstate process.
-  * {@hide}
-  */
+ * Binder interface for the currently running dumpstate process.
+ * {@hide}
+ */
 interface IDumpstate {
 
     // NOTE: If you add to or change these modes, please also change the corresponding enums
@@ -49,10 +49,10 @@
     // Default mode.
     const int BUGREPORT_MODE_DEFAULT = 6;
 
-    /*
+    /**
      * Starts a bugreport in the background.
      *
-     *<p>Shows the user a dialog to get consent for sharing the bugreport with the calling
+     * <p>Shows the user a dialog to get consent for sharing the bugreport with the calling
      * application. If they deny {@link IDumpstateListener#onError} will be called. If they
      * consent and bugreport generation is successful artifacts will be copied to the given fds and
      * {@link IDumpstateListener#onFinished} will be called. If there
@@ -71,8 +71,15 @@
                         int bugreportMode, IDumpstateListener listener,
                         boolean isScreenshotRequested);
 
-    /*
+    /**
      * Cancels the bugreport currently in progress.
+     *
+     * <p>The caller must match the original caller of {@link #startBugreport} in order for the
+     * report to actually be cancelled. A {@link SecurityException} is reported if a mismatch is
+     * detected.
+     *
+     * @param callingUid UID of the original application that requested the cancellation.
+     * @param callingPackage package of the original application that requested the cancellation.
      */
-    void cancelBugreport();
+    void cancelBugreport(int callingUid, @utf8InCpp String callingPackage);
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index a5e6c68..50c1624 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -21,8 +21,6 @@
   *
   * <p>When bugreport creation is complete one of {@code onError} or {@code onFinished} is called.
   *
-  * <p>These methods are synchronous by design in order to make dumpstate's lifecycle simpler
-  * to handle.
   *
   * {@hide}
   */
@@ -54,10 +52,8 @@
 
     /**
      * Called on an error condition with one of the error codes listed above.
-     * This is not an asynchronous method since it can race with dumpstate exiting, thus triggering
-     * death recipient.
      */
-    void onError(int errorCode);
+    oneway void onError(int errorCode);
 
     /**
      * Called when taking bugreport finishes successfully.
@@ -72,5 +68,5 @@
     /**
      * Called when ui intensive bugreport dumps are finished.
      */
-    oneway void onUiIntensiveBugreportDumpsFinished(String callingPackage);
+    oneway void onUiIntensiveBugreportDumpsFinished();
 }
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 581d3de..fbb0a18 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mount.h>
 #include <sys/poll.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
@@ -78,6 +79,7 @@
 #include <hardware_legacy/power.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
+#include <log/log_read.h>
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
@@ -94,6 +96,7 @@
 using ::android::hardware::dumpstate::V1_1::toString;
 using ::std::literals::chrono_literals::operator""ms;
 using ::std::literals::chrono_literals::operator""s;
+using ::std::placeholders::_1;
 
 // TODO: remove once moved to namespace
 using android::defaultServiceManager;
@@ -112,7 +115,9 @@
 using android::os::IDumpstateListener;
 using android::os::dumpstate::CommandOptions;
 using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::DumpPool;
 using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::TaskQueue;
 
 // Keep in sync with
 // frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -125,8 +130,8 @@
 static Dumpstate& ds = Dumpstate::GetInstance();
 static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
                       const CommandOptions& options = CommandOptions::DEFAULT,
-                      bool verbose_duration = false) {
-    return ds.RunCommand(title, full_command, options, verbose_duration);
+                      bool verbose_duration = false, int out_fd = STDOUT_FILENO) {
+    return ds.RunCommand(title, full_command, options, verbose_duration, out_fd);
 }
 
 // Reasonable value for max stats.
@@ -170,6 +175,7 @@
 #define SNAPSHOTCTL_LOG_DIR "/data/misc/snapshotctl_log"
 #define LINKERCONFIG_DIR "/linkerconfig"
 #define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
+#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
 
 // TODO(narayan): Since this information has to be kept in sync
 // with tombstoned, we should just put it in a common header.
@@ -195,8 +201,35 @@
     func_ptr(__VA_ARGS__);                                  \
     RETURN_IF_USER_DENIED_CONSENT();
 
+// Runs func_ptr, and logs a duration report after it's finished.
+#define RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, ...)      \
+    {                                                            \
+        DurationReporter duration_reporter_in_macro(log_title);  \
+        func_ptr(__VA_ARGS__);                                   \
+    }
+
+// Similar with RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK, an additional duration report
+// is output after a slow function is finished.
+#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(log_title, func_ptr, ...) \
+    RETURN_IF_USER_DENIED_CONSENT();                                           \
+    RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__);               \
+    RETURN_IF_USER_DENIED_CONSENT();
+
+#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
+    RETURN_IF_USER_DENIED_CONSENT();                      \
+    pool_ptr->waitForTask(task_name);                     \
+    RETURN_IF_USER_DENIED_CONSENT();
+
 static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
 
+// Names of parallel tasks, they are used for the DumpPool to identify the dump
+// task and the log title of the duration report.
+static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
+static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
+static const std::string DUMP_HALS_TASK = "DUMP HALS";
+static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
+static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
+
 namespace android {
 namespace os {
 namespace {
@@ -305,8 +338,12 @@
 
 static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
                        const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
-                       long dumpsysTimeoutMs = 0) {
-    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
+                       long dumpsysTimeoutMs = 0, int out_fd = STDOUT_FILENO) {
+    return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs, out_fd);
+}
+static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
+                       int out_fd) {
+    return ds.RunDumpsys(title, dumpsysArgs, Dumpstate::DEFAULT_DUMPSYS, 0, out_fd);
 }
 static int DumpFile(const std::string& title, const std::string& path) {
     return ds.DumpFile(title, path);
@@ -661,18 +698,31 @@
 
 static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
 
-/* timeout in ms to read a list of buffers */
+// Returns the actual readable size of the given buffer or -1 on error.
+static long logcat_buffer_readable_size(const std::string& buffer) {
+    std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
+        android_logger_list_alloc(0, 0, 0), &android_logger_list_free};
+    auto logger = android_logger_open(logger_list.get(), android_name_to_log_id(buffer.c_str()));
+
+    return android_logger_get_log_readable_size(logger);
+}
+
+// Returns timeout in ms to read a list of buffers.
 static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
     unsigned long timeout_ms = 0;
     for (const auto& buffer : buffers) {
-        log_id_t id = android_name_to_log_id(buffer.c_str());
-        unsigned long property_size = __android_logger_get_buffer_size(id);
-        /* Engineering margin is ten-fold our guess */
-        timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
+        long readable_size = logcat_buffer_readable_size(buffer);
+        if (readable_size > 0) {
+            // Engineering margin is ten-fold our guess.
+            timeout_ms += 10 * (readable_size + worst_write_perf) / worst_write_perf;
+        }
     }
     return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
 }
 
+// Opens a socket and returns its file descriptor.
+static int open_socket(const char* service);
+
 Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
 }
 
@@ -751,8 +801,9 @@
     RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
                    CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
-    printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
-           PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
+    printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
+           id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
+           options_->args.c_str(), options_->bugreport_mode.c_str());
     printf("\n");
 }
 
@@ -982,7 +1033,6 @@
         MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
         return;
     }
-    DurationReporter duration_reporter("INCIDENT REPORT");
     const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
     auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
                 O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
@@ -997,9 +1047,29 @@
         // Use a different name from "incident.proto"
         // /proto/incident.proto is reserved for incident service dump
         // i.e. metadata for debugging.
-        ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
+        ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "incident_report" + kProtoExt,
+                path);
+    } else {
+        unlink(path.c_str());
     }
-    unlink(path.c_str());
+}
+
+static void MaybeAddSystemTraceToZip() {
+    // This function copies into the .zip the system trace that was snapshotted
+    // by the early call to MaybeSnapshotSystemTrace(), if any background
+    // tracing was happening.
+    if (!ds.IsZipping()) {
+        MYLOGD("Not dumping system trace because it's not a zipped bugreport\n");
+        return;
+    }
+    if (!ds.has_system_trace_) {
+        // No background trace was happening at the time dumpstate was invoked.
+        return;
+    }
+    ds.AddZipEntry(
+            ZIP_ROOT_DIR + SYSTEM_TRACE_SNAPSHOT,
+            SYSTEM_TRACE_SNAPSHOT);
+    android::os::UnlinkAndLogOnError(SYSTEM_TRACE_SNAPSHOT);
 }
 
 static void DumpVisibleWindowViews() {
@@ -1294,15 +1364,20 @@
                            /* timeout= */ 90s, /* service_timeout= */ 10s);
 }
 
-static void DumpHals() {
+/*
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpHals(int out_fd = STDOUT_FILENO) {
     if (!ds.IsZipping()) {
-        RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
-                   CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+        RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
+                   CommandOptions::WithTimeout(60).AsRootIfAvailable().Build());
         return;
     }
-    DurationReporter duration_reporter("DUMP HALS");
-    RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
-               CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+    RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
+               CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
+               false, out_fd);
 
     using android::hidl::manager::V1_0::IServiceManager;
     using android::hardware::defaultServiceManager;
@@ -1324,6 +1399,7 @@
                             }, '_');
             const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
 
+            bool empty = false;
             {
                 auto fd = android::base::unique_fd(
                     TEMP_FAILURE_RETRY(open(path.c_str(),
@@ -1338,13 +1414,14 @@
                         {"lshal", "debug", "-E", interface},
                         CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
 
-                bool empty = 0 == lseek(fd, 0, SEEK_END);
-                if (!empty) {
-                    ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
-                }
+                empty = 0 == lseek(fd, 0, SEEK_END);
             }
-
-            unlink(path.c_str());
+            if (!empty) {
+                ds.EnqueueAddZipEntryAndCleanupIfNeeded("lshal-debug/" + cleanName + ".txt",
+                        path);
+            } else {
+                unlink(path.c_str());
+            }
         }
     });
 
@@ -1416,6 +1493,8 @@
 
     RunDumpsys("DUMPSYS NETWORK_SERVICE_LIMITED", {"wifi", "-a"},
                CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS CONNECTIVITY REQUESTS", {"connectivity", "requests"},
+               CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
 
     printf("========================================================\n");
     printf("== Dropbox crashes\n");
@@ -1432,6 +1511,73 @@
     printf("========================================================\n");
 }
 
+/*
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpCheckins(int out_fd = STDOUT_FILENO) {
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Checkins\n");
+    dprintf(out_fd, "========================================================\n");
+
+    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
+    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
+    RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
+    RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
+    RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
+    RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"}, out_fd);
+}
+
+/*
+ * Runs dumpsys on activity service to dump all application activities, services
+ * and providers in the device.
+ *
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpAppInfos(int out_fd = STDOUT_FILENO) {
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Running Application Activities\n");
+    dprintf(out_fd, "========================================================\n");
+
+    // The following dumpsys internally collects output from running apps, so it can take a long
+    // time. So let's extend the timeout.
+
+    const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
+
+    RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Running Application Services (platform)\n");
+    dprintf(out_fd, "========================================================\n");
+
+    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
+            DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Running Application Services (non-platform)\n");
+    dprintf(out_fd, "========================================================\n");
+
+    RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Running Application Providers (platform)\n");
+    dprintf(out_fd, "========================================================\n");
+
+    RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Running Application Providers (non-platform)\n");
+    dprintf(out_fd, "========================================================\n");
+
+    RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
+            DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+}
+
 // Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
 // via the consent they are shown. Ignores other errors that occur while running various
 // commands. The consent checking is currently done around long running tasks, which happen to
@@ -1439,6 +1585,18 @@
 static Dumpstate::RunStatus dumpstate() {
     DurationReporter duration_reporter("DUMPSTATE");
 
+    // Enqueue slow functions into the thread pool, if the parallel run is enabled.
+    if (ds.dump_pool_) {
+        // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
+        // drop root user. Restarts it with two threads for the parallel run.
+        ds.dump_pool_->start(/* thread_counts = */2);
+
+        ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+        ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+        ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+        ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
+    }
+
     // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
     // check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
     // in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
@@ -1470,7 +1628,11 @@
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
                                          CommandOptions::AS_ROOT);
 
-    DumpHals();
+    if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
+    }
 
     RunCommand("PRINTENV", {"printenv"});
     RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -1481,8 +1643,7 @@
         RunCommand("LSMOD", {"lsmod"});
     }
 
-    if (__android_logger_property_get_bool(
-            "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
+    if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
         DoKernelLogcat();
     } else {
         do_dmesg();
@@ -1497,6 +1658,8 @@
 
     /* Dump Bluetooth HCI logs */
     ds.AddDir("/data/misc/bluetooth/logs", true);
+    /* Dump Nfc NCI logs */
+    ds.AddDir("/data/misc/nfc/logs", true);
 
     if (ds.options_->do_screenshot && !ds.do_early_screenshot_) {
         MYLOGI("taking late screenshot\n");
@@ -1505,6 +1668,8 @@
 
     AddAnrTraceFiles();
 
+    MaybeAddSystemTraceToZip();
+
     // NOTE: tombstones are always added as separate entries in the zip archive
     // and are not interspersed with the main report.
     const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
@@ -1552,7 +1717,11 @@
 
     ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
+    if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
+    }
 
     /* Migrate the ril_dumpstate to a device specific dumpstate? */
     int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
@@ -1574,57 +1743,13 @@
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
 
-    printf("========================================================\n");
-    printf("== Checkins\n");
-    printf("========================================================\n");
+    if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
+    }
 
-    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
-
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
-
-    RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
-    RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
-    RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
-    RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
-
-    printf("========================================================\n");
-    printf("== Running Application Activities\n");
-    printf("========================================================\n");
-
-    // The following dumpsys internally collects output from running apps, so it can take a long
-    // time. So let's extend the timeout.
-
-    const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
-
-    RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
-
-    printf("========================================================\n");
-    printf("== Running Application Services (platform)\n");
-    printf("========================================================\n");
-
-    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
-            DUMPSYS_COMPONENTS_OPTIONS);
-
-    printf("========================================================\n");
-    printf("== Running Application Services (non-platform)\n");
-    printf("========================================================\n");
-
-    RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
-            DUMPSYS_COMPONENTS_OPTIONS);
-
-    printf("========================================================\n");
-    printf("== Running Application Providers (platform)\n");
-    printf("========================================================\n");
-
-    RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
-            DUMPSYS_COMPONENTS_OPTIONS);
-
-    printf("========================================================\n");
-    printf("== Running Application Providers (non-platform)\n");
-    printf("========================================================\n");
-
-    RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
-            DUMPSYS_COMPONENTS_OPTIONS);
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpAppInfos);
 
     printf("========================================================\n");
     printf("== Dropbox crashes\n");
@@ -1649,7 +1774,12 @@
     // Add linker configuration directory
     ds.AddDir(LINKERCONFIG_DIR, true);
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
+    if (ds.dump_pool_) {
+        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
+                DumpIncidentReport);
+    }
 
     return Dumpstate::RunStatus::OK;
 }
@@ -1670,7 +1800,18 @@
     time_t logcat_ts = time(nullptr);
 
     /* collect stack traces from Dalvik and native processes (needs root) */
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
+    if (dump_pool_) {
+        RETURN_IF_USER_DENIED_CONSENT();
+        // One thread is enough since we only need to enqueue DumpTraces here.
+        dump_pool_->start(/* thread_counts = */1);
+
+        // DumpTraces takes long time, post it to the another thread in the
+        // pool, if pool is available
+        dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
+    } else {
+        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
+                &dump_traces_path);
+    }
 
     /* Run some operations that require root. */
     ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
@@ -1713,6 +1854,15 @@
     DumpFile("PSI memory", "/proc/pressure/memory");
     DumpFile("PSI io", "/proc/pressure/io");
 
+    if (dump_pool_) {
+        RETURN_IF_USER_DENIED_CONSENT();
+        dump_pool_->waitForTask(DUMP_TRACES_TASK);
+
+        // Current running thread in the pool is the root user also. Shutdown
+        // the pool and restart later to ensure all threads in the pool could
+        // drop the root user.
+        dump_pool_->shutdown();
+    }
     if (!DropRootUser()) {
         return Dumpstate::RunStatus::ERROR;
     }
@@ -1724,31 +1874,39 @@
     return status;
 }
 
+// Common states for telephony and wifi which are needed to be collected before
+// dumpstate drop the root user.
+static void DumpstateRadioAsRoot() {
+    DumpIpTablesAsRoot();
+    ds.AddDir(LOGPERSIST_DATA_DIR, false);
+}
+
 // This method collects common dumpsys for telephony and wifi. Typically, wifi
 // reports are fine to include all information, but telephony reports on user
 // builds need to strip some content (see DumpstateTelephonyOnly).
 static void DumpstateRadioCommon(bool include_sensitive_info = true) {
-    DumpIpTablesAsRoot();
-
-    ds.AddDir(LOGPERSIST_DATA_DIR, false);
-
-    if (!DropRootUser()) {
-        return;
-    }
-
     // We need to be picky about some stuff for telephony reports on user builds.
     if (!include_sensitive_info) {
         // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
         DoRadioLogcat();
     } else {
+        // DumpHals takes long time, post it to the another thread in the pool,
+        // if pool is available.
+        if (ds.dump_pool_) {
+            ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+        }
         // Contains various system properties and process startup info.
         do_dmesg();
         // Logs other than the radio buffer may contain package/component names and potential PII.
         DoLogcat();
         // Too broad for connectivity problems.
         DoKmsg();
-        // Contains unrelated hardware info (camera, NFC, biometrics, ...).
-        DumpHals();
+        // DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
+        if (ds.dump_pool_) {
+            ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
+        } else {
+            RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
+        }
     }
 
     DumpPacketStats();
@@ -1772,6 +1930,21 @@
 
     const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
 
+    DumpstateRadioAsRoot();
+    if (!DropRootUser()) {
+        return;
+    }
+
+    // Starts thread pool after the root user is dropped, and two additional threads
+    // are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
+    if (ds.dump_pool_) {
+        ds.dump_pool_->start(/*thread_counts =*/2);
+
+        // DumpstateBoard takes long time, post it to the another thread in the pool,
+        // if pool is available.
+        ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+    }
+
     DumpstateRadioCommon(include_sensitive_info);
 
     if (include_sensitive_info) {
@@ -1848,12 +2021,29 @@
     printf("========================================================\n");
     printf("== dumpstate: done (id %d)\n", ds.id_);
     printf("========================================================\n");
+
+    if (ds.dump_pool_) {
+        ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
+    } else {
+        RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
+    }
 }
 
 // This method collects dumpsys for wifi debugging only
 static void DumpstateWifiOnly() {
     DurationReporter duration_reporter("DUMPSTATE");
 
+    DumpstateRadioAsRoot();
+    if (!DropRootUser()) {
+        return;
+    }
+
+    // Starts thread pool after the root user is dropped. Only one additional
+    // thread is needed for DumpHals in the DumpstateRadioCommon.
+    if (ds.dump_pool_) {
+        ds.dump_pool_->start(/*thread_counts =*/1);
+    }
+
     DumpstateRadioCommon();
 
     printf("========================================================\n");
@@ -1871,8 +2061,6 @@
 }
 
 Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
-    DurationReporter duration_reporter("DUMP TRACES");
-
     const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
     const size_t buf_size = temp_file_pattern.length() + 1;
     std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
@@ -1980,17 +2168,32 @@
     return RunStatus::OK;
 }
 
-void Dumpstate::DumpstateBoard() {
-    DurationReporter duration_reporter("dumpstate_board()");
-    printf("========================================================\n");
-    printf("== Board\n");
-    printf("========================================================\n");
+void Dumpstate::DumpstateBoard(int out_fd) {
+    dprintf(out_fd, "========================================================\n");
+    dprintf(out_fd, "== Board\n");
+    dprintf(out_fd, "========================================================\n");
 
     if (!IsZipping()) {
         MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
         return;
     }
 
+    /*
+     * mount debugfs for non-user builds which launch with S and unmount it
+     * after invoking dumpstateBoard_* methods. This is to enable debug builds
+     * to not have debugfs mounted during runtime. It will also ensure that
+     * debugfs is only accessed by the dumpstate HAL.
+     */
+    auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0);
+    bool mount_debugfs = !PropertiesHelper::IsUserBuild() && api_level >= 31;
+
+    if (mount_debugfs) {
+        RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
+                   AS_ROOT_20);
+        RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"},
+                   AS_ROOT_20);
+    }
+
     std::vector<std::string> paths;
     std::vector<android::base::ScopeGuard<std::function<void()>>> remover;
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
@@ -2090,6 +2293,10 @@
                "there might be racing in content\n", killing_timeout_sec);
     }
 
+    if (mount_debugfs) {
+        RunCommand("unmount debugfs", {"umount", "/sys/kernel/debug"}, AS_ROOT_20);
+    }
+
     auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
     for (size_t i = 0; i < paths.size(); i++) {
         struct stat s;
@@ -2110,27 +2317,26 @@
             MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
             continue;
         }
-        AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
-        printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
+        remover[i].Disable();
+        EnqueueAddZipEntryAndCleanupIfNeeded(kDumpstateBoardFiles[i], paths[i]);
+        dprintf(out_fd, "*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
     }
 }
 
 static void ShowUsage() {
     fprintf(stderr,
-            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-d] [-p] "
-            "[-z] [-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
+            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o directory] [-p] "
+            "[-s] [-S] [-q] [-P] [-R] [-L] [-V version]\n"
             "  -h: display this help message\n"
             "  -b: play sound file instead of vibrate, at beginning of job\n"
             "  -e: play sound file instead of vibrate, at end of job\n"
             "  -o: write to custom directory (only in limited mode)\n"
-            "  -d: append date to filename\n"
             "  -p: capture screenshot to filename.png\n"
-            "  -z: generate zipped file\n"
-            "  -s: write output to control socket (for init)\n"
-            "  -S: write file location to control socket (for init; requires -z)\n"
+            "  -s: write zipped file to control socket (for init)\n"
+            "  -S: write file location to control socket (for init)\n"
             "  -q: disable vibrate\n"
             "  -P: send broadcast when started and do progress updates\n"
-            "  -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
+            "  -R: take bugreport in remote mode (shouldn't be used with -P)\n"
             "  -w: start binder service and make it wait for a call to startBugreport\n"
             "  -L: output limited information that is safe for submission in feedback reports\n"
             "  -v: prints the dumpstate header and exit\n");
@@ -2141,6 +2347,11 @@
 }
 
 bool Dumpstate::FinishZipFile() {
+    // Runs all enqueued adding zip entry and cleanup tasks before finishing the zip file.
+    if (zip_entry_tasks_) {
+        zip_entry_tasks_->run(/* do_cancel = */false);
+    }
+
     std::string entry_name = base_name_ + "-" + name_ + ".txt";
     MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
            tmp_path_.c_str());
@@ -2224,21 +2435,17 @@
 
 /*
  * Prepares state like filename, screenshot path, etc in Dumpstate. Also initializes ZipWriter
- * if we are writing zip files and adds the version file.
+ * and adds the version file. Return false if zip_file could not be open to write.
  */
-static void PrepareToWriteToFile() {
+static bool PrepareToWriteToFile() {
     MaybeResolveSymlink(&ds.bugreport_internal_dir_);
 
     std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
     std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
     ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
-    if (ds.options_->do_add_date) {
-        char date[80];
-        strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
-        ds.name_ = date;
-    } else {
-        ds.name_ = "undated";
-    }
+    char date[80];
+    strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+    ds.name_ = date;
 
     if (ds.options_->telephony_only) {
         ds.base_name_ += "-telephony";
@@ -2265,18 +2472,17 @@
         destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
         ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
 
-    if (ds.options_->do_zip_file) {
-        ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
-        MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
-        create_parent_dirs(ds.path_.c_str());
-        ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
-        if (ds.zip_file == nullptr) {
-            MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
-        } else {
-            ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
-        }
-        ds.AddTextZipEntry("version.txt", ds.version_);
+    ds.path_ = ds.GetPath(ds.CalledByApi() ? "-zip.tmp" : ".zip");
+    MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
+    create_parent_dirs(ds.path_.c_str());
+    ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
+    if (ds.zip_file == nullptr) {
+        MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
+        return false;
     }
+    ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
+    ds.AddTextZipEntry("version.txt", ds.version_);
+    return true;
 }
 
 /*
@@ -2284,14 +2490,9 @@
  * printing zipped file status, etc.
  */
 static void FinalizeFile() {
-    bool do_text_file = true;
-    if (ds.options_->do_zip_file) {
-        if (!ds.FinishZipFile()) {
-            MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
-            do_text_file = true;
-        } else {
-            do_text_file = false;
-        }
+    bool do_text_file = !ds.FinishZipFile();
+    if (do_text_file) {
+        MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
     }
 
     std::string final_path = ds.path_;
@@ -2300,7 +2501,9 @@
         android::os::CopyFileToFile(ds.path_, final_path);
     }
 
-    if (ds.options_->use_control_socket) {
+    if (ds.options_->stream_to_socket) {
+        android::os::CopyFileToFd(ds.path_, ds.control_socket_fd_);
+    } else if (ds.options_->progress_updates_to_socket) {
         if (do_text_file) {
             dprintf(ds.control_socket_fd_,
                     "FAIL:could not create zip file, check %s "
@@ -2344,7 +2547,6 @@
             break;
         case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
             // Currently, the dumpstate binder is only used by Shell to update progress.
-            options->do_start_service = true;
             options->do_progress_updates = true;
             options->do_screenshot = is_screenshot_requested;
             options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
@@ -2356,9 +2558,7 @@
             options->dumpstate_hal_mode = DumpstateMode::REMOTE;
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WEAR:
-            options->do_start_service = true;
             options->do_progress_updates = true;
-            options->do_zip_file = true;
             options->do_screenshot = is_screenshot_requested;
             options->dumpstate_hal_mode = DumpstateMode::WEAR;
             break;
@@ -2371,7 +2571,6 @@
             break;
         case Dumpstate::BugreportMode::BUGREPORT_WIFI:
             options->wifi_only = true;
-            options->do_zip_file = true;
             options->do_screenshot = false;
             options->dumpstate_hal_mode = DumpstateMode::WIFI;
             break;
@@ -2382,13 +2581,13 @@
 
 static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
     MYLOGI(
-        "do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d "
-        "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
+        "do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
+        "is_remote_mode: %d show_header_only: %d telephony_only: %d "
         "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
         "limited_only: %d args: %s\n",
-        options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
+        options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
         options.do_screenshot, options.is_remote_mode, options.show_header_only,
-        options.do_start_service, options.telephony_only, options.wifi_only,
+        options.telephony_only, options.wifi_only,
         options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
         toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
 }
@@ -2397,11 +2596,6 @@
                                         const android::base::unique_fd& bugreport_fd_in,
                                         const android::base::unique_fd& screenshot_fd_in,
                                         bool is_screenshot_requested) {
-    // In the new API world, date is always added; output is always a zip file.
-    // TODO(111441001): remove these options once they are obsolete.
-    do_add_date = true;
-    do_zip_file = true;
-
     // Duplicate the fds because the passed in fds don't outlive the binder transaction.
     bugreport_fd.reset(dup(bugreport_fd_in.get()));
     screenshot_fd.reset(dup(screenshot_fd_in.get()));
@@ -2415,18 +2609,20 @@
     while ((c = getopt(argc, argv, "dho:svqzpLPBRSV:w")) != -1) {
         switch (c) {
             // clang-format off
-            case 'd': do_add_date = true;            break;
-            case 'z': do_zip_file = true;            break;
             case 'o': out_dir = optarg;              break;
-            case 's': use_socket = true;             break;
-            case 'S': use_control_socket = true;     break;
+            case 's': stream_to_socket = true;       break;
+            case 'S': progress_updates_to_socket = true;    break;
             case 'v': show_header_only = true;       break;
             case 'q': do_vibrate = false;            break;
             case 'p': do_screenshot = true;          break;
             case 'P': do_progress_updates = true;    break;
             case 'R': is_remote_mode = true;         break;
             case 'L': limited_only = true;           break;
-            case 'V':                                break;  // compatibility no-op
+            case 'V':
+            case 'd':
+            case 'z':
+                // compatibility no-op
+                break;
             case 'w':
                 // This was already processed
                 break;
@@ -2455,19 +2651,15 @@
 }
 
 bool Dumpstate::DumpOptions::ValidateOptions() const {
-    if (bugreport_fd.get() != -1 && !do_zip_file) {
+    if (bugreport_fd.get() != -1 && stream_to_socket) {
         return false;
     }
 
-    if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
+    if ((progress_updates_to_socket || do_progress_updates) && stream_to_socket) {
         return false;
     }
 
-    if (use_control_socket && !do_zip_file) {
-        return false;
-    }
-
-    if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
+    if (is_remote_mode && (do_progress_updates || stream_to_socket)) {
         return false;
     }
     return true;
@@ -2519,6 +2711,15 @@
     }
     tombstone_data_.clear();
     anr_data_.clear();
+
+    // Instead of shutdown the pool, we delete temporary files directly since
+    // shutdown blocking the call.
+    if (dump_pool_) {
+        dump_pool_->deleteTempFiles();
+    }
+    if (zip_entry_tasks_) {
+        zip_entry_tasks_->run(/*do_cancel =*/ true);
+    }
 }
 
 /*
@@ -2533,17 +2734,16 @@
  * The temporary bugreport is then populated via printfs, dumping contents of files and
  * output of commands to stdout.
  *
- * If zipping, the temporary bugreport file is added to the zip archive. Else it's renamed to final
- * text file.
+ * A bunch of other files and dumps are added to the zip archive.
  *
- * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
- * gets added to the archive.
+ * The temporary bugreport file and the log file also get added to the archive.
  *
  * Bugreports are first generated in a local directory and later copied to the caller's fd
  * or directory if supplied.
  */
 Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
                                             const std::string& calling_package) {
+    DurationReporter duration_reporter("RUN INTERNAL", /* logcat_only = */true);
     LogDumpOptions(*options_);
     if (!options_->ValidateOptions()) {
         MYLOGE("Invalid options specified\n");
@@ -2584,14 +2784,9 @@
     MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
             calling_uid, calling_package.c_str());
 
-    // Redirect output if needed
-    bool is_redirecting = options_->OutputToFile();
-
     // TODO: temporarily set progress until it's part of the Dumpstate constructor
     std::string stats_path =
-        is_redirecting
-            ? android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str())
-            : "";
+        android::base::StringPrintf("%s/dumpstate-stats.txt", bugreport_internal_dir_.c_str());
     progress_.reset(new Progress(stats_path));
 
     if (acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME) < 0) {
@@ -2603,15 +2798,6 @@
 
     register_sig_handler();
 
-    // TODO(b/111441001): maybe skip if already started?
-    if (options_->do_start_service) {
-        MYLOGI("Starting 'dumpstate' service\n");
-        android::status_t ret;
-        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
-            MYLOGE("Unable to start DumpstateService: %d\n", ret);
-        }
-    }
-
     if (PropertiesHelper::IsDryRun()) {
         MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
@@ -2623,35 +2809,33 @@
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
-    if (options_->use_socket) {
-        if (!redirect_to_socket(stdout, "dumpstate")) {
-            return ERROR;
-        }
-    }
-
-    if (options_->use_control_socket) {
+    if (options_->stream_to_socket || options_->progress_updates_to_socket) {
         MYLOGD("Opening control socket\n");
-        control_socket_fd_ = open_socket("dumpstate");
+        control_socket_fd_ = open_socket_fn_("dumpstate");
         if (control_socket_fd_ == -1) {
             return ERROR;
         }
-        options_->do_progress_updates = 1;
+        if (options_->progress_updates_to_socket) {
+            options_->do_progress_updates = 1;
+        }
     }
 
-    if (is_redirecting) {
-        PrepareToWriteToFile();
+    if (!PrepareToWriteToFile()) {
+        return ERROR;
+    }
 
-        if (options_->do_progress_updates) {
-            // clang-format off
-            std::vector<std::string> am_args = {
-                 "--receiver-permission", "android.permission.DUMP",
-            };
-            // clang-format on
-            // Send STARTED broadcast for apps that listen to bugreport generation events
-            SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
-            if (options_->use_control_socket) {
-                dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
-            }
+    // Interactive, wear & telephony modes are default to true.
+    // and may enable from cli option or when using control socket
+    if (options_->do_progress_updates) {
+        // clang-format off
+        std::vector<std::string> am_args = {
+                "--receiver-permission", "android.permission.DUMP",
+        };
+        // clang-format on
+        // Send STARTED broadcast for apps that listen to bugreport generation events
+        SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
+        if (options_->progress_updates_to_socket) {
+            dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
         }
     }
 
@@ -2666,76 +2850,79 @@
         Vibrate(150);
     }
 
-    if (options_->do_zip_file && zip_file != nullptr) {
+    if (zip_file != nullptr) {
         if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(),
-                   strerror(errno));
+                    strerror(errno));
         }
     }
 
     int dup_stdout_fd;
     int dup_stderr_fd;
-    if (is_redirecting) {
-        // Redirect stderr to log_path_ for debugging.
-        TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
-        if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
-            return ERROR;
-        }
-        if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
-                   strerror(errno));
-        }
+    // Redirect stderr to log_path_ for debugging.
+    TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
+    if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+        return ERROR;
+    }
+    if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
+        MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
+                strerror(errno));
+    }
 
-        // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
-        // moved into zip file later, if zipping.
-        TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
-        // TODO: why not write to a file instead of stdout to overcome this problem?
-        /* TODO: rather than generating a text file now and zipping it later,
-           it would be more efficient to redirect stdout to the zip entry
-           directly, but the libziparchive doesn't support that option yet. */
-        if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
-            return ERROR;
-        }
-        if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
-            MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
-                   tmp_path_.c_str(), strerror(errno));
-        }
+    // Redirect stdout to tmp_path_. This is the main bugreport entry and will be
+    // moved into zip file later, if zipping.
+    TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
+    // TODO: why not write to a file instead of stdout to overcome this problem?
+    /* TODO: rather than generating a text file now and zipping it later,
+        it would be more efficient to redirect stdout to the zip entry
+        directly, but the libziparchive doesn't support that option yet. */
+    if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+        return ERROR;
+    }
+    if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
+        MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
+                tmp_path_.c_str(), strerror(errno));
     }
 
     // Don't buffer stdout
     setvbuf(stdout, nullptr, _IONBF, 0);
 
+    // Enable the parallel run if the client requests to output to a file.
+    EnableParallelRunIfNeeded();
+    // Using scope guard to make sure the dump pool can be shut down correctly.
+    auto scope_guard_to_shutdown_pool = android::base::make_scope_guard([=]() {
+        ShutdownDumpPool();
+    });
+
     // NOTE: there should be no stdout output until now, otherwise it would break the header.
     // In particular, DurationReport objects should be created passing 'title, NULL', so their
     // duration is logged into MYLOG instead.
     PrintHeader();
 
-    // TODO(b/158737089) reduce code repetition in if branches
-    if (options_->telephony_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateTelephonyOnly(calling_package);
-        DumpstateBoard();
-    } else if (options_->wifi_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateWifiOnly();
-    } else if (options_->limited_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateLimitedOnly();
-    } else {
+    bool is_dumpstate_restricted = options_->telephony_only
+                                   || options_->wifi_only
+                                   || options_->limited_only;
+    if (!is_dumpstate_restricted) {
         // Invoke critical dumpsys first to preserve system state, before doing anything else.
         RunDumpsysCritical();
+    }
+    MaybeTakeEarlyScreenshot();
 
-        // Take screenshot and get consent only after critical dumpsys has finished.
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-
+    if (!is_dumpstate_restricted) {
+        // Snapshot the system trace now (if running) to avoid that dumpstate's
+        // own activity pushes out interesting data from the trace ring buffer.
+        // The trace file is added to the zip by MaybeAddSystemTraceToZip().
+        MaybeSnapshotSystemTrace();
+    }
+    onUiIntensiveBugreportDumpsFinished(calling_uid);
+    MaybeCheckUserConsent(calling_uid, calling_package);
+    if (options_->telephony_only) {
+        DumpstateTelephonyOnly(calling_package);
+    } else if (options_->wifi_only) {
+        DumpstateWifiOnly();
+    } else if (options_->limited_only) {
+        DumpstateLimitedOnly();
+    } else {
         // Dump state for the default case. This also drops root.
         RunStatus s = DumpstateDefaultAfterCritical();
         if (s != RunStatus::OK) {
@@ -2747,14 +2934,10 @@
     }
 
     /* close output if needed */
-    if (is_redirecting) {
-        TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
-    }
+    TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
 
     // Zip the (now complete) .tmp file within the internal directory.
-    if (options_->OutputToFile()) {
-        FinalizeFile();
-    }
+    FinalizeFile();
 
     // Share the final file with the caller if the user has consented or Shell is the caller.
     Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -2797,11 +2980,9 @@
     progress_->Save();
     MYLOGI("done (id %d)\n", id_);
 
-    if (is_redirecting) {
-        TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
-    }
+    TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
 
-    if (options_->use_control_socket && control_socket_fd_ != -1) {
+    if (control_socket_fd_ != -1) {
         MYLOGD("Closing control socket\n");
         close(control_socket_fd_);
     }
@@ -2823,16 +3004,34 @@
     TakeScreenshot();
 }
 
-void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
-                                                    const std::string& calling_package) {
+void Dumpstate::MaybeSnapshotSystemTrace() {
+    // If a background system trace is happening and is marked as "suitable for
+    // bugreport" (i.e. bugreport_score > 0 in the trace config), this command
+    // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely)
+    // case that no trace is ongoing, this command is a no-op.
+    // Note: this should not be enqueued as we need to freeze the trace before
+    // dumpstate starts. Otherwise the trace ring buffers will contain mostly
+    // the dumpstate's own activity which is irrelevant.
+    int res = RunCommand(
+        "SERIALIZE PERFETTO TRACE",
+        {"perfetto", "--save-for-bugreport"},
+        CommandOptions::WithTimeout(10)
+            .DropRoot()
+            .CloseAllFileDescriptorsOnExec()
+            .Build());
+    has_system_trace_ = res == 0;
+    // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
+    // file in the later stages.
+}
+
+void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
     if (calling_uid == AID_SHELL || !CalledByApi()) {
         return;
     }
     if (listener_ != nullptr) {
         // Let listener know ui intensive bugreport dumps are finished, then it can do event
         // handling if required.
-        android::String16 package(calling_package.c_str());
-        listener_->onUiIntensiveBugreportDumpsFinished(package);
+        listener_->onUiIntensiveBugreportDumpsFinished();
     }
 }
 
@@ -2871,6 +3070,42 @@
     android::os::UnlinkAndLogOnError(path_);
 }
 
+void Dumpstate::EnableParallelRunIfNeeded() {
+    if (!PropertiesHelper::IsParallelRun()) {
+        return;
+    }
+    dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
+    zip_entry_tasks_ = std::make_unique<TaskQueue>();
+}
+
+void Dumpstate::ShutdownDumpPool() {
+    if (dump_pool_) {
+        dump_pool_->shutdown();
+        dump_pool_ = nullptr;
+    }
+    if (zip_entry_tasks_) {
+        zip_entry_tasks_->run(/* do_cancel = */true);
+        zip_entry_tasks_ = nullptr;
+    }
+}
+
+void Dumpstate::EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
+        const std::string& entry_path) {
+    auto func_add_zip_entry_and_cleanup = [=](bool task_cancelled) {
+        if (!task_cancelled) {
+            AddZipEntry(entry_name, entry_path);
+        }
+        android::os::UnlinkAndLogOnError(entry_path);
+    };
+    if (zip_entry_tasks_) {
+        // Enqueues AddZipEntryAndCleanup function if the parallel run is enabled.
+        zip_entry_tasks_->add(func_add_zip_entry_and_cleanup, _1);
+    } else {
+        // Invokes AddZipEntryAndCleanup immediately
+        std::invoke(func_add_zip_entry_and_cleanup, /* task_cancelled = */false);
+    }
+}
+
 Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
     MYLOGD("User denied consent; deleting files and returning\n");
     CleanupTmpFiles();
@@ -2981,7 +3216,8 @@
       options_(new Dumpstate::DumpOptions()),
       last_reported_percent_progress_(0),
       version_(version),
-      now_(time(nullptr)) {
+      now_(time(nullptr)),
+      open_socket_fn_(open_socket) {
 }
 
 Dumpstate& Dumpstate::GetInstance() {
@@ -2989,8 +3225,9 @@
     return singleton_;
 }
 
-DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
-    : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose,
+        int duration_fd) : title_(title), logcat_only_(logcat_only), verbose_(verbose),
+        duration_fd_(duration_fd) {
     if (!title_.empty()) {
         started_ = Nanotime();
     }
@@ -3004,7 +3241,8 @@
         }
         if (!logcat_only_) {
             // Use "Yoda grammar" to make it easier to grep|sort sections.
-            printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
+            dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
+                    elapsed, title_.c_str());
         }
     }
 }
@@ -3590,10 +3828,11 @@
 }
 
 int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
-                          const CommandOptions& options, bool verbose_duration) {
-    DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
+                          const CommandOptions& options, bool verbose_duration, int out_fd) {
+    DurationReporter duration_reporter(title, false /* logcat_only */,
+                                       verbose_duration, out_fd);
 
-    int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
+    int status = RunCommandToFd(out_fd, title, full_command, options);
 
     /* TODO: for now we're simplifying the progress calculation by using the
      * timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
@@ -3605,14 +3844,14 @@
 }
 
 void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
-                           const CommandOptions& options, long dumpsysTimeoutMs) {
+                           const CommandOptions& options, long dumpsysTimeoutMs, int out_fd) {
     long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
     std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
     dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
-    RunCommand(title, dumpsys, options);
+    RunCommand(title, dumpsys, options, false, out_fd);
 }
 
-int open_socket(const char *service) {
+static int open_socket(const char* service) {
     int s = android_get_control_socket(service);
     if (s < 0) {
         MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
@@ -3647,19 +3886,6 @@
     return fd;
 }
 
-/* redirect output to a service control socket */
-bool redirect_to_socket(FILE* redirect, const char* service) {
-    int fd = open_socket(service);
-    if (fd == -1) {
-        return false;
-    }
-    fflush(redirect);
-    // TODO: handle dup2 failure
-    TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
-    close(fd);
-    return true;
-}
-
 // TODO: should call is_valid_output_file and/or be merged into it.
 void create_parent_dirs(const char *path) {
     char *chp = const_cast<char *> (path);
@@ -3732,12 +3958,16 @@
     fclose(fp);
 }
 
-// TODO: make this function thread safe if sections are generated in parallel.
 void Dumpstate::UpdateProgress(int32_t delta_sec) {
     if (progress_ == nullptr) {
         MYLOGE("UpdateProgress: progress_ not set\n");
         return;
     }
+    // This function updates progress related members of the dumpstate and reports
+    // progress percentage to the bugreport client. Since it could be called by
+    // different dump tasks at the same time if the parallel run is enabled, a
+    // mutex lock is necessary here to synchronize the call.
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
 
     // Always update progess so stats can be tuned...
     progress_->Inc(delta_sec);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 0d25d30..f83968b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -35,6 +35,8 @@
 #include <ziparchive/zip_writer.h>
 
 #include "DumpstateUtil.h"
+#include "DumpPool.h"
+#include "TaskQueue.h"
 
 // Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
 // std::vector<std::string>
@@ -52,6 +54,7 @@
 
 class DumpstateTest;
 class ProgressTest;
+class ZippedBugReportStreamTest;
 
 }  // namespace dumpstate
 }  // namespace os
@@ -75,7 +78,7 @@
 class DurationReporter {
   public:
     explicit DurationReporter(const std::string& title, bool logcat_only = false,
-                              bool verbose = false);
+                              bool verbose = false, int duration_fd = STDOUT_FILENO);
 
     ~DurationReporter();
 
@@ -84,6 +87,7 @@
     bool logcat_only_;
     bool verbose_;
     uint64_t started_;
+    int duration_fd_;
 
     DISALLOW_COPY_AND_ASSIGN(DurationReporter);
 };
@@ -193,7 +197,8 @@
  * that are spread accross utils.cpp and dumpstate.cpp will be moved to it.
  */
 class Dumpstate {
-    friend class DumpstateTest;
+    friend class android::os::dumpstate::DumpstateTest;
+    friend class android::os::dumpstate::ZippedBugReportStreamTest;
 
   public:
     enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
@@ -227,11 +232,13 @@
      * |full_command| array containing the command (first entry) and its arguments.
      * Must contain at least one element.
      * |options| optional argument defining the command's behavior.
+     * |out_fd| A fd to support the DumpPool to output results to a temporary
+     * file. Using STDOUT_FILENO if it's not running in the parallel task.
      */
     int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
                    const android::os::dumpstate::CommandOptions& options =
                        android::os::dumpstate::CommandOptions::DEFAULT,
-                   bool verbose_duration = false);
+                   bool verbose_duration = false, int out_fd = STDOUT_FILENO);
 
     /*
      * Runs `dumpsys` with the given arguments, automatically setting its timeout
@@ -244,10 +251,12 @@
      * |options| optional argument defining the command's behavior.
      * |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the
      * timeout from `options`)
+     * |out_fd| A fd to support the DumpPool to output results to a temporary
+     * file. Using STDOUT_FILENO if it's not running in the parallel task.
      */
     void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
                     const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS,
-                    long dumpsys_timeout_ms = 0);
+                    long dumpsys_timeout_ms = 0, int out_fd = STDOUT_FILENO);
 
     /*
      * Prints the contents of a file.
@@ -304,7 +313,12 @@
     // Returns OK in all other cases.
     RunStatus DumpTraces(const char** path);
 
-    void DumpstateBoard();
+    /*
+     * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+     * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+     * if it's not running in the parallel task.
+     */
+    void DumpstateBoard(int out_fd = STDOUT_FILENO);
 
     /*
      * Updates the overall progress of the bugreport generation by the given weight increment.
@@ -361,20 +375,30 @@
     bool CalledByApi() const;
 
     /*
+     * Enqueues a task to the dumpstate's TaskQueue if the parallel run is enabled,
+     * otherwise invokes it immediately. The task adds file at path entry_path
+     * as a zip file entry with name entry_name. Unlinks entry_path when done.
+     *
+     * All enqueued tasks will be executed in the dumpstate's FinishZipFile method
+     * before the zip file is finished. Tasks will be cancelled in dumpstate's
+     * ShutdownDumpPool method if they have never been called.
+     */
+    void EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
+            const std::string& entry_path);
+
+    /*
      * Structure to hold options that determine the behavior of dumpstate.
      */
     struct DumpOptions {
-        bool do_add_date = false;
-        bool do_zip_file = false;
         bool do_vibrate = true;
-        // Writes bugreport content to a socket; only flatfile format is supported.
-        bool use_socket = false;
-        bool use_control_socket = false;
+        // Writes bugreport zipped file to a socket.
+        bool stream_to_socket = false;
+        // Writes generation progress updates to a socket.
+        bool progress_updates_to_socket = false;
         bool do_screenshot = false;
         bool is_screenshot_copied = false;
         bool is_remote_mode = false;
         bool show_header_only = false;
-        bool do_start_service = false;
         bool telephony_only = false;
         bool wifi_only = false;
         // Trimmed-down version of dumpstate to only include whitelisted logs.
@@ -411,13 +435,6 @@
         /* Returns true if the options set so far are consistent. */
         bool ValidateOptions() const;
 
-        /* Returns if options specified require writing bugreport to a file */
-        bool OutputToFile() const {
-            // If we are not writing to socket, we will write to a file. If bugreport_fd is
-            // specified, it is preferred. If not bugreport is written to /bugreports.
-            return !use_socket;
-        }
-
         /* Returns if options specified require writing to custom file location */
         bool OutputToCustomFile() {
             // Custom location is only honored in limited mode.
@@ -441,9 +458,15 @@
     // Whether it should take an screenshot earlier in the process.
     bool do_early_screenshot_ = false;
 
+    // This is set to true when the trace snapshot request in the early call to
+    // MaybeSnapshotSystemTrace(). When this is true, the later stages of
+    // dumpstate will append the trace to the zip archive.
+    bool has_system_trace_ = false;
+
     std::unique_ptr<Progress> progress_;
 
-    // When set, defines a socket file-descriptor use to report progress to bugreportz.
+    // When set, defines a socket file-descriptor use to report progress to bugreportz
+    // or to stream the zipped file to.
     int control_socket_fd_ = -1;
 
     // Bugreport format version;
@@ -455,8 +478,8 @@
     // `bugreport-BUILD_ID`.
     std::string base_name_;
 
-    // Name is the suffix part of the bugreport files - it's typically the date (when invoked with
-    // `-d`), but it could be changed by the user..
+    // Name is the suffix part of the bugreport files - it's typically the date,
+    // but it could be changed by the user..
     std::string name_;
 
     std::string bugreport_internal_dir_ = DUMPSTATE_DIRECTORY;
@@ -490,6 +513,13 @@
     // List of open ANR dump files.
     std::vector<DumpData> anr_data_;
 
+    // A thread pool to execute dump tasks simultaneously if the parallel run is enabled.
+    std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_;
+
+    // A task queue to collect adding zip entry tasks inside dump tasks if the
+    // parallel run is enabled.
+    std::unique_ptr<android::os::dumpstate::TaskQueue> zip_entry_tasks_;
+
     // A callback to IncidentCompanion service, which checks user consent for sharing the
     // bugreport with the calling app. If the user has not responded yet to the dialog it will
     // be neither confirmed nor denied.
@@ -518,9 +548,9 @@
     RunStatus DumpstateDefaultAfterCritical();
 
     void MaybeTakeEarlyScreenshot();
+    void MaybeSnapshotSystemTrace();
 
-    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid,
-                                             const std::string& calling_package);
+    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid);
 
     void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package);
 
@@ -528,17 +558,25 @@
     // but leaves the log file alone.
     void CleanupTmpFiles();
 
+    // Create the thread pool to enable the parallel run function.
+    void EnableParallelRunIfNeeded();
+    void ShutdownDumpPool();
+
     RunStatus HandleUserConsentDenied();
 
     // Copies bugreport artifacts over to the caller's directories provided there is user consent or
     // called by Shell.
     RunStatus CopyBugreportIfUserConsented(int32_t calling_uid);
 
+    std::function<int(const char *)> open_socket_fn_;
+
     // Used by GetInstance() only.
     explicit Dumpstate(const std::string& version = VERSION_CURRENT);
 
     android::sp<ConsentCallback> consent_callback_;
 
+    std::recursive_mutex mutex_;
+
     DISALLOW_COPY_AND_ASSIGN(Dumpstate);
 };
 
@@ -565,16 +603,6 @@
 int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
                int (*dump_from_fd)(const char* title, const char* path, int fd));
 
-/** opens a socket and returns its file descriptor */
-int open_socket(const char *service);
-
-/*
- * Redirects 'redirect' to a service control socket.
- *
- * Returns true if redirect succeeds.
- */
-bool redirect_to_socket(FILE* redirect, const char* service);
-
 /*
  * Redirects 'redirect' to a file indicated by 'path', truncating it.
  *
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index e491a4b..a80da4e 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -11,7 +11,7 @@
 
 # dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
 # it is finished.
-service dumpstatez /system/bin/dumpstate -S -d -z
+service dumpstatez /system/bin/dumpstate -S
     socket dumpstate stream 0660 shell log
     class main
     disabled
diff --git a/libs/binder/ndk/test/AndroidTest.xml b/cmds/dumpstate/dumpstate_smoke_test.xml
similarity index 70%
rename from libs/binder/ndk/test/AndroidTest.xml
rename to cmds/dumpstate/dumpstate_smoke_test.xml
index 89646f7..0aff200 100644
--- a/libs/binder/ndk/test/AndroidTest.xml
+++ b/cmds/dumpstate/dumpstate_smoke_test.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,20 +13,19 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs binderVendorDoubleLoadTest.">
+<configuration description="Config for dumpstate_smoke_test">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-native" />
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="binderVendorDoubleLoadTest->/data/nativetest/vendor/binderVendorDoubleLoadTest" />
+        <option name="push" value="dumpstate_smoke_test->/data/local/tmp/dumpstate_smoke_test" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/nativetest/vendor" />
-        <option name="module-name" value="binderVendorDoubleLoadTest" />
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="dumpstate_smoke_test" />
+        <option name="native-test-timeout" value="600000" />
     </test>
 </configuration>
-
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 6f2d754..c62d302 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -173,12 +173,9 @@
         return binder::Status::ok();
     }
 
-    binder::Status onUiIntensiveBugreportDumpsFinished(const android::String16& callingpackage)
-        override {
+    binder::Status onUiIntensiveBugreportDumpsFinished() override {
         std::lock_guard <std::mutex> lock(lock_);
-        std::string callingpackageUtf8 = std::string(String8(callingpackage).string());
-        dprintf(out_fd_, "\rCalling package of ui intensive bugreport dumps finished: %s",
-                callingpackageUtf8.c_str());
+        dprintf(out_fd_, "\rUi intensive bugreport dumps finished");
         return binder::Status::ok();
     }
 
@@ -209,13 +206,10 @@
     static std::shared_ptr<std::vector<SectionInfo>> sections;
     static Dumpstate& ds;
     static std::chrono::milliseconds duration;
-    static void SetUpTestCase() {
+    static void GenerateBugreport() {
         // clang-format off
         char* argv[] = {
-            (char*)"dumpstate",
-            (char*)"-d",
-            (char*)"-z",
-            (char*)"-B"
+            (char*)"dumpstate"
         };
         // clang-format on
         sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
@@ -236,20 +230,20 @@
 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
 
 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+    GenerateBugreport();
     EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
-TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is1MBMBinSize) {
     struct stat st;
     EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
-    EXPECT_GE(st.st_size, 3000000 /* 3MB */);
-    EXPECT_LE(st.st_size, 30000000 /* 30MB */);
+    EXPECT_GE(st.st_size, 1000000 /* 1MB */);
 }
 
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
     EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
                              << duration.count() << " s.";
-    EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+    EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
                               << duration.count() << " s.";
 }
 
@@ -266,7 +260,8 @@
         CloseArchive(handle);
     }
 
-    void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+    void FileExists(const char* filename, uint32_t minsize,
+                    uint32_t maxsize = std::numeric_limits<uint32_t>::max()) {
         ZipEntry entry;
         GetEntry(handle, filename, &entry);
         EXPECT_GT(entry.uncompressed_length, minsize);
@@ -285,7 +280,7 @@
                     main_entry.uncompressed_length);
 
     // contains main entry file
-    FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
+    FileExists(bugreport_txt_name.c_str(), 1000000U);
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
@@ -301,8 +296,9 @@
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
-    FileExists("dumpstate_board.bin", 1000000U, 80000000U);
-    FileExists("dumpstate_board.txt", 100000U, 1000000U);
+    // TODO(b/160109027): cf_x86_phone-userdebug does not dump them.
+    // FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+    // FileExists("dumpstate_board.txt", 100000U, 1000000U);
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
@@ -314,8 +310,12 @@
     // FS/proc/*/mountinfo size > 0
     FileExists("FS/proc/1/mountinfo", 0U, 100000U);
 
-    // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
-    FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
+    // FS/data/misc/profiles/cur/0/*/primary.prof should exist. Also, since dumpstate only adds
+    // profiles to the zip in the non-user build, a build checking is necessary here.
+    if (!PropertiesHelper::IsUserBuild()) {
+        ZipEntry entry;
+        GetEntry(handle, "FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", &entry);
+    }
 }
 
 /**
@@ -323,6 +323,16 @@
  */
 class BugreportSectionTest : public Test {
   public:
+    ZipArchiveHandle handle;
+
+    void SetUp() {
+        ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath().c_str(), &handle), 0);
+    }
+
+    void TearDown() {
+        CloseArchive(handle);
+    }
+
     static void SetUpTestCase() {
         ParseSections(ZippedBugreportGenerationTest::getZipFilePath().c_str(),
                       ZippedBugreportGenerationTest::sections.get());
@@ -347,6 +357,19 @@
         }
         FAIL() << sectionName << " not found.";
     }
+
+    /**
+     * Whether or not the content of the section is injected by other commands.
+     */
+    bool IsContentInjectedByOthers(const std::string& line) {
+        // Command header such as `------ APP ACTIVITIES (/system/bin/dumpsys activity -v) ------`.
+        static const std::regex kCommandHeader = std::regex{"------ .+ \\(.+\\) ------"};
+        std::smatch match;
+        if (std::regex_match(line, match, kCommandHeader)) {
+          return true;
+        }
+        return false;
+    }
 };
 
 TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
@@ -400,10 +423,32 @@
     SectionExists("batterystats", /* bytes= */ 1000);
 }
 
-TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+TEST_F(BugreportSectionTest, DISABLED_WifiSectionGenerated) {
     SectionExists("wifi", /* bytes= */ 100000);
 }
 
+TEST_F(BugreportSectionTest, NoInjectedContentByOtherCommand) {
+    // Extract the main entry to a temp file
+    TemporaryFile tmp_binary;
+    ASSERT_NE(-1, tmp_binary.fd);
+    ExtractBugreport(&handle, tmp_binary.fd);
+
+    // Read line by line and identify sections
+    std::ifstream ifs(tmp_binary.path, std::ifstream::in);
+    std::string line;
+    std::string current_section_name;
+    while (std::getline(ifs, line)) {
+        std::string section_name;
+        if (IsSectionStart(line, &section_name)) {
+            current_section_name = section_name;
+        } else if (IsSectionEnd(line)) {
+            current_section_name = "";
+        } else if (!current_section_name.empty()) {
+            EXPECT_FALSE(IsContentInjectedByOthers(line));
+        }
+    }
+}
+
 class DumpstateBinderTest : public Test {
   protected:
     void SetUp() override {
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c7df1bb..b2518ad 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "dumpstate"
-#include <cutils/log.h>
+#define LOG_TAG "dumpstate_test"
 
 #include "DumpstateInternal.h"
 #include "DumpstateService.h"
 #include "android/os/BnDumpstate.h"
 #include "dumpstate.h"
+#include "DumpPool.h"
 
 #include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
 #include <gtest/gtest.h>
 
 #include <fcntl.h>
@@ -38,7 +39,9 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/hardware/dumpstate/1.1/types.h>
+#include <cutils/log.h>
 #include <cutils/properties.h>
+#include <ziparchive/zip_archive.h>
 
 namespace android {
 namespace os {
@@ -46,6 +49,7 @@
 
 using ::android::hardware::dumpstate::V1_1::DumpstateMode;
 using ::testing::EndsWith;
+using ::testing::Eq;
 using ::testing::HasSubstr;
 using ::testing::IsEmpty;
 using ::testing::IsNull;
@@ -66,8 +70,7 @@
     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
     MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onScreenshotTaken, binder::Status(bool success));
-    MOCK_METHOD1(onUiIntensiveBugreportDumpsFinished,
-        binder::Status(const android::String16& callingpackage));
+    MOCK_METHOD0(onUiIntensiveBugreportDumpsFinished, binder::Status());
 
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
@@ -95,6 +98,10 @@
         PropertiesHelper::unroot_ = unroot;
     }
 
+    void SetParallelRun(bool parallel_run) const {
+        PropertiesHelper::parallel_run_ = parallel_run;
+    }
+
     bool IsStandalone() const {
         return calls_ == 1;
     }
@@ -170,11 +177,9 @@
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
 
-    EXPECT_FALSE(options_.do_add_date);
-    EXPECT_FALSE(options_.do_zip_file);
     EXPECT_EQ("", options_.out_dir);
-    EXPECT_FALSE(options_.use_socket);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_TRUE(options_.do_vibrate);
     EXPECT_FALSE(options_.do_screenshot);
@@ -189,17 +194,13 @@
     char* argv[] = {
         const_cast<char*>("dumpstatez"),
         const_cast<char*>("-S"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-z"),
     };
     // clang-format on
 
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
-    EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_zip_file);
-    EXPECT_TRUE(options_.use_control_socket);
+    EXPECT_TRUE(options_.progress_updates_to_socket);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -207,7 +208,7 @@
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
@@ -223,13 +224,11 @@
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
-    EXPECT_TRUE(options_.use_socket);
+    EXPECT_TRUE(options_.stream_to_socket);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.do_add_date);
-    EXPECT_FALSE(options_.do_zip_file);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_FALSE(options_.do_progress_updates);
@@ -240,108 +239,93 @@
 
 TEST_F(DumpOptionsTest, InitializeFullBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
-    EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
-    EXPECT_FALSE(options_.do_start_service);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
 TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
-    EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
-    EXPECT_TRUE(options_.do_start_service);
     EXPECT_TRUE(options_.do_screenshot);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
 TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false);
-    EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.is_remote_mode);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
 
     // Other options retain default values
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.do_progress_updates);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
 TEST_F(DumpOptionsTest, InitializeWearBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
-    EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
-    EXPECT_TRUE(options_.do_start_service);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
 TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false);
-    EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_screenshot);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.telephony_only);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
 TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
     options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
-    EXPECT_TRUE(options_.do_add_date);
     EXPECT_FALSE(options_.do_screenshot);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.wifi_only);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.limited_only);
 }
 
@@ -350,8 +334,6 @@
     char* argv[] = {
         const_cast<char*>("dumpstatez"),
         const_cast<char*>("-S"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-z"),
         const_cast<char*>("-q"),
         const_cast<char*>("-L"),
         const_cast<char*>("-o abc")
@@ -361,9 +343,7 @@
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
-    EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_zip_file);
-    EXPECT_TRUE(options_.use_control_socket);
+    EXPECT_TRUE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_TRUE(options_.limited_only);
     EXPECT_EQ(" abc", std::string(options_.out_dir));
@@ -373,7 +353,7 @@
     EXPECT_FALSE(options_.do_screenshot);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
 
@@ -390,18 +370,16 @@
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
-    EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_screenshot);
-    EXPECT_TRUE(options_.do_zip_file);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.show_header_only);
     EXPECT_FALSE(options_.do_progress_updates);
     EXPECT_FALSE(options_.is_remote_mode);
-    EXPECT_FALSE(options_.use_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
     EXPECT_FALSE(options_.wifi_only);
     EXPECT_FALSE(options_.limited_only);
 }
@@ -410,8 +388,6 @@
     // clang-format off
     char* argv[] = {
         const_cast<char*>("dumpstate"),
-        const_cast<char*>("-d"),
-        const_cast<char*>("-z"),
         const_cast<char*>("-s"),
         const_cast<char*>("-S"),
 
@@ -421,11 +397,9 @@
     Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
 
     EXPECT_EQ(status, Dumpstate::RunStatus::OK);
-    EXPECT_TRUE(options_.do_add_date);
-    EXPECT_TRUE(options_.do_zip_file);
     // TODO: Maybe we should trim the filename
-    EXPECT_TRUE(options_.use_socket);
-    EXPECT_TRUE(options_.use_control_socket);
+    EXPECT_TRUE(options_.stream_to_socket);
+    EXPECT_TRUE(options_.progress_updates_to_socket);
 
     // Other options retain default values
     EXPECT_FALSE(options_.show_header_only);
@@ -459,10 +433,8 @@
     EXPECT_TRUE(options_.is_remote_mode);
 
     // Other options retain default values
-    EXPECT_FALSE(options_.do_add_date);
-    EXPECT_FALSE(options_.do_zip_file);
-    EXPECT_FALSE(options_.use_socket);
-    EXPECT_FALSE(options_.use_control_socket);
+    EXPECT_FALSE(options_.stream_to_socket);
+    EXPECT_FALSE(options_.progress_updates_to_socket);
     EXPECT_FALSE(options_.limited_only);
     EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
 }
@@ -495,40 +467,31 @@
     EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT);
 }
 
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
-    options_.do_zip_file = true;
-    // Writing to socket = !writing to file.
-    options_.use_socket = true;
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage1) {
+    options_.progress_updates_to_socket = true;
+    options_.stream_to_socket = true;
     EXPECT_FALSE(options_.ValidateOptions());
 
-    options_.use_socket = false;
+    options_.stream_to_socket = false;
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
-TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
+TEST_F(DumpOptionsTest, ValidateOptionsSocketUsage2) {
     options_.do_progress_updates = true;
     // Writing to socket = !writing to file.
-    options_.use_socket = true;
+    options_.stream_to_socket = true;
     EXPECT_FALSE(options_.ValidateOptions());
 
-    options_.use_socket = false;
-    EXPECT_TRUE(options_.ValidateOptions());
-}
-
-TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) {
-    options_.use_control_socket = true;
-    EXPECT_FALSE(options_.ValidateOptions());
-
-    options_.do_zip_file = true;
+    options_.stream_to_socket = false;
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
 TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
+    options_.do_progress_updates = true;
     options_.is_remote_mode = true;
     EXPECT_FALSE(options_.ValidateOptions());
 
-    options_.do_zip_file = true;
-    options_.do_add_date = true;
+    options_.do_progress_updates = false;
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
@@ -542,6 +505,10 @@
         ds.options_.reset(new Dumpstate::DumpOptions());
     }
 
+    void TearDown() {
+        ds.ShutdownDumpPool();
+    }
+
     // Runs a command and capture `stdout` and `stderr`.
     int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
                    const CommandOptions& options = CommandOptions::DEFAULT) {
@@ -569,6 +536,10 @@
         ds.progress_.reset(new Progress(initial_max, progress, 1.2));
     }
 
+    void EnableParallelRunIfNeeded() {
+        ds.EnableParallelRunIfNeeded();
+    }
+
     std::string GetProgressMessage(int progress, int max,
             int old_max = 0, bool update_progress = true) {
         EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
@@ -1007,6 +978,83 @@
     ds.listener_.clear();
 }
 
+TEST_F(DumpstateTest, DumpPool_withParallelRunEnabled_notNull) {
+    SetParallelRun(true);
+    EnableParallelRunIfNeeded();
+    EXPECT_TRUE(ds.zip_entry_tasks_);
+    EXPECT_TRUE(ds.dump_pool_);
+}
+
+TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
+    SetParallelRun(false);
+    EnableParallelRunIfNeeded();
+    EXPECT_FALSE(ds.zip_entry_tasks_);
+    EXPECT_FALSE(ds.dump_pool_);
+}
+
+class ZippedBugReportStreamTest : public DumpstateBaseTest {
+  public:
+    void SetUp() {
+        DumpstateBaseTest::SetUp();
+        ds_.options_.reset(new Dumpstate::DumpOptions());
+    }
+    void TearDown() {
+        CloseArchive(handle_);
+    }
+
+    // Set bugreport mode and options before here.
+    void GenerateBugreport() {
+        ds_.Initialize();
+        EXPECT_EQ(Dumpstate::RunStatus::OK, ds_.Run(/*calling_uid=*/-1, /*calling_package=*/""));
+    }
+
+    // Most bugreports droproot, ensure the file can be opened by shell to verify file content.
+    void CreateFd(const std::string& path, android::base::unique_fd* out_fd) {
+        out_fd->reset(TEMP_FAILURE_RETRY(open(path.c_str(),
+                                              O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                              S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+        ASSERT_GE(out_fd->get(), 0) << "could not create FD for path " << path;
+    }
+
+    void VerifyEntry(const ZipArchiveHandle archive, const std::string_view entry_name,
+                     ZipEntry* data) {
+        int32_t e = FindEntry(archive, entry_name, data);
+        EXPECT_EQ(0, e) << ErrorCodeString(e) << " entry name: " << entry_name;
+    }
+
+    // While testing dumpstate in process, using STDOUT may get confused about
+    // the internal fd redirection. Redirect to a dedicate fd to save content.
+    void RedirectOutputToFd(android::base::unique_fd& ufd) {
+        ds_.open_socket_fn_ = [&](const char*) -> int { return ufd.release(); };
+    };
+
+    Dumpstate& ds_ = Dumpstate::GetInstance();
+    ZipArchiveHandle handle_;
+};
+
+// Generate a quick wifi report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamWifiReport) {
+    std::string out_path = kTestDataPath + "out.zip";
+    android::base::unique_fd out_fd;
+    CreateFd(out_path, &out_fd);
+    ds_.options_->wifi_only = true;
+    ds_.options_->stream_to_socket = true;
+    RedirectOutputToFd(out_fd);
+
+    GenerateBugreport();
+    OpenArchive(out_path.c_str(), &handle_);
+
+    ZipEntry entry;
+    VerifyEntry(handle_, "main_entry.txt", &entry);
+    std::string bugreport_txt_name;
+    bugreport_txt_name.resize(entry.uncompressed_length);
+    ExtractToMemory(handle_, &entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+                    entry.uncompressed_length);
+    EXPECT_THAT(bugreport_txt_name,
+                testing::ContainsRegex("(bugreport-.+-wifi(-[[:digit:]]+){6}\\.txt)"));
+    VerifyEntry(handle_, bugreport_txt_name, &entry);
+}
+
 class DumpstateServiceTest : public DumpstateBaseTest {
   public:
     DumpstateService dss;
@@ -1618,6 +1666,154 @@
     EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
 }
 
+class DumpPoolTest : public DumpstateBaseTest {
+  public:
+    void SetUp() {
+        dump_pool_ = std::make_unique<DumpPool>(kTestDataPath);
+        DumpstateBaseTest::SetUp();
+        CreateOutputFile();
+    }
+
+    void CreateOutputFile() {
+        out_path_ = kTestDataPath + "out.txt";
+        out_fd_.reset(TEMP_FAILURE_RETRY(open(out_path_.c_str(),
+                O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+        ASSERT_GE(out_fd_.get(), 0) << "could not create FD for path "
+                << out_path_;
+    }
+
+    int getTempFileCounts(const std::string& folder) {
+        int count = 0;
+        std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+                &closedir);
+        if (!dir_ptr) {
+            return -1;
+        }
+        int dir_fd = dirfd(dir_ptr.get());
+        if (dir_fd < 0) {
+            return -1;
+        }
+
+        struct dirent* de;
+        while ((de = readdir(dir_ptr.get()))) {
+            if (de->d_type != DT_REG) {
+                continue;
+            }
+            std::string file_name(de->d_name);
+            if (file_name.find(DumpPool::PREFIX_TMPFILE_NAME) != 0) {
+                continue;
+            }
+            count++;
+        }
+        return count;
+    }
+
+    void setLogDuration(bool log_duration) {
+        dump_pool_->setLogDuration(log_duration);
+    }
+
+    std::unique_ptr<DumpPool> dump_pool_;
+    android::base::unique_fd out_fd_;
+    std::string out_path_;
+};
+
+TEST_F(DumpPoolTest, EnqueueTaskWithFd) {
+    auto dump_func_1 = [](int out_fd) {
+        dprintf(out_fd, "A");
+    };
+    auto dump_func_2 = [](int out_fd) {
+        dprintf(out_fd, "B");
+        sleep(1);
+    };
+    auto dump_func_3 = [](int out_fd) {
+        dprintf(out_fd, "C");
+    };
+    setLogDuration(/* log_duration = */false);
+    dump_pool_->enqueueTaskWithFd(/* task_name = */"1", dump_func_1, std::placeholders::_1);
+    dump_pool_->enqueueTaskWithFd(/* task_name = */"2", dump_func_2, std::placeholders::_1);
+    dump_pool_->enqueueTaskWithFd(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+
+    dump_pool_->waitForTask("1", "", out_fd_.get());
+    dump_pool_->waitForTask("2", "", out_fd_.get());
+    dump_pool_->waitForTask("3", "", out_fd_.get());
+    dump_pool_->shutdown();
+
+    std::string result;
+    ReadFileToString(out_path_, &result);
+    EXPECT_THAT(result, StrEq("A\nB\nC\n"));
+    EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
+TEST_F(DumpPoolTest, EnqueueTask_withDurationLog) {
+    bool run_1 = false;
+    auto dump_func_1 = [&]() {
+        run_1 = true;
+    };
+
+    dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
+    dump_pool_->waitForTask("1", "", out_fd_.get());
+    dump_pool_->shutdown();
+
+    std::string result;
+    ReadFileToString(out_path_, &result);
+    EXPECT_TRUE(run_1);
+    EXPECT_THAT(result, StrEq("------ 0.000s was the duration of '1' ------\n"));
+    EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
+class TaskQueueTest : public DumpstateBaseTest {
+public:
+    void SetUp() {
+        DumpstateBaseTest::SetUp();
+    }
+
+    TaskQueue task_queue_;
+};
+
+TEST_F(TaskQueueTest, runTask) {
+    bool is_task1_run = false;
+    bool is_task2_run = false;
+    auto task_1 = [&](bool task_cancelled) {
+        if (task_cancelled) {
+            return;
+        }
+        is_task1_run = true;
+    };
+    auto task_2 = [&](bool task_cancelled) {
+        if (task_cancelled) {
+            return;
+        }
+        is_task2_run = true;
+    };
+    task_queue_.add(task_1, std::placeholders::_1);
+    task_queue_.add(task_2, std::placeholders::_1);
+
+    task_queue_.run(/* do_cancel = */false);
+
+    EXPECT_TRUE(is_task1_run);
+    EXPECT_TRUE(is_task2_run);
+}
+
+TEST_F(TaskQueueTest, runTask_withCancelled) {
+    bool is_task1_cancelled = false;
+    bool is_task2_cancelled = false;
+    auto task_1 = [&](bool task_cancelled) {
+        is_task1_cancelled = task_cancelled;
+    };
+    auto task_2 = [&](bool task_cancelled) {
+        is_task2_cancelled = task_cancelled;
+    };
+    task_queue_.add(task_1, std::placeholders::_1);
+    task_queue_.add(task_2, std::placeholders::_1);
+
+    task_queue_.run(/* do_cancel = */true);
+
+    EXPECT_TRUE(is_task1_cancelled);
+    EXPECT_TRUE(is_task2_cancelled);
+}
+
+
 }  // namespace dumpstate
 }  // namespace os
 }  // namespace android
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a427c8d..a017246 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -230,7 +230,7 @@
     }
 
     const size_t N = services.size();
-    if (N > 1) {
+    if (N > 1 || showListOnly) {
         // first print a list of the current services
         std::cout << "Currently running services:" << std::endl;
 
@@ -427,7 +427,7 @@
                  << strerror(errno) << std::endl;
             status = -errno;
             break;
-        } else if (rc == 0) {
+        } else if (rc == 0 || time_left_ms() == 0) {
             status = TIMED_OUT;
             break;
         }
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index b9395ba..67a77f6 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -55,6 +55,7 @@
     MOCK_METHOD1(listServices, Vector<String16>(int));
     MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
     MOCK_METHOD1(isDeclared, bool(const String16&));
+    MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
@@ -206,10 +207,7 @@
     }
 
     void AssertRunningServices(const std::vector<std::string>& services) {
-        std::string expected;
-        if (services.size() > 1) {
-            expected.append("Currently running services:\n");
-        }
+        std::string expected = "Currently running services:\n";
         for (const std::string& service : services) {
             expected.append("  ").append(service).append("\n");
         }
@@ -263,6 +261,21 @@
     AssertRunningServices({"Locksmith", "Valet"});
 }
 
+TEST_F(DumpsysTest, ListServicesOneRegistered) {
+    ExpectListServices({"Locksmith"});
+    ExpectCheckService("Locksmith");
+
+    CallMain({"-l"});
+
+    AssertRunningServices({"Locksmith"});
+}
+
+TEST_F(DumpsysTest, ListServicesEmpty) {
+    CallMain({"-l"});
+
+    AssertRunningServices({});
+}
+
 // Tests 'dumpsys -l' when a service is not running
 TEST_F(DumpsysTest, ListRunningServices) {
     ExpectListServices({"Locksmith", "Valet"});
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 8ff4dd8..523115f 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -17,15 +17,15 @@
         "InstalldNativeService.cpp",
         "QuotaUtils.cpp",
         "dexopt.cpp",
+        "execv_helper.cpp",
         "globals.cpp",
+        "run_dex2oat.cpp",
+        "unique_file.cpp",
         "utils.cpp",
         "utils_default.cpp",
         "view_compiler.cpp",
         ":installd_aidl",
     ],
-    header_libs: [
-        "dex2oat_headers",
-    ],
     shared_libs: [
         "libbase",
         "libbinder",
@@ -103,6 +103,28 @@
 }
 
 //
+// Unit tests
+//
+
+cc_test_host {
+    name: "run_dex2oat_test",
+    test_suites: ["general-tests"],
+    clang: true,
+    srcs: [
+        "run_dex2oat_test.cpp",
+        "run_dex2oat.cpp",
+        "unique_file.cpp",
+        "execv_helper.cpp",
+    ],
+    cflags: ["-Wall", "-Werror"],
+    shared_libs: [
+        "libbase",
+        "server_configurable_flags",
+    ],
+    test_config: "run_dex2oat_test.xml",
+}
+
+//
 // Executable
 //
 
@@ -205,18 +227,18 @@
 
     srcs: [
         "dexopt.cpp",
+        "execv_helper.cpp",
         "globals.cpp",
         "otapreopt.cpp",
         "otapreopt_utils.cpp",
+        "run_dex2oat.cpp",
+        "unique_file.cpp",
         "utils.cpp",
         "utils_default.cpp",
         "view_compiler.cpp",
     ],
 
-    header_libs: ["dex2oat_headers"],
-
     static_libs: [
-        "libartimagevalues",
         "libdiskusage",
         "libotapreoptparameters",
     ],
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
index 6e079eb..b17cba1 100644
--- a/cmds/installd/CrateManager.cpp
+++ b/cmds/installd/CrateManager.cpp
@@ -86,7 +86,7 @@
 }
 
 void CrateManager::traverseAllPackagesForUser(
-        const std::unique_ptr<std::string>& uuid, userid_t userId,
+        const std::optional<std::string>& uuid, userid_t userId,
         std::function<void(FTSENT*)>& onHandlingPackage) {
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
@@ -96,21 +96,21 @@
 
 void CrateManager::createCrate(
         CratedFolder cratedFolder,
-        std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+        std::function<void(CratedFolder, CrateMetadata&&)>& onCreateCrate) {
     const char* path = cratedFolder->fts_path;
     if (path == nullptr || *path == '\0') {
         return;
     }
 
-    std::unique_ptr<CrateMetadata> crateMetadata = std::make_unique<CrateMetadata>();
-    crateMetadata->uid = cratedFolder->fts_statp->st_uid;
-    crateMetadata->packageName = mPackageName;
-    crateMetadata->id = getValidatedCratedPath(path);
+    CrateMetadata crateMetadata;
+    crateMetadata.uid = cratedFolder->fts_statp->st_uid;
+    crateMetadata.packageName = mPackageName;
+    crateMetadata.id = getValidatedCratedPath(path);
 
-    onCreateCrate(cratedFolder, crateMetadata);
+    onCreateCrate(cratedFolder, std::move(crateMetadata));
 }
 
-void CrateManager::traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+void CrateManager::traverseAllCrates(std::function<void(CratedFolder, CrateMetadata&&)>& onCreateCrate) {
     std::function<void(FTSENT*)> onVisitCrateDir = [&](FTSENT* cratedFolder) -> void {
         createCrate(cratedFolder, onCreateCrate);
     };
@@ -118,11 +118,11 @@
 }
 
 #if CRATE_DEBUG
-void CrateManager::dump(std::unique_ptr<CrateMetadata>& CrateMetadata) {
+void CrateManager::dump(const CrateMetadata& CrateMetadata) {
     LOG(DEBUG) << "CrateMetadata = {"
-            << "uid : \"" << CrateMetadata->uid
-            << "\", packageName : \"" << CrateMetadata->packageName
-            << "\", id : \"" << CrateMetadata->id
+            << "uid : \"" << CrateMetadata.uid
+            << "\", packageName : \"" << CrateMetadata.packageName
+            << "\", id : \"" << CrateMetadata.id
             << "\"}";
 }
 #endif
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
index 4332d4c..1f30b5d 100644
--- a/cmds/installd/CrateManager.h
+++ b/cmds/installd/CrateManager.h
@@ -25,7 +25,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -55,18 +55,18 @@
     CrateManager(const char* uuid, userid_t userId, const std::string& packageName);
     ~CrateManager();
 
-    void traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+    void traverseAllCrates(std::function<void(CratedFolder, CrateMetadata&&)>& onCreateCrate);
 
     static void traverseChildDir(const std::string& targetDir,
             std::function<void(FTSENT*)>& onVisitChildDir);
 
     static void traverseAllPackagesForUser(
-        const std::unique_ptr<std::string>& uuid,
+        const std::optional<std::string>& uuid,
         userid_t userId,
         std::function<void(FTSENT*)>& onHandlingPackage);
 
 #if CRATE_DEBUG
-    static void dump(std::unique_ptr<CrateMetadata>& CrateMetadata);
+    static void dump(const CrateMetadata& CrateMetadata);
 #endif
 private:
     std::string mRoot;
@@ -75,7 +75,7 @@
 
     void createCrate(
         CratedFolder cratedFolder,
-        std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+        std::function<void(CratedFolder, CrateMetadata&&)>& onCreateCrate);
 };
 
 } // namespace installd
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b9c1add..c55fc6a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -166,7 +166,7 @@
     }
 }
 
-binder::Status checkArgumentUuid(const std::unique_ptr<std::string>& uuid) {
+binder::Status checkArgumentUuid(const std::optional<std::string>& uuid) {
     if (!uuid || is_valid_filename(*uuid)) {
         return ok();
     } else {
@@ -175,7 +175,7 @@
     }
 }
 
-binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+binder::Status checkArgumentUuidTestOrNull(const std::optional<std::string>& uuid) {
     if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
         return ok();
     } else {
@@ -214,7 +214,7 @@
     return ok();
 }
 
-binder::Status checkArgumentPath(const std::unique_ptr<std::string>& path) {
+binder::Status checkArgumentPath(const std::optional<std::string>& path) {
     if (path) {
         return checkArgumentPath(*path);
     } else {
@@ -398,6 +398,10 @@
         PLOG(ERROR) << "Failed to prepare " << profile_dir;
         return false;
     }
+    if (selinux_android_restorecon(profile_dir.c_str(), 0)) {
+        PLOG(ERROR) << "Failed to restorecon " << profile_dir;
+        return false;
+    }
 
     const std::string ref_profile_path =
             create_primary_reference_profile_package_dir_path(packageName);
@@ -421,8 +425,8 @@
 }
 
 binder::Status InstalldNativeService::createAppDataBatched(
-        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& uuids,
-        const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& packageNames,
+        const std::optional<std::vector<std::optional<std::string>>>& uuids,
+        const std::optional<std::vector<std::optional<std::string>>>& packageNames,
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         const std::vector<std::string>& seInfos, const std::vector<int32_t>& targetSdkVersions,
         int64_t* _aidl_return) {
@@ -432,10 +436,11 @@
     ATRACE_BEGIN("createAppDataBatched");
     binder::Status ret;
     for (size_t i = 0; i < uuids->size(); i++) {
-        if (!packageNames->at(i)) {
+        std::optional<std::string> packageName = packageNames->at(i);
+        if (!packageName) {
             continue;
         }
-        ret = createAppData(uuids->at(i), *packageNames->at(i), userId, flags, appIds[i],
+        ret = createAppData(uuids->at(i), *packageName, userId, flags, appIds[i],
                 seInfos[i], targetSdkVersions[i], _aidl_return);
         if (!ret.isOk()) {
             ATRACE_END();
@@ -446,7 +451,7 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::createAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
@@ -527,7 +532,7 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::migrateAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -588,7 +593,7 @@
     return res;
 }
 
-binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::clearAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -708,7 +713,7 @@
     return res;
 }
 
-binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -780,7 +785,7 @@
     return (gid != -1) ? gid : uid;
 }
 
-binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::fixupAppData(const std::optional<std::string>& uuid,
         int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -900,7 +905,7 @@
 }
 
 binder::Status InstalldNativeService::snapshotAppData(
-        const std::unique_ptr<std::string>& volumeUuid,
+        const std::optional<std::string>& volumeUuid,
         const std::string& packageName, int32_t user, int32_t snapshotId,
         int32_t storageFlags, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
@@ -940,6 +945,33 @@
 
     auto scope_guard = android::base::make_scope_guard(deleter);
 
+    if (storageFlags & FLAG_STORAGE_DE) {
+        auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
+        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+            snapshotId, package_name);
+
+        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+        if (rc != 0) {
+            return error(rc, "Failed to create folder " + to);
+        }
+
+        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+        if (rc != 0) {
+            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+        }
+
+        // Check if we have data to copy.
+        if (access(from.c_str(), F_OK) == 0) {
+          rc = copy_directory_recursive(from.c_str(), to.c_str());
+        }
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            clear_de_on_exit = true;
+            return res;
+        }
+    }
+
     // The app may not have any data at all, in which case it's OK to skip here.
     auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
     if (access(from_ce.c_str(), F_OK) != 0) {
@@ -965,30 +997,6 @@
         LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
     }
 
-    if (storageFlags & FLAG_STORAGE_DE) {
-        auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
-        auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
-        auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
-            snapshotId, package_name);
-
-        int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
-        if (rc != 0) {
-            return error(rc, "Failed to create folder " + to);
-        }
-
-        rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
-        if (rc != 0) {
-            return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
-        }
-
-        rc = copy_directory_recursive(from.c_str(), to.c_str());
-        if (rc != 0) {
-            res = error(rc, "Failed copying " + from + " to " + to);
-            clear_de_on_exit = true;
-            return res;
-        }
-    }
-
     if (storageFlags & FLAG_STORAGE_CE) {
         auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
         auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
@@ -1027,7 +1035,7 @@
 }
 
 binder::Status InstalldNativeService::restoreAppDataSnapshot(
-        const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
+        const std::optional<std::string>& volumeUuid, const std::string& packageName,
         const int32_t appId, const std::string& seInfo, const int32_t user,
         const int32_t snapshotId, int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
@@ -1099,7 +1107,7 @@
 }
 
 binder::Status InstalldNativeService::destroyAppDataSnapshot(
-        const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
+        const std::optional<std::string> &volumeUuid, const std::string& packageName,
         const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
         int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
@@ -1132,7 +1140,7 @@
 }
 
 binder::Status InstalldNativeService::destroyCeSnapshotsNotSpecified(
-        const std::unique_ptr<std::string> &volumeUuid, const int32_t userId,
+        const std::optional<std::string> &volumeUuid, const int32_t user,
         const std::vector<int32_t>& retainSnapshotIds) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
@@ -1140,7 +1148,7 @@
 
     const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
 
-    auto base_path = create_data_misc_ce_rollback_base_path(volume_uuid, userId);
+    auto base_path = create_data_misc_ce_rollback_base_path(volume_uuid, user);
 
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(base_path.c_str()), closedir);
     if (!dir) {
@@ -1159,7 +1167,7 @@
                 std::find(retainSnapshotIds.begin(), retainSnapshotIds.end(),
                           snapshot_id) == retainSnapshotIds.end()) {
             auto rollback_path = create_data_misc_ce_rollback_path(
-                volume_uuid, userId, snapshot_id);
+                volume_uuid, user, snapshot_id);
             int res = delete_dir_contents_and_dir(rollback_path, true /* ignore_if_missing */);
             if (res != 0) {
                 return error(res, "Failed clearing snapshot " + rollback_path);
@@ -1169,8 +1177,8 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
-        const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
+binder::Status InstalldNativeService::moveCompleteApp(const std::optional<std::string>& fromUuid,
+        const std::optional<std::string>& toUuid, const std::string& packageName,
         int32_t appId, const std::string& seInfo,
         int32_t targetSdkVersion, const std::string& fromCodePath) {
     ENFORCE_UID(AID_SYSTEM);
@@ -1277,7 +1285,7 @@
     return res;
 }
 
-binder::Status InstalldNativeService::createUserData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::createUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -1295,7 +1303,7 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::destroyUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -1332,13 +1340,13 @@
     return res;
 }
 
-binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::freeCache(const std::optional<std::string>& uuid,
         int64_t targetFreeBytes, int64_t cacheReservedBytes, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    auto uuidString = uuid ? *uuid : "";
+    auto uuidString = uuid.value_or("");
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto data_path = create_data_path(uuid_);
     auto noop = (flags & FLAG_FREE_CACHE_NOOP);
@@ -1736,7 +1744,7 @@
     fts_close(fts);
 }
 
-binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::getAppSize(const std::optional<std::string>& uuid,
         const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
         int32_t appId, const std::vector<int64_t>& ceDataInodes,
         const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
@@ -1776,7 +1784,7 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
-    auto uuidString = uuid ? *uuid : "";
+    auto uuidString = uuid.value_or("");
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     if (!IsQuotaSupported(uuidString)) {
@@ -1963,7 +1971,7 @@
     return sizes;
 }
 
-binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::getUserSize(const std::optional<std::string>& uuid,
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
@@ -1983,7 +1991,7 @@
     memset(&stats, 0, sizeof(stats));
     memset(&extStats, 0, sizeof(extStats));
 
-    auto uuidString = uuid ? *uuid : "";
+    auto uuidString = uuid.value_or("");
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     if (!IsQuotaSupported(uuidString)) {
@@ -2095,7 +2103,7 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::getExternalSize(const std::optional<std::string>& uuid,
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
@@ -2110,7 +2118,7 @@
     LOG(INFO) << "Measuring external " << userId;
 #endif
 
-    auto uuidString = uuid ? *uuid : "";
+    auto uuidString = uuid.value_or("");
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
     int64_t totalSize = 0;
@@ -2194,6 +2202,9 @@
         auto obbPath = StringPrintf("%s/Android/obb",
                 create_data_media_path(uuid_, userId).c_str());
         calculate_tree_size(obbPath, &obbSize);
+        if (!(flags & FLAG_USE_QUOTA)) {
+            totalSize -= obbSize;
+        }
         ATRACE_END();
     }
 
@@ -2212,9 +2223,9 @@
 }
 
 binder::Status InstalldNativeService::getAppCrates(
-        const std::unique_ptr<std::string>& uuid,
+        const std::optional<std::string>& uuid,
         const std::vector<std::string>& packageNames, int32_t userId,
-        std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+        std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     for (const auto& packageName : packageNames) {
@@ -2223,15 +2234,15 @@
 #ifdef ENABLE_STORAGE_CRATES
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+    auto retVector = std::vector<std::optional<CrateMetadata>>();
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
 
-    std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
-            [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+    std::function<void(CratedFolder, CrateMetadata&&)> onCreateCrate =
+            [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void {
         if (cratedFolder == nullptr) {
             return;
         }
-        retVector->push_back(std::move(crateMetadata));
+        retVector.push_back(std::move(crateMetadata));
     };
 
     for (const auto& packageName : packageNames) {
@@ -2243,15 +2254,15 @@
     }
 
 #if CRATE_DEBUG
-    LOG(WARNING) << "retVector->size() =" << retVector->size();
-    for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
-        CrateManager::dump(*iter);
+    LOG(WARNING) << "retVector.size() =" << retVector.size();
+    for (auto& item : retVector) {
+        CrateManager::dump(item);
     }
 #endif
 
     *_aidl_return = std::move(retVector);
 #else // ENABLE_STORAGE_CRATES
-    *_aidl_return = nullptr;
+    _aidl_return->reset();
 
     /* prevent compile warning fail */
     if (userId < 0) {
@@ -2262,18 +2273,18 @@
 }
 
 binder::Status InstalldNativeService::getUserCrates(
-        const std::unique_ptr<std::string>& uuid, int32_t userId,
-        std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+        const std::optional<std::string>& uuid, int32_t userId,
+        std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
 #ifdef ENABLE_STORAGE_CRATES
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
-    auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+    auto retVector = std::vector<std::optional<CrateMetadata>>();
 
-    std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
-            [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+    std::function<void(CratedFolder, CrateMetadata&&)> onCreateCrate =
+            [&](CratedFolder cratedFolder, CrateMetadata&& crateMetadata) -> void {
         if (cratedFolder == nullptr) {
             return;
         }
@@ -2287,15 +2298,15 @@
     CrateManager::traverseAllPackagesForUser(uuid, userId, onHandingPackage);
 
 #if CRATE_DEBUG
-    LOG(DEBUG) << "retVector->size() =" << retVector->size();
-    for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
-        CrateManager::dump(*iter);
+    LOG(DEBUG) << "retVector.size() =" << retVector.size();
+    for (auto& item : retVector) {
+        CrateManager::dump(item);
     }
 #endif
 
     *_aidl_return = std::move(retVector);
 #else // ENABLE_STORAGE_CRATES
-    *_aidl_return = nullptr;
+    _aidl_return->reset();
 
     /* prevent compile warning fail */
     if (userId < 0) {
@@ -2305,7 +2316,7 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::setAppQuota(const std::optional<std::string>& uuid,
         int32_t userId, int32_t appId, int64_t cacheQuota) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -2376,19 +2387,19 @@
     return ok();
 }
 
-static const char* getCStr(const std::unique_ptr<std::string>& data,
+static const char* getCStr(const std::optional<std::string>& data,
         const char* default_value = nullptr) {
-    return data == nullptr ? default_value : data->c_str();
+    return data ? data->c_str() : default_value;
 }
 binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
-        const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
-        int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
-        const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-        const std::unique_ptr<std::string>& classLoaderContext,
-        const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
-        const std::unique_ptr<std::string>& profileName,
-        const std::unique_ptr<std::string>& dexMetadataPath,
-        const std::unique_ptr<std::string>& compilationReason) {
+        const std::optional<std::string>& packageName, const std::string& instructionSet,
+        int32_t dexoptNeeded, const std::optional<std::string>& outputPath, int32_t dexFlags,
+        const std::string& compilerFilter, const std::optional<std::string>& uuid,
+        const std::optional<std::string>& classLoaderContext,
+        const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
+        const std::optional<std::string>& profileName,
+        const std::optional<std::string>& dexMetadataPath,
+        const std::optional<std::string>& compilationReason) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PATH(apkPath);
@@ -2434,7 +2445,7 @@
 }
 
 binder::Status InstalldNativeService::linkNativeLibraryDirectory(
-        const std::unique_ptr<std::string>& uuid, const std::string& packageName,
+        const std::optional<std::string>& uuid, const std::string& packageName,
         const std::string& nativeLibPath32, int32_t userId) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
@@ -2525,7 +2536,7 @@
     return res;
 }
 
-binder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr<std::string>& uuid,
+binder::Status InstalldNativeService::restoreconAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
@@ -2643,7 +2654,7 @@
 }
 
 binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
-        const std::string& instructionSet, const std::unique_ptr<std::string>& outputPath) {
+        const std::string& instructionSet, const std::optional<std::string>& outputPath) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PATH(apkPath);
     CHECK_ARGUMENT_PATH(outputPath);
@@ -2795,7 +2806,7 @@
 
 binder::Status InstalldNativeService::reconcileSecondaryDexFile(
         const std::string& dexPath, const std::string& packageName, int32_t uid,
-        const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
+        const std::vector<std::string>& isas, const std::optional<std::string>& volumeUuid,
         int32_t storage_flag, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(volumeUuid);
@@ -2810,7 +2821,7 @@
 
 binder::Status InstalldNativeService::hashSecondaryDexFile(
         const std::string& dexPath, const std::string& packageName, int32_t uid,
-        const std::unique_ptr<std::string>& volumeUuid, int32_t storageFlag,
+        const std::optional<std::string>& volumeUuid, int32_t storageFlag,
         std::vector<uint8_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(volumeUuid);
@@ -2869,7 +2880,7 @@
 
 // Mount volume's CE and DE storage to mirror
 binder::Status InstalldNativeService::tryMountDataMirror(
-        const std::unique_ptr<std::string>& uuid) {
+        const std::optional<std::string>& uuid) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (!sAppDataIsolationEnabled) {
@@ -2933,7 +2944,7 @@
 
 // Unmount volume's CE and DE storage from mirror
 binder::Status InstalldNativeService::onPrivateVolumeRemoved(
-        const std::unique_ptr<std::string>& uuid) {
+        const std::optional<std::string>& uuid) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (!sAppDataIsolationEnabled) {
@@ -2977,7 +2988,7 @@
 }
 
 std::string InstalldNativeService::findDataMediaPath(
-        const std::unique_ptr<std::string>& uuid, userid_t userid) {
+        const std::optional<std::string>& uuid, userid_t userid) {
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
@@ -2990,15 +3001,14 @@
 }
 
 binder::Status InstalldNativeService::isQuotaSupported(
-        const std::unique_ptr<std::string>& uuid, bool* _aidl_return) {
-    auto uuidString = uuid ? *uuid : "";
-    *_aidl_return = IsQuotaSupported(uuidString);
+        const std::optional<std::string>& uuid, bool* _aidl_return) {
+    *_aidl_return = IsQuotaSupported(uuid.value_or(""));
     return ok();
 }
 
 binder::Status InstalldNativeService::prepareAppProfile(const std::string& packageName,
         int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
-        const std::unique_ptr<std::string>& dexMetadata, bool* _aidl_return) {
+        const std::optional<std::string>& dexMetadata, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     CHECK_ARGUMENT_PATH(codePath);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 8e7d98b..9819327 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -40,81 +40,81 @@
     static char const* getServiceName() { return "installd"; }
     virtual status_t dump(int fd, const Vector<String16> &args) override;
 
-    binder::Status createUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+    binder::Status createUserData(const std::optional<std::string>& uuid, int32_t userId,
             int32_t userSerial, int32_t flags);
-    binder::Status destroyUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+    binder::Status destroyUserData(const std::optional<std::string>& uuid, int32_t userId,
             int32_t flags);
     binder::Status createAppDataBatched(
-            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& uuids,
-            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& packageNames,
+            const std::optional<std::vector<std::optional<std::string>>>& uuids,
+            const std::optional<std::vector<std::optional<std::string>>>& packageNames,
             int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
             const std::vector<std::string>& seInfos, const std::vector<int32_t>& targetSdkVersions,
             int64_t* _aidl_return);
-    binder::Status createAppData(const std::unique_ptr<std::string>& uuid,
+    binder::Status createAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
             const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
-    binder::Status restoreconAppData(const std::unique_ptr<std::string>& uuid,
+    binder::Status restoreconAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
             const std::string& seInfo);
-    binder::Status migrateAppData(const std::unique_ptr<std::string>& uuid,
+    binder::Status migrateAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags);
-    binder::Status clearAppData(const std::unique_ptr<std::string>& uuid,
+    binder::Status clearAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
-    binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid,
+    binder::Status destroyAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
 
-    binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
+    binder::Status fixupAppData(const std::optional<std::string>& uuid, int32_t flags);
 
-    binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
+    binder::Status snapshotAppData(const std::optional<std::string>& volumeUuid,
             const std::string& packageName, const int32_t user, const int32_t snapshotId,
             int32_t storageFlags, int64_t* _aidl_return);
-    binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
+    binder::Status restoreAppDataSnapshot(const std::optional<std::string>& volumeUuid,
             const std::string& packageName, const int32_t appId, const std::string& seInfo,
             const int32_t user, const int32_t snapshotId, int32_t storageFlags);
-    binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
+    binder::Status destroyAppDataSnapshot(const std::optional<std::string> &volumeUuid,
             const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
             const int32_t snapshotId, int32_t storageFlags);
-    binder::Status destroyCeSnapshotsNotSpecified(const std::unique_ptr<std::string> &volumeUuid,
-            const int32_t userId, const std::vector<int32_t>& retainSnapshotIds);
+    binder::Status destroyCeSnapshotsNotSpecified(const std::optional<std::string> &volumeUuid,
+            const int32_t user, const std::vector<int32_t>& retainSnapshotIds);
 
-    binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
+    binder::Status getAppSize(const std::optional<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
             int32_t appId, const std::vector<int64_t>& ceDataInodes,
             const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return);
-    binder::Status getUserSize(const std::unique_ptr<std::string>& uuid,
+    binder::Status getUserSize(const std::optional<std::string>& uuid,
             int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
             std::vector<int64_t>* _aidl_return);
-    binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
+    binder::Status getExternalSize(const std::optional<std::string>& uuid,
             int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
             std::vector<int64_t>* _aidl_return);
 
-    binder::Status getAppCrates(const std::unique_ptr<std::string>& uuid,
+    binder::Status getAppCrates(const std::optional<std::string>& uuid,
             const std::vector<std::string>& packageNames,
             int32_t userId,
-            std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+            std::optional<std::vector<std::optional<android::os::storage::CrateMetadata>>>*
                     _aidl_return);
     binder::Status getUserCrates(
-            const std::unique_ptr<std::string>& uuid, int32_t userId,
-            std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+            const std::optional<std::string>& uuid, int32_t userId,
+            std::optional<std::vector<std::optional<android::os::storage::CrateMetadata>>>*
                     _aidl_return);
 
-    binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+    binder::Status setAppQuota(const std::optional<std::string>& uuid,
             int32_t userId, int32_t appId, int64_t cacheQuota);
 
-    binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
-            const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
+    binder::Status moveCompleteApp(const std::optional<std::string>& fromUuid,
+            const std::optional<std::string>& toUuid, const std::string& packageName,
             int32_t appId, const std::string& seInfo,
             int32_t targetSdkVersion, const std::string& fromCodePath);
 
     binder::Status dexopt(const std::string& apkPath, int32_t uid,
-            const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
-            int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
-            const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
-            const std::unique_ptr<std::string>& classLoaderContext,
-            const std::unique_ptr<std::string>& seInfo, bool downgrade,
-            int32_t targetSdkVersion, const std::unique_ptr<std::string>& profileName,
-            const std::unique_ptr<std::string>& dexMetadataPath,
-            const std::unique_ptr<std::string>& compilationReason);
+            const std::optional<std::string>& packageName, const std::string& instructionSet,
+            int32_t dexoptNeeded, const std::optional<std::string>& outputPath, int32_t dexFlags,
+            const std::string& compilerFilter, const std::optional<std::string>& uuid,
+            const std::optional<std::string>& classLoaderContext,
+            const std::optional<std::string>& seInfo, bool downgrade,
+            int32_t targetSdkVersion, const std::optional<std::string>& profileName,
+            const std::optional<std::string>& dexMetadataPath,
+            const std::optional<std::string>& compilationReason);
 
     binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
                                   const std::string& outDexFile, int uid, bool* _aidl_return);
@@ -137,9 +137,9 @@
             const std::string& profileName);
 
     binder::Status rmPackageDir(const std::string& packageDir);
-    binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t targetFreeBytes,
+    binder::Status freeCache(const std::optional<std::string>& uuid, int64_t targetFreeBytes,
             int64_t cacheReservedBytes, int32_t flags);
-    binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
+    binder::Status linkNativeLibraryDirectory(const std::optional<std::string>& uuid,
             const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
     binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
     binder::Status linkFile(const std::string& relativePath, const std::string& fromBase,
@@ -147,27 +147,27 @@
     binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet,
             const std::string& outputPath);
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
-            const std::unique_ptr<std::string>& outputPath);
+            const std::optional<std::string>& outputPath);
     binder::Status installApkVerity(const std::string& filePath,
             android::base::unique_fd verityInput, int32_t contentSize);
     binder::Status assertFsverityRootHashMatches(const std::string& filePath,
             const std::vector<uint8_t>& expectedHash);
     binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
         const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
-        const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
+        const std::optional<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
     binder::Status hashSecondaryDexFile(const std::string& dexPath,
-        const std::string& packageName, int32_t uid, const std::unique_ptr<std::string>& volumeUuid,
+        const std::string& packageName, int32_t uid, const std::optional<std::string>& volumeUuid,
         int32_t storageFlag, std::vector<uint8_t>* _aidl_return);
 
     binder::Status invalidateMounts();
-    binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
+    binder::Status isQuotaSupported(const std::optional<std::string>& volumeUuid,
             bool* _aidl_return);
-    binder::Status tryMountDataMirror(const std::unique_ptr<std::string>& volumeUuid);
-    binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
+    binder::Status tryMountDataMirror(const std::optional<std::string>& volumeUuid);
+    binder::Status onPrivateVolumeRemoved(const std::optional<std::string>& volumeUuid);
 
     binder::Status prepareAppProfile(const std::string& packageName,
             int32_t userId, int32_t appId, const std::string& profileName,
-            const std::string& codePath, const std::unique_ptr<std::string>& dexMetadata,
+            const std::string& codePath, const std::optional<std::string>& dexMetadata,
             bool* _aidl_return);
 
     binder::Status migrateLegacyObbData();
@@ -184,7 +184,7 @@
     /* Map from UID to cache quota size */
     std::unordered_map<uid_t, int64_t> mCacheQuotas;
 
-    std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid);
+    std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid);
 };
 
 }  // namespace installd
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index 9a21104..fc745d0 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -1,6 +1,5 @@
 set noparent
 
-agampe@google.com
 calin@google.com
 jsharkey@android.com
 maco@google.com
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index c6583a1..3f0fb6d 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -15,6 +15,9 @@
     {
       "name": "installd_utils_test"
     },
+    {
+      "name": "run_dex2oat_test"
+    },
     // AdoptableHostTest moves packages, part of which is handled by installd
     {
       "name": "AdoptableHostTest"
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index eeda6c5..4ac70a4 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -117,11 +117,10 @@
             int userId, int snapshotId, int storageFlags);
     void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
             int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
-    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
-            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
     void destroyCeSnapshotsNotSpecified(@nullable @utf8InCpp String uuid, int userId,
             in int[] retainSnapshotIds);
-
+    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
     void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid);
     void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ffa8724..4dfd1d0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -39,7 +39,6 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
-#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
@@ -50,11 +49,15 @@
 
 #include "dexopt.h"
 #include "dexopt_return_codes.h"
+#include "execv_helper.h"
 #include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
+#include "run_dex2oat.h"
+#include "unique_file.h"
 #include "utils.h"
 
+using android::base::Basename;
 using android::base::EndsWith;
 using android::base::GetBoolProperty;
 using android::base::GetProperty;
@@ -67,16 +70,6 @@
 namespace android {
 namespace installd {
 
-// Should minidebug info be included in compiled artifacts? Even if this value is
-// "true," usage might still be conditional to other constraints, e.g., system
-// property overrides.
-static constexpr bool kEnableMinidebugInfo = true;
-
-static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
-static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
-static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
-static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
-
 
 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
 struct FreeDelete {
@@ -186,93 +179,6 @@
     return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
 }
 
-static std::vector<std::string> SplitBySpaces(const std::string& str) {
-    if (str.empty()) {
-        return {};
-    }
-    return android::base::Split(str, " ");
-}
-
-static const char* get_location_from_path(const char* path) {
-    static constexpr char kLocationSeparator = '/';
-    const char *location = strrchr(path, kLocationSeparator);
-    if (location == nullptr) {
-        return path;
-    } else {
-        // Skip the separator character.
-        return location + 1;
-    }
-}
-
-// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
-// need to be performed between the fork and exec.
-class ExecVHelper {
-  public:
-    // Store a placeholder for the binary name.
-    ExecVHelper() : args_(1u, std::string()) {}
-
-    void PrepareArgs(const std::string& bin) {
-        CHECK(!args_.empty());
-        CHECK(args_[0].empty());
-        args_[0] = bin;
-        // Write char* into array.
-        for (const std::string& arg : args_) {
-            argv_.push_back(arg.c_str());
-        }
-        argv_.push_back(nullptr);  // Add null terminator.
-    }
-
-    [[ noreturn ]]
-    void Exec(int exit_code) {
-        execv(argv_[0], (char * const *)&argv_[0]);
-        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
-        exit(exit_code);
-    }
-
-    // Add an arg if it's not empty.
-    void AddArg(const std::string& arg) {
-        if (!arg.empty()) {
-            args_.push_back(arg);
-        }
-    }
-
-    // Add a runtime arg if it's not empty.
-    void AddRuntimeArg(const std::string& arg) {
-        if (!arg.empty()) {
-            args_.push_back("--runtime-arg");
-            args_.push_back(arg);
-        }
-    }
-
-  protected:
-    // Holder arrays for backing arg storage.
-    std::vector<std::string> args_;
-
-    // Argument poiners.
-    std::vector<const char*> argv_;
-};
-
-static std::string MapPropertyToArg(const std::string& property,
-                                    const std::string& format,
-                                    const std::string& default_value = "") {
-  std::string prop = GetProperty(property, default_value);
-  if (!prop.empty()) {
-    return StringPrintf(format.c_str(), prop.c_str());
-  }
-  return "";
-}
-
-static std::string MapPropertyToArgWithBackup(const std::string& property,
-                                              const std::string& backupProperty,
-                                              const std::string& format,
-                                              const std::string& default_value = "") {
-  std::string value = GetProperty(property, default_value);
-  if (!value.empty()) {
-    return StringPrintf(format.c_str(), value.c_str());
-  }
-  return MapPropertyToArg(backupProperty, format, default_value);
-}
-
 // Determines which binary we should use for execution (the debug or non-debug version).
 // e.g. dex2oatd vs dex2oat
 static const char* select_execution_binary(const char* binary, const char* debug_binary,
@@ -311,9 +217,6 @@
 static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
 // Feature flag name for running the JIT in Zygote experiment, b/119800099.
 static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
-// Location of the JIT Zygote image.
-static const char* kJitZygoteImage =
-    "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
 
 // Phenotype property name for enabling profiling the boot class path.
 static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
@@ -328,288 +231,11 @@
     return profile_boot_class_path == "true";
 }
 
-class RunDex2Oat : public ExecVHelper {
-  public:
-    RunDex2Oat(int zip_fd,
-               int oat_fd,
-               int input_vdex_fd,
-               int output_vdex_fd,
-               int image_fd,
-               const char* input_file_name,
-               const char* output_file_name,
-               int swap_fd,
-               const char* instruction_set,
-               const char* compiler_filter,
-               bool debuggable,
-               bool post_bootcomplete,
-               bool for_restore,
-               bool background_job_compile,
-               int profile_fd,
-               const char* class_loader_context,
-               const std::string& class_loader_context_fds,
-               int target_sdk_version,
-               bool enable_hidden_api_checks,
-               bool generate_compact_dex,
-               int dex_metadata_fd,
-               const char* compilation_reason) {
-        // Get the relative path to the input file.
-        const char* relative_input_file_name = get_location_from_path(input_file_name);
-
-        std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
-        std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
-
-        std::string threads_format = "-j%s";
-        std::string dex2oat_threads_arg = post_bootcomplete
-                ? (for_restore
-                    ? MapPropertyToArgWithBackup(
-                            "dalvik.vm.restore-dex2oat-threads",
-                            "dalvik.vm.dex2oat-threads",
-                            threads_format)
-                    : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
-                : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
-        std::string cpu_set_format = "--cpu-set=%s";
-        std::string dex2oat_cpu_set_arg = post_bootcomplete
-                ? (for_restore
-                    ? MapPropertyToArgWithBackup(
-                            "dalvik.vm.restore-dex2oat-cpu-set",
-                            "dalvik.vm.dex2oat-cpu-set",
-                            cpu_set_format)
-                    : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
-                : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
-
-        std::string bootclasspath;
-        char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
-        if (dex2oat_bootclasspath != nullptr) {
-            bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
-        }
-        // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
-        // BOOTCLASSPATH.
-
-        const std::string dex2oat_isa_features_key =
-                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
-        std::string instruction_set_features_arg =
-            MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
-
-        const std::string dex2oat_isa_variant_key =
-                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
-        std::string instruction_set_variant_arg =
-            MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
-
-        const char* dex2oat_norelocation = "-Xnorelocate";
-
-        const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
-        std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
-        ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
-
-        // If we are booting without the real /data, don't spend time compiling.
-        std::string vold_decrypt = GetProperty("vold.decrypt", "");
-        bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
-                                vold_decrypt == "1";
-
-        std::string updatable_bcp_packages =
-            MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
-                             "--updatable-bcp-packages-file=%s");
-        if (updatable_bcp_packages.empty()) {
-          // Make dex2oat fail by providing non-existent file name.
-          updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
-        }
-
-        std::string resolve_startup_string_arg =
-                MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
-                                 "--resolve-startup-const-strings=%s");
-        if (resolve_startup_string_arg.empty()) {
-          // If empty, fall back to system property.
-          resolve_startup_string_arg =
-                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
-                                 "--resolve-startup-const-strings=%s");
-        }
-
-        const std::string image_block_size_arg =
-                MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
-                                 "--max-image-block-size=%s");
-
-        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
-
-        std::string image_format_arg;
-        if (image_fd >= 0) {
-            image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
-        }
-
-        std::string dex2oat_large_app_threshold_arg =
-            MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
-
-
-
-        // Decide whether to use dex2oat64.
-        bool use_dex2oat64 = false;
-        // Check whether the device even supports 64-bit ABIs.
-        if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
-          use_dex2oat64 = GetBoolProperty("dalvik.vm.dex2oat64.enabled", false);
-        }
-        const char* dex2oat_bin = select_execution_binary(
-            (use_dex2oat64 ? kDex2oat64Path : kDex2oat32Path),
-            (use_dex2oat64 ? kDex2oatDebug64Path : kDex2oatDebug32Path),
-            background_job_compile);
-
-        bool generate_minidebug_info = kEnableMinidebugInfo &&
-                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
-
-        std::string boot_image;
-        std::string use_jitzygote_image =
-            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
-                                                                 ENABLE_JITZYGOTE_IMAGE,
-                                                                 /*default_value=*/ "");
-
-        if (use_jitzygote_image == "true" || IsBootClassPathProfilingEnable()) {
-          boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
-        } else {
-          boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
-        }
-
-        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-        // use arraysize instead.
-        std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
-        std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
-        std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
-        std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
-        std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
-        std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
-        std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
-        std::string dex2oat_compiler_filter_arg;
-        std::string dex2oat_swap_fd;
-        std::string dex2oat_image_fd;
-        std::string target_sdk_version_arg;
-        if (target_sdk_version != 0) {
-            target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
-        }
-        std::string class_loader_context_arg;
-        std::string class_loader_context_fds_arg;
-        if (class_loader_context != nullptr) {
-            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
-                                                    class_loader_context);
-            if (!class_loader_context_fds.empty()) {
-                class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
-                                                            class_loader_context_fds.c_str());
-            }
-        }
-
-        if (swap_fd >= 0) {
-            dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
-        }
-        if (image_fd >= 0) {
-            dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
-        }
-
-        // Compute compiler filter.
-        bool have_dex2oat_relocation_skip_flag = false;
-        if (skip_compilation) {
-            dex2oat_compiler_filter_arg = "--compiler-filter=extract";
-            have_dex2oat_relocation_skip_flag = true;
-        } else if (compiler_filter != nullptr) {
-            dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
-        }
-
-        if (dex2oat_compiler_filter_arg.empty()) {
-            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
-                                                           "--compiler-filter=%s");
-        }
-
-        // Check whether all apps should be compiled debuggable.
-        if (!debuggable) {
-            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
-        }
-        std::string profile_arg;
-        if (profile_fd != -1) {
-            profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
-        }
-
-        // Get the directory of the apk to pass as a base classpath directory.
-        std::string base_dir;
-        std::string apk_dir(input_file_name);
-        unsigned long dir_index = apk_dir.rfind('/');
-        bool has_base_dir = dir_index != std::string::npos;
-        if (has_base_dir) {
-            apk_dir = apk_dir.substr(0, dir_index);
-            base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
-        }
-
-        std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-        std::string compilation_reason_arg = compilation_reason == nullptr
-                ? ""
-                : std::string("--compilation-reason=") + compilation_reason;
-
-        ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
-        // Disable cdex if update input vdex is true since this combination of options is not
-        // supported.
-        const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-        AddArg(zip_fd_arg);
-        AddArg(zip_location_arg);
-        AddArg(input_vdex_fd_arg);
-        AddArg(output_vdex_fd_arg);
-        AddArg(oat_fd_arg);
-        AddArg(oat_location_arg);
-        AddArg(instruction_set_arg);
-
-        AddArg(instruction_set_variant_arg);
-        AddArg(instruction_set_features_arg);
-
-        AddArg(boot_image);
-
-        AddRuntimeArg(bootclasspath);
-        AddRuntimeArg(dex2oat_Xms_arg);
-        AddRuntimeArg(dex2oat_Xmx_arg);
-
-        AddArg(updatable_bcp_packages);
-        AddArg(resolve_startup_string_arg);
-        AddArg(image_block_size_arg);
-        AddArg(dex2oat_compiler_filter_arg);
-        AddArg(dex2oat_threads_arg);
-        AddArg(dex2oat_cpu_set_arg);
-        AddArg(dex2oat_swap_fd);
-        AddArg(dex2oat_image_fd);
-
-        if (generate_debug_info) {
-            AddArg("--generate-debug-info");
-        }
-        if (debuggable) {
-            AddArg("--debuggable");
-        }
-        AddArg(image_format_arg);
-        AddArg(dex2oat_large_app_threshold_arg);
-
-        if (have_dex2oat_relocation_skip_flag) {
-            AddRuntimeArg(dex2oat_norelocation);
-        }
-        AddArg(profile_arg);
-        AddArg(base_dir);
-        AddArg(class_loader_context_arg);
-        AddArg(class_loader_context_fds_arg);
-        if (generate_minidebug_info) {
-            AddArg(kMinidebugDex2oatFlag);
-        }
-        if (disable_cdex) {
-            AddArg(kDisableCompactDexFlag);
-        }
-        AddRuntimeArg(target_sdk_version_arg);
-        if (enable_hidden_api_checks) {
-            AddRuntimeArg("-Xhidden-api-policy:enabled");
-        }
-
-        if (dex_metadata_fd > -1) {
-            AddArg(dex_metadata_fd_arg);
-        }
-
-        AddArg(compilation_reason_arg);
-
-        // Do not add args after dex2oat_flags, they should override others for debugging.
-        args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
-
-        PrepareArgs(dex2oat_bin);
+static void UnlinkIgnoreResult(const std::string& path) {
+    if (unlink(path.c_str()) < 0) {
+        PLOG(ERROR) << "Failed to unlink " << path;
     }
-};
+}
 
 /*
  * Whether dexopt should use a swap file when compiling an APK.
@@ -727,6 +353,16 @@
     return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
 }
 
+static UniqueFile open_reference_profile_as_unique_file(uid_t uid, const std::string& package_name,
+        const std::string& location, bool read_write, bool is_secondary_dex) {
+    std::string profile_path = create_reference_profile_path(package_name, location,
+                                                             is_secondary_dex);
+    unique_fd ufd = open_profile(uid, profile_path, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+    return UniqueFile(ufd.release(), profile_path, [](const std::string& path) {
+        clear_profile(path);
+    });
+}
+
 static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
         const std::string& location) {
     std::string profile = create_snapshot_profile_path(package_name, location);
@@ -814,6 +450,26 @@
             AddArg("--boot-image-merge");
         }
 
+        // The percent won't exceed 100, otherwise, don't set it and use the
+        // default one set in profman.
+        uint32_t min_new_classes_percent_change = ::android::base::GetUintProperty<uint32_t>(
+            "dalvik.vm.bgdexopt.new-classes-percent",
+            /*default*/std::numeric_limits<uint32_t>::max());
+        if (min_new_classes_percent_change <= 100) {
+          AddArg("--min-new-classes-percent-change=" +
+                 std::to_string(min_new_classes_percent_change));
+        }
+
+        // The percent won't exceed 100, otherwise, don't set it and use the
+        // default one set in profman.
+        uint32_t min_new_methods_percent_change = ::android::base::GetUintProperty<uint32_t>(
+            "dalvik.vm.bgdexopt.new-methods-percent",
+            /*default*/std::numeric_limits<uint32_t>::max());
+        if (min_new_methods_percent_change <= 100) {
+          AddArg("--min-new-methods-percent-change=" +
+                 std::to_string(min_new_methods_percent_change));
+        }
+
         // Do not add after dex2oat_flags, they should override others for debugging.
         PrepareArgs(profman_bin);
     }
@@ -868,6 +524,7 @@
                   /*for_boot_image*/false);
     }
 
+    using ExecVHelper::Exec;  // To suppress -Wno-overloaded-virtual
     void Exec() {
         ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
     }
@@ -1022,7 +679,7 @@
         PLOG(ERROR) << "installd cannot open " << code_path.c_str();
         return false;
     }
-    dex_locations.push_back(get_location_from_path(code_path.c_str()));
+    dex_locations.push_back(Basename(code_path));
     apk_fds.push_back(std::move(apk_fd));
 
 
@@ -1216,118 +873,14 @@
     return true;
 }
 
-// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
-// on destruction. It will also run the given cleanup (unless told not to) after closing.
-//
-// Usage example:
-//
-//   Dex2oatFileWrapper file(open(...),
-//                                                   [name]() {
-//                                                       unlink(name.c_str());
-//                                                   });
-//   // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
-//            wrapper if captured as a reference.
-//
-//   if (file.get() == -1) {
-//       // Error opening...
-//   }
-//
-//   ...
-//   if (error) {
-//       // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
-//       // and delete the file (after the fd is closed).
-//       return -1;
-//   }
-//
-//   (Success case)
-//   file.SetCleanup(false);
-//   // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
-//   // (leaving the file around; after the fd is closed).
-//
-class Dex2oatFileWrapper {
- public:
-    Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
-    }
-
-    Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
-            : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
-
-    Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
-        value_ = other.value_;
-        cleanup_ = other.cleanup_;
-        do_cleanup_ = other.do_cleanup_;
-        auto_close_ = other.auto_close_;
-        other.release();
-    }
-
-    Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
-        value_ = other.value_;
-        cleanup_ = other.cleanup_;
-        do_cleanup_ = other.do_cleanup_;
-        auto_close_ = other.auto_close_;
-        other.release();
-        return *this;
-    }
-
-    ~Dex2oatFileWrapper() {
-        reset(-1);
-    }
-
-    int get() {
-        return value_;
-    }
-
-    void SetCleanup(bool cleanup) {
-        do_cleanup_ = cleanup;
-    }
-
-    void reset(int new_value) {
-        if (auto_close_ && value_ >= 0) {
-            close(value_);
-        }
-        if (do_cleanup_ && cleanup_ != nullptr) {
-            cleanup_();
-        }
-
-        value_ = new_value;
-    }
-
-    void reset(int new_value, std::function<void ()> new_cleanup) {
-        if (auto_close_ && value_ >= 0) {
-            close(value_);
-        }
-        if (do_cleanup_ && cleanup_ != nullptr) {
-            cleanup_();
-        }
-
-        value_ = new_value;
-        cleanup_ = new_cleanup;
-    }
-
-    void DisableAutoClose() {
-        auto_close_ = false;
-    }
-
- private:
-    void release() {
-        value_ = -1;
-        do_cleanup_ = false;
-        cleanup_ = nullptr;
-    }
-    int value_;
-    std::function<void ()> cleanup_;
-    bool do_cleanup_;
-    bool auto_close_;
-};
-
 // (re)Creates the app image if needed.
-Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path,
+UniqueFile maybe_open_app_image(const std::string& out_oat_path,
         bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) {
 
     const std::string image_path = create_image_filename(out_oat_path);
     if (image_path.empty()) {
         // Happens when the out_oat_path has an unknown extension.
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
 
     // In case there is a stale image, remove it now. Ignore any error.
@@ -1335,18 +888,19 @@
 
     // Not enabled, exit.
     if (!generate_app_image) {
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
     std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
     if (app_image_format.empty()) {
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
     // Recreate is true since we do not want to modify a mapped image. If the app is
     // already running and we modify the image file, it can cause crashes (b/27493510).
-    Dex2oatFileWrapper wrapper_fd(
+    UniqueFile image_file(
             open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
-            [image_path]() { unlink(image_path.c_str()); });
-    if (wrapper_fd.get() < 0) {
+            image_path,
+            UnlinkIgnoreResult);
+    if (image_file.fd() < 0) {
         // Could not create application image file. Go on since we can compile without it.
         LOG(ERROR) << "installd could not create '" << image_path
                 << "' for image file during dexopt";
@@ -1357,21 +911,21 @@
             }
         }
     } else if (!set_permissions_and_ownership(
-                wrapper_fd.get(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
+                image_file.fd(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
-        wrapper_fd.reset(-1);
+        image_file.reset();
     }
 
-    return wrapper_fd;
+    return image_file;
 }
 
 // Creates the dexopt swap file if necessary and return its fd.
 // Returns -1 if there's no need for a swap or in case of errors.
-unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+unique_fd maybe_open_dexopt_swap_file(const std::string& out_oat_path) {
     if (!ShouldUseSwapFileForDexopt()) {
         return invalid_unique_fd();
     }
-    auto swap_file_name = std::string(out_oat_path) + ".swap";
+    auto swap_file_name = out_oat_path + ".swap";
     unique_fd swap_fd(open_output_file(
             swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
     if (swap_fd.get() < 0) {
@@ -1389,13 +943,13 @@
 
 // Opens the reference profiles if needed.
 // Note that the reference profile might not exist so it's OK if the fd will be -1.
-Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
+UniqueFile maybe_open_reference_profile(const std::string& pkgname,
         const std::string& dex_path, const char* profile_name, bool profile_guided,
         bool is_public, int uid, bool is_secondary_dex) {
     // If we are not profile guided compilation, or we are compiling system server
     // do not bother to open the profiles; we won't be using them.
     if (!profile_guided || (pkgname[0] == '*')) {
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
 
     // If this is a secondary dex path which is public do not open the profile.
@@ -1407,7 +961,7 @@
     // compiling with a public profile from the .dm file the PackageManager will
     // set is_public toghether with the profile guided compilation.
     if (is_secondary_dex && is_public) {
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
 
     // Open reference profile in read only mode as dex2oat does not get write permissions.
@@ -1417,33 +971,28 @@
     } else {
         if (profile_name == nullptr) {
             // This path is taken for system server re-compilation lunched from ZygoteInit.
-            return Dex2oatFileWrapper();
+            return UniqueFile();
         } else {
             location = profile_name;
         }
     }
-    unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false,
-            is_secondary_dex);
-    const auto& cleanup = [pkgname, location, is_secondary_dex]() {
-        clear_reference_profile(pkgname, location, is_secondary_dex);
-    };
-    return Dex2oatFileWrapper(ufd.release(), cleanup);
+    return open_reference_profile_as_unique_file(uid, pkgname, location, /*read_write*/false,
+                                                 is_secondary_dex);
 }
 
-// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
-// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper and the output fd to
+// out_vdex_wrapper. Returns true for success or false in case of errors.
 bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
         const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
-        bool profile_guided, Dex2oatFileWrapper* in_vdex_wrapper_fd,
-        Dex2oatFileWrapper* out_vdex_wrapper_fd) {
-    CHECK(in_vdex_wrapper_fd != nullptr);
-    CHECK(out_vdex_wrapper_fd != nullptr);
+        bool profile_guided, UniqueFile* in_vdex_wrapper,
+        UniqueFile* out_vdex_wrapper) {
+    CHECK(in_vdex_wrapper != nullptr);
+    CHECK(out_vdex_wrapper != nullptr);
     // Open the existing VDEX. We do this before creating the new output VDEX, which will
     // unlink the old one.
     char in_odex_path[PKG_PATH_MAX];
     int dexopt_action = abs(dexopt_needed);
     bool is_odex_location = dexopt_needed < 0;
-    std::string in_vdex_path_str;
 
     // Infer the name of the output VDEX.
     const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
@@ -1465,7 +1014,7 @@
         } else {
             path = out_oat_path;
         }
-        in_vdex_path_str = create_vdex_filename(path);
+        std::string in_vdex_path_str = create_vdex_filename(path);
         if (in_vdex_path_str.empty()) {
             ALOGE("installd cannot compute input vdex location for '%s'\n", path);
             return false;
@@ -1483,13 +1032,15 @@
             !profile_guided;
         if (update_vdex_in_place) {
             // Open the file read-write to be able to update it.
-            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
-            if (in_vdex_wrapper_fd->get() == -1) {
+            in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0),
+                                   in_vdex_path_str);
+            if (in_vdex_wrapper->fd() == -1) {
                 // If we failed to open the file, we cannot update it in place.
                 update_vdex_in_place = false;
             }
         } else {
-            in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+            in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0),
+                                   in_vdex_path_str);
         }
     }
 
@@ -1498,22 +1049,24 @@
     if (update_vdex_in_place) {
         // We unlink the file in case the invocation of dex2oat fails, to ensure we don't
         // have bogus stale vdex files.
-        out_vdex_wrapper_fd->reset(
-              in_vdex_wrapper_fd->get(),
-              [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+        out_vdex_wrapper->reset(
+              in_vdex_wrapper->fd(),
+              out_vdex_path_str,
+              UnlinkIgnoreResult);
         // Disable auto close for the in wrapper fd (it will be done when destructing the out
         // wrapper).
-        in_vdex_wrapper_fd->DisableAutoClose();
+        in_vdex_wrapper->DisableAutoClose();
     } else {
-        out_vdex_wrapper_fd->reset(
+        out_vdex_wrapper->reset(
               open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
-              [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
-        if (out_vdex_wrapper_fd->get() < 0) {
+              out_vdex_path_str,
+              UnlinkIgnoreResult);
+        if (out_vdex_wrapper->fd() < 0) {
             ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
             return false;
         }
     }
-    if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+    if (!set_permissions_and_ownership(out_vdex_wrapper->fd(), is_public, uid,
             out_vdex_path_str.c_str(), is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
         return false;
@@ -1524,25 +1077,24 @@
 }
 
 // Opens the output oat file for the given apk.
-// If successful it stores the output path into out_oat_path and returns true.
-Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
-        bool is_public, int uid, const char* instruction_set, bool is_secondary_dex,
-        char* out_oat_path) {
+UniqueFile open_oat_out_file(const char* apk_path, const char* oat_dir,
+        bool is_public, int uid, const char* instruction_set, bool is_secondary_dex) {
+    char out_oat_path[PKG_PATH_MAX];
     if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
-        return Dex2oatFileWrapper();
+        return UniqueFile();
     }
-    const std::string out_oat_path_str(out_oat_path);
-    Dex2oatFileWrapper wrapper_fd(
+    UniqueFile oat(
             open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
-            [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
-    if (wrapper_fd.get() < 0) {
+            out_oat_path,
+            UnlinkIgnoreResult);
+    if (oat.fd() < 0) {
         PLOG(ERROR) << "installd cannot open output during dexopt" <<  out_oat_path;
     } else if (!set_permissions_and_ownership(
-                wrapper_fd.get(), is_public, uid, out_oat_path, is_secondary_dex)) {
+                oat.fd(), is_public, uid, out_oat_path, is_secondary_dex)) {
         ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
-        wrapper_fd.reset(-1);
+        oat.reset();
     }
-    return wrapper_fd;
+    return oat;
 }
 
 // Creates RDONLY fds for oat and vdex files, if exist.
@@ -1578,23 +1130,6 @@
     return true;
 }
 
-// Updates the access times of out_oat_path based on those from apk_path.
-void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
-    struct stat input_stat;
-    memset(&input_stat, 0, sizeof(input_stat));
-    if (stat(apk_path, &input_stat) != 0) {
-        PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
-        return;
-    }
-
-    struct utimbuf ut;
-    ut.actime = input_stat.st_atime;
-    ut.modtime = input_stat.st_mtime;
-    if (utime(out_oat_path, &ut) != 0) {
-        PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
-    }
-}
-
 // Runs (execv) dexoptanalyzer on the given arguments.
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
@@ -2149,8 +1684,8 @@
     }
 
     // Open the input file.
-    unique_fd input_fd(open(dex_path, O_RDONLY, 0));
-    if (input_fd.get() < 0) {
+    UniqueFile in_dex(open(dex_path, O_RDONLY, 0), dex_path);
+    if (in_dex.fd() < 0) {
         *error_msg = StringPrintf("installd cannot open '%s' for input during dexopt", dex_path);
         LOG(ERROR) << *error_msg;
         return -1;
@@ -2164,19 +1699,19 @@
     }
 
     // Create the output OAT file.
-    char out_oat_path[PKG_PATH_MAX];
-    Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
-            instruction_set, is_secondary_dex, out_oat_path);
-    if (out_oat_fd.get() < 0) {
+    UniqueFile out_oat = open_oat_out_file(dex_path, oat_dir, is_public, uid,
+            instruction_set, is_secondary_dex);
+    if (out_oat.fd() < 0) {
         *error_msg = "Could not open out oat file.";
         return -1;
     }
 
     // Open vdex files.
-    Dex2oatFileWrapper in_vdex_fd;
-    Dex2oatFileWrapper out_vdex_fd;
-    if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
-            is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+    UniqueFile in_vdex;
+    UniqueFile out_vdex;
+    if (!open_vdex_files_for_dex2oat(dex_path, out_oat.path().c_str(), dexopt_needed,
+            instruction_set, is_public, uid, is_secondary_dex, profile_guided, &in_vdex,
+            &out_vdex)) {
         *error_msg = "Could not open vdex files.";
         return -1;
     }
@@ -2196,63 +1731,85 @@
     }
 
     // Create a swap file if necessary.
-    unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
+    unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat.path());
 
     // Open the reference profile if needed.
-    Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
+    UniqueFile reference_profile = maybe_open_reference_profile(
             pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
 
-    if (reference_profile_fd.get() == -1) {
+    if (reference_profile.fd() == -1) {
         // We don't create an app image without reference profile since there is no speedup from
         // loading it in that case and instead will be a small overhead.
         generate_app_image = false;
     }
 
     // Create the app image file if needed.
-    Dex2oatFileWrapper image_fd = maybe_open_app_image(
-            out_oat_path, generate_app_image, is_public, uid, is_secondary_dex);
+    UniqueFile out_image = maybe_open_app_image(
+            out_oat.path(), generate_app_image, is_public, uid, is_secondary_dex);
 
-    unique_fd dex_metadata_fd;
+    UniqueFile dex_metadata;
     if (dex_metadata_path != nullptr) {
-        dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
-        if (dex_metadata_fd.get() < 0) {
+        dex_metadata.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)),
+                           dex_metadata_path);
+        if (dex_metadata.fd() < 0) {
             PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
         }
     }
 
+    std::string jitzygote_flag = server_configurable_flags::GetServerConfigurableFlag(
+        RUNTIME_NATIVE_BOOT_NAMESPACE,
+        ENABLE_JITZYGOTE_IMAGE,
+        /*default_value=*/ "");
+    bool use_jitzygote_image = jitzygote_flag == "true" || IsBootClassPathProfilingEnable();
+
+    // Decide whether to use dex2oat64.
+    bool use_dex2oat64 = false;
+    // Check whether the device even supports 64-bit ABIs.
+    if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
+      use_dex2oat64 = GetBoolProperty("dalvik.vm.dex2oat64.enabled", false);
+    }
+    const char* dex2oat_bin = select_execution_binary(
+        (use_dex2oat64 ? kDex2oat64Path : kDex2oat32Path),
+        (use_dex2oat64 ? kDex2oatDebug64Path : kDex2oatDebug32Path),
+        background_job_compile);
+
+    auto execv_helper = std::make_unique<ExecVHelper>();
+
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
-    RunDex2Oat runner(input_fd.get(),
-                      out_oat_fd.get(),
-                      in_vdex_fd.get(),
-                      out_vdex_fd.get(),
-                      image_fd.get(),
-                      dex_path,
-                      out_oat_path,
+    RunDex2Oat runner(dex2oat_bin, execv_helper.get());
+    runner.Initialize(out_oat,
+                      out_vdex,
+                      out_image,
+                      in_dex,
+                      in_vdex,
+                      dex_metadata,
+                      reference_profile,
+                      class_loader_context,
+                      join_fds(context_input_fds),
                       swap_fd.get(),
                       instruction_set,
                       compiler_filter,
                       debuggable,
                       boot_complete,
                       for_restore,
-                      background_job_compile,
-                      reference_profile_fd.get(),
-                      class_loader_context,
-                      join_fds(context_input_fds),
                       target_sdk_version,
                       enable_hidden_api_checks,
                       generate_compact_dex,
-                      dex_metadata_fd.get(),
+                      use_jitzygote_image,
                       compilation_reason);
 
     pid_t pid = fork();
     if (pid == 0) {
+        // Need to set schedpolicy before dropping privileges
+        // for cgroup migration. See details at b/175178520.
+        SetDex2OatScheduling(boot_complete);
+
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        SetDex2OatScheduling(boot_complete);
-        if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
-            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
+        if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
+            PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
             _exit(DexoptReturnCodes::kFlock);
         }
 
@@ -2269,13 +1826,11 @@
         }
     }
 
-    update_out_oat_access_times(dex_path, out_oat_path);
-
     // We've been successful, don't delete output.
-    out_oat_fd.SetCleanup(false);
-    out_vdex_fd.SetCleanup(false);
-    image_fd.SetCleanup(false);
-    reference_profile_fd.SetCleanup(false);
+    out_oat.DisableCleanup();
+    out_vdex.DisableCleanup();
+    out_image.DisableCleanup();
+    reference_profile.DisableCleanup();
 
     return 0;
 }
@@ -2325,7 +1880,7 @@
 //   out_secondary_dex_exists will be set to false.
 bool reconcile_secondary_dex_file(const std::string& dex_path,
         const std::string& pkgname, int uid, const std::vector<std::string>& isas,
-        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+        const std::optional<std::string>& volume_uuid, int storage_flag,
         /*out*/bool* out_secondary_dex_exists) {
     *out_secondary_dex_exists = false;  // start by assuming the file does not exist.
     if (isas.size() == 0) {
@@ -2346,7 +1901,7 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+        const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
                 uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
@@ -2447,11 +2002,11 @@
 // the app.
 // For any other errors (e.g. if any of the parameters are invalid) returns false.
 bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid,
-        const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+        const std::optional<std::string>& volume_uuid, int storage_flag,
         std::vector<uint8_t>* out_secondary_dex_hash) {
     out_secondary_dex_hash->clear();
 
-    const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+    const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
 
     if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
         LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: "
@@ -2978,7 +2533,7 @@
                          appid_t app_id,
                          const std::string& profile_name,
                          const std::string& code_path,
-                         const std::unique_ptr<std::string>& dex_metadata) {
+                         const std::optional<std::string>& dex_metadata) {
     // Prepare the current profile.
     std::string cur_profile  = create_current_profile_path(user_id, package_name, profile_name,
             /*is_secondary_dex*/ false);
@@ -2989,7 +2544,7 @@
     }
 
     // Check if we need to install the profile from the dex metadata.
-    if (dex_metadata == nullptr) {
+    if (!dex_metadata) {
         return true;
     }
 
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index cc44873..d35953c 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -21,6 +21,8 @@
 
 #include <sys/types.h>
 
+#include <optional>
+
 #include <cutils/multiuser.h>
 
 namespace android {
@@ -100,17 +102,17 @@
                          appid_t app_id,
                          const std::string& profile_name,
                          const std::string& code_path,
-                         const std::unique_ptr<std::string>& dex_metadata);
+                         const std::optional<std::string>& dex_metadata);
 
 bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
 
 bool reconcile_secondary_dex_file(const std::string& dex_path,
         const std::string& pkgname, int uid, const std::vector<std::string>& isas,
-        const std::unique_ptr<std::string>& volumeUuid, int storage_flag,
+        const std::optional<std::string>& volumeUuid, int storage_flag,
         /*out*/bool* out_secondary_dex_exists);
 
 bool hash_secondary_dex_file(const std::string& dex_path,
-        const std::string& pkgname, int uid, const std::unique_ptr<std::string>& volume_uuid,
+        const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid,
         int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
 
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
index bbecfa4..e5198ad 100644
--- a/cmds/installd/dexopt_return_codes.h
+++ b/cmds/installd/dexopt_return_codes.h
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include <dex2oat_return_codes.h>
-
 namespace android {
 namespace installd {
 
@@ -70,48 +68,21 @@
     return nullptr;
 }
 
-inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
-    switch (code) {
-        case art::dex2oat::ReturnCode::kNoFailure:
-            return "dex2oat success";
-        case art::dex2oat::ReturnCode::kOther:
-            return "unspecified dex2oat error";
-        case art::dex2oat::ReturnCode::kCreateRuntime:
-            return "dex2oat failed to create a runtime";
+inline const char* get_dex2oat_return_code_name(int code) {
+    if (code == 0) {
+        return "dex2oat success";
+    } else {
+        return "dex2oat error";
     }
-    return nullptr;
 }
 
-// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
-// exit codes) as well as art::dex2oat::ReturnCode.
+// Get some slightly descriptive string for the return code.
 inline const char* get_return_code_name(int code) {
-    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
-    // TODO: How could switch-case checks be used to enforce completeness?
-    switch (code) {
-        case kSetGid:
-        case kSetUid:
-        case kCapSet:
-        case kFlock:
-        case kProfmanExec:
-        case kSetSchedPolicy:
-        case kSetPriority:
-        case kDex2oatExec:
-        case kInstructionSetLength:
-        case kHashValidatePath:
-        case kHashOpenPath:
-        case kHashReadDex:
-        case kHashWrite:
-            break;
-        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
-        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
-        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
-            break;
-    }
     const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
     if (value != nullptr) {
         return value;
     }
-    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    value = get_dex2oat_return_code_name(code);
     return value;
 }
 
diff --git a/cmds/installd/execv_helper.cpp b/cmds/installd/execv_helper.cpp
new file mode 100644
index 0000000..a2d240a
--- /dev/null
+++ b/cmds/installd/execv_helper.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "installd"
+
+#include "execv_helper.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+namespace android {
+namespace installd {
+
+// Store a placeholder for the binary name.
+ExecVHelper::ExecVHelper() : args_(1u, std::string()) {}
+
+ExecVHelper::~ExecVHelper() {}
+
+void ExecVHelper::PrepareArgs(const std::string& bin) {
+    CHECK(!args_.empty());
+    CHECK(args_[0].empty());
+    args_[0] = bin;
+    // Write char* into array.
+    for (const std::string& arg : args_) {
+        argv_.push_back(arg.c_str());
+    }
+    argv_.push_back(nullptr);  // Add null terminator.
+}
+
+void ExecVHelper::Exec(int exit_code) {
+    execv(argv_[0], (char * const *)&argv_[0]);
+    PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
+    exit(exit_code);
+}
+
+void ExecVHelper::AddArg(const std::string& arg) {
+    if (!arg.empty()) {
+        args_.push_back(arg);
+    }
+}
+
+void ExecVHelper::AddRuntimeArg(const std::string& arg) {
+    if (!arg.empty()) {
+        args_.push_back("--runtime-arg");
+        args_.push_back(arg);
+    }
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/execv_helper.h b/cmds/installd/execv_helper.h
new file mode 100644
index 0000000..9adfc0e
--- /dev/null
+++ b/cmds/installd/execv_helper.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_EXECV_HELPER_H
+#define ANDROID_INSTALLD_EXECV_HELPER_H
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace installd {
+
+// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
+// need to be performed between the fork and exec.
+class ExecVHelper {
+  public:
+    ExecVHelper();
+    virtual ~ExecVHelper();
+
+    [[ noreturn ]]
+    virtual void Exec(int exit_code);
+
+    void PrepareArgs(const std::string& bin);
+
+    // Add an arg if it's not empty.
+    void AddArg(const std::string& arg);
+
+    // Add a runtime arg if it's not empty.
+    void AddRuntimeArg(const std::string& arg);
+
+  protected:
+    // Holder arrays for backing arg storage.
+    std::vector<std::string> args_;
+
+    // Argument poiners.
+    std::vector<const char*> argv_;
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_EXECV_HELPER_H
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 18f8268..443821c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -31,10 +31,8 @@
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <art_image_values.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
-#include <dex2oat_return_codes.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -96,7 +94,7 @@
 
 template<typename T>
 static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
-    return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
+    return (x & -n);
 }
 
 template<typename T>
@@ -523,6 +521,7 @@
     // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
     static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
         constexpr size_t kPageSize = PAGE_SIZE;
+        static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two");
         CHECK_EQ(min_delta % kPageSize, 0u);
         CHECK_EQ(max_delta % kPageSize, 0u);
         CHECK_LT(min_delta, max_delta);
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 6459805..72c03bf 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -68,15 +68,15 @@
                                        apex::kApexPackageVendorDir};
     for (const auto& dir : apex_dirs) {
         // Cast call to void to suppress warn_unused_result.
-        static_cast<void>(apex::scanPackagesDirAndActivate(dir));
+        static_cast<void>(apex::ScanPackagesDirAndActivate(dir));
     }
-    return apex::getActivePackages();
+    return apex::GetActivePackages();
 }
 
 static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
     for (const apex::ApexFile& apex_file : active_packages) {
         const std::string& package_path = apex_file.GetPath();
-        base::Result<void> status = apex::deactivatePackage(package_path);
+        base::Result<void> status = apex::DeactivatePackage(package_path);
         if (!status.ok()) {
             LOG(ERROR) << "Failed to deactivate " << package_path << ": "
                        << status.error();
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
new file mode 100644
index 0000000..17ea903
--- /dev/null
+++ b/cmds/installd/run_dex2oat.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "installd"
+
+#include "run_dex2oat.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+
+#include "unique_file.h"
+
+using android::base::Basename;
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+namespace {
+
+// Should minidebug info be included in compiled artifacts? Even if this value is
+// "true," usage might still be conditional to other constraints, e.g., system
+// property overrides.
+static constexpr bool kEnableMinidebugInfo = true;
+
+static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
+static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
+static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
+static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
+
+// Location of the JIT Zygote image.
+static const char* kJitZygoteImage =
+    "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
+
+std::vector<std::string> SplitBySpaces(const std::string& str) {
+    if (str.empty()) {
+        return {};
+    }
+    return android::base::Split(str, " ");
+}
+
+}  // namespace
+
+RunDex2Oat::RunDex2Oat(const char* dex2oat_bin, ExecVHelper* execv_helper)
+  : dex2oat_bin_(dex2oat_bin), execv_helper_(execv_helper) {}
+
+void RunDex2Oat::Initialize(const UniqueFile& output_oat,
+                            const UniqueFile& output_vdex,
+                            const UniqueFile& output_image,
+                            const UniqueFile& input_dex,
+                            const UniqueFile& input_vdex,
+                            const UniqueFile& dex_metadata,
+                            const UniqueFile& profile,
+                            const char* class_loader_context,
+                            const std::string& class_loader_context_fds,
+                            int swap_fd,
+                            const char* instruction_set,
+                            const char* compiler_filter,
+                            bool debuggable,
+                            bool post_bootcomplete,
+                            bool for_restore,
+                            int target_sdk_version,
+                            bool enable_hidden_api_checks,
+                            bool generate_compact_dex,
+                            bool use_jitzygote_image,
+                            const char* compilation_reason) {
+    PrepareBootImageAndBootClasspathFlags(use_jitzygote_image);
+
+    PrepareInputFileFlags(output_oat, output_vdex, output_image, input_dex, input_vdex,
+                          dex_metadata, profile, swap_fd, class_loader_context,
+                          class_loader_context_fds);
+
+    PrepareCompilerConfigFlags(input_vdex, output_vdex, instruction_set, compiler_filter,
+                               debuggable, target_sdk_version, enable_hidden_api_checks,
+                               generate_compact_dex, compilation_reason);
+
+    PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore);
+
+    const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+    std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+
+    // Do not add args after dex2oat_flags, they should override others for debugging.
+    for (auto it = dex2oat_flags_args.begin(); it != dex2oat_flags_args.end(); ++it) {
+        AddArg(*it);
+    }
+
+    execv_helper_->PrepareArgs(dex2oat_bin_);
+}
+
+RunDex2Oat::~RunDex2Oat() {}
+
+void RunDex2Oat::PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image) {
+    std::string boot_image;
+    if (use_jitzygote_image) {
+        boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
+    } else {
+        boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
+    }
+    AddArg(boot_image);
+
+    // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+    // BOOTCLASSPATH.
+    char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+    if (dex2oat_bootclasspath != nullptr) {
+        AddRuntimeArg(StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath));
+    }
+
+    std::string updatable_bcp_packages =
+            MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
+                             "--updatable-bcp-packages-file=%s");
+    if (updatable_bcp_packages.empty()) {
+        // Make dex2oat fail by providing non-existent file name.
+        updatable_bcp_packages =
+                "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
+    }
+    AddArg(updatable_bcp_packages);
+}
+
+void RunDex2Oat::PrepareInputFileFlags(const UniqueFile& output_oat,
+                                       const UniqueFile& output_vdex,
+                                       const UniqueFile& output_image,
+                                       const UniqueFile& input_dex,
+                                       const UniqueFile& input_vdex,
+                                       const UniqueFile& dex_metadata,
+                                       const UniqueFile& profile,
+                                       int swap_fd,
+                                       const char* class_loader_context,
+                                       const std::string& class_loader_context_fds) {
+    std::string input_basename = Basename(input_dex.path());
+    LOG(VERBOSE) << "Running " << dex2oat_bin_ << " in=" << input_basename << " out="
+                 << output_oat.path();
+
+    AddArg(StringPrintf("--zip-fd=%d", input_dex.fd()));
+    AddArg(StringPrintf("--zip-location=%s", input_basename.c_str()));
+    AddArg(StringPrintf("--oat-fd=%d", output_oat.fd()));
+    AddArg(StringPrintf("--oat-location=%s", output_oat.path().c_str()));
+    AddArg(StringPrintf("--input-vdex-fd=%d", input_vdex.fd()));
+    AddArg(StringPrintf("--output-vdex-fd=%d", output_vdex.fd()));
+
+    if (output_image.fd() >= 0) {
+        AddArg(StringPrintf("--app-image-fd=%d", output_image.fd()));
+        AddArg(MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s"));
+    }
+    if (dex_metadata.fd() > -1) {
+        AddArg("--dm-fd=" + std::to_string(dex_metadata.fd()));
+    }
+    if (profile.fd() != -1) {
+        AddArg(StringPrintf("--profile-file-fd=%d", profile.fd()));
+    }
+    if (swap_fd >= 0) {
+        AddArg(StringPrintf("--swap-fd=%d", swap_fd));
+    }
+
+    // Get the directory of the apk to pass as a base classpath directory.
+    {
+        std::string apk_dir(input_dex.path());
+        size_t dir_index = apk_dir.rfind('/');
+        if (dir_index != std::string::npos) {
+            apk_dir = apk_dir.substr(0, dir_index);
+            AddArg(StringPrintf("--classpath-dir=%s", apk_dir.c_str()));
+        }
+    }
+
+    if (class_loader_context != nullptr) {
+        AddArg(StringPrintf("--class-loader-context=%s", class_loader_context));
+        if (!class_loader_context_fds.empty()) {
+            AddArg(StringPrintf("--class-loader-context-fds=%s",
+                                class_loader_context_fds.c_str()));
+        }
+    }
+}
+
+void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex,
+                                            const UniqueFile& output_vdex,
+                                            const char* instruction_set,
+                                            const char* compiler_filter,
+                                            bool debuggable,
+                                            int target_sdk_version,
+                                            bool enable_hidden_api_checks,
+                                            bool generate_compact_dex,
+                                            const char* compilation_reason) {
+    // Disable cdex if update input vdex is true since this combination of options is not
+    // supported.
+    const bool disable_cdex = !generate_compact_dex || (input_vdex.fd() == output_vdex.fd());
+    if (disable_cdex) {
+        AddArg(kDisableCompactDexFlag);
+    }
+
+    // ISA related
+    {
+        AddArg(StringPrintf("--instruction-set=%s", instruction_set));
+
+        const std::string dex2oat_isa_features_key =
+                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+        std::string instruction_set_features_arg =
+                MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+        AddArg(instruction_set_features_arg);
+
+        const std::string dex2oat_isa_variant_key =
+                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+        std::string instruction_set_variant_arg =
+                MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+        AddArg(instruction_set_variant_arg);
+    }
+
+    // Compute compiler filter.
+    {
+        std::string dex2oat_compiler_filter_arg;
+        {
+            // If we are booting without the real /data, don't spend time compiling.
+            std::string vold_decrypt = GetProperty("vold.decrypt", "");
+            bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                    vold_decrypt == "1";
+
+            bool have_dex2oat_relocation_skip_flag = false;
+            if (skip_compilation) {
+                dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+                have_dex2oat_relocation_skip_flag = true;
+            } else if (compiler_filter != nullptr) {
+                dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s",
+                                                           compiler_filter);
+            }
+            if (have_dex2oat_relocation_skip_flag) {
+                AddRuntimeArg("-Xnorelocate");
+            }
+        }
+
+        if (dex2oat_compiler_filter_arg.empty()) {
+            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                           "--compiler-filter=%s");
+        }
+        AddArg(dex2oat_compiler_filter_arg);
+
+        if (compilation_reason != nullptr) {
+            AddArg(std::string("--compilation-reason=") + compilation_reason);
+        }
+    }
+
+    AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
+                            "--max-image-block-size=%s"));
+
+    AddArg(MapPropertyToArg("dalvik.vm.dex2oat-very-large",
+                            "--very-large-app-threshold=%s"));
+
+    std::string resolve_startup_string_arg = MapPropertyToArg(
+        "persist.device_config.runtime.dex2oat_resolve_startup_strings",
+        "--resolve-startup-const-strings=%s");
+    if (resolve_startup_string_arg.empty()) {
+        // If empty, fall back to system property.
+        resolve_startup_string_arg =
+                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                                 "--resolve-startup-const-strings=%s");
+    }
+    AddArg(resolve_startup_string_arg);
+
+    // Debug related
+    {
+        // Check whether all apps should be compiled debuggable.
+        if (!debuggable) {
+            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+        }
+        if (debuggable) {
+            AddArg("--debuggable");
+        }
+
+        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+        if (generate_debug_info) {
+            AddArg("--generate-debug-info");
+        }
+        {
+            bool generate_minidebug_info = kEnableMinidebugInfo &&
+                    GetBoolProperty(kMinidebugInfoSystemProperty,
+                                    kMinidebugInfoSystemPropertyDefault);
+            if (generate_minidebug_info) {
+                AddArg(kMinidebugDex2oatFlag);
+            }
+        }
+    }
+
+    if (target_sdk_version != 0) {
+        AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
+    }
+
+    if (enable_hidden_api_checks) {
+        AddRuntimeArg("-Xhidden-api-policy:enabled");
+    }
+}
+
+void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete,
+                                                          bool for_restore) {
+    // CPU set
+    {
+        std::string cpu_set_format = "--cpu-set=%s";
+        std::string dex2oat_cpu_set_arg = post_bootcomplete
+                ? (for_restore
+                   ? MapPropertyToArgWithBackup(
+                           "dalvik.vm.restore-dex2oat-cpu-set",
+                           "dalvik.vm.dex2oat-cpu-set",
+                           cpu_set_format)
+                   : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
+                : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
+        AddArg(dex2oat_cpu_set_arg);
+    }
+
+    // Number of threads
+    {
+        std::string threads_format = "-j%s";
+        std::string dex2oat_threads_arg = post_bootcomplete
+                ? (for_restore
+                   ? MapPropertyToArgWithBackup(
+                           "dalvik.vm.restore-dex2oat-threads",
+                           "dalvik.vm.dex2oat-threads",
+                           threads_format)
+                   : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
+                : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
+        AddArg(dex2oat_threads_arg);
+    }
+
+    AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s"));
+    AddRuntimeArg(MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s"));
+}
+
+void RunDex2Oat::Exec(int exit_code) {
+    execv_helper_->Exec(exit_code);
+}
+
+void RunDex2Oat::AddArg(const std::string& arg) {
+    execv_helper_->AddArg(arg);
+}
+
+void RunDex2Oat::AddRuntimeArg(const std::string& arg) {
+    execv_helper_->AddRuntimeArg(arg);
+}
+
+std::string RunDex2Oat::GetProperty(const std::string& key,
+                                    const std::string& default_value) {
+    return android::base::GetProperty(key, default_value);
+}
+
+bool RunDex2Oat::GetBoolProperty(const std::string& key, bool default_value) {
+    return android::base::GetBoolProperty(key, default_value);
+}
+
+std::string RunDex2Oat::MapPropertyToArg(const std::string& property,
+                                         const std::string& format,
+                                         const std::string& default_value) {
+    std::string prop = GetProperty(property, default_value);
+    if (!prop.empty()) {
+        return StringPrintf(format.c_str(), prop.c_str());
+    }
+    return "";
+}
+
+std::string RunDex2Oat::MapPropertyToArgWithBackup(
+        const std::string& property,
+        const std::string& backupProperty,
+        const std::string& format,
+        const std::string& default_value) {
+    std::string value = GetProperty(property, default_value);
+    if (!value.empty()) {
+        return StringPrintf(format.c_str(), value.c_str());
+    }
+    return MapPropertyToArg(backupProperty, format, default_value);
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h
new file mode 100644
index 0000000..325a3a2
--- /dev/null
+++ b/cmds/installd/run_dex2oat.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_RUN_DEX2OAT_H
+#define ANDROID_INSTALLD_RUN_DEX2OAT_H
+
+#include <memory>
+#include <string>
+
+#include "execv_helper.h"
+
+namespace android {
+namespace installd {
+
+class UniqueFile;
+
+class RunDex2Oat {
+  public:
+    explicit RunDex2Oat(const char* dex2oat_bin, ExecVHelper* execv_helper);
+    virtual ~RunDex2Oat();
+
+    void Initialize(const UniqueFile& output_oat,
+                    const UniqueFile& output_vdex,
+                    const UniqueFile& output_image,
+                    const UniqueFile& input_dex,
+                    const UniqueFile& input_vdex,
+                    const UniqueFile& dex_metadata,
+                    const UniqueFile& profile,
+                    const char* class_loader_context,
+                    const std::string& class_loader_context_fds,
+                    int swap_fd,
+                    const char* instruction_set,
+                    const char* compiler_filter,
+                    bool debuggable,
+                    bool post_bootcomplete,
+                    bool for_restore,
+                    int target_sdk_version,
+                    bool enable_hidden_api_checks,
+                    bool generate_compact_dex,
+                    bool use_jitzygote_image,
+                    const char* compilation_reason);
+
+    void Exec(int exit_code);
+
+  protected:
+    void PrepareBootImageAndBootClasspathFlags(bool use_jitzygote_image);
+    void PrepareInputFileFlags(const UniqueFile& output_oat,
+                               const UniqueFile& output_vdex,
+                               const UniqueFile& output_image,
+                               const UniqueFile& input_dex,
+                               const UniqueFile& input_vdex,
+                               const UniqueFile& dex_metadata,
+                               const UniqueFile& profile,
+                               int swap_fd,
+                               const char* class_loader_context,
+                               const std::string& class_loader_context_fds);
+    void PrepareCompilerConfigFlags(const UniqueFile& input_vdex,
+                                    const UniqueFile& output_vdex,
+                                    const char* instruction_set,
+                                    const char* compiler_filter,
+                                    bool debuggable,
+                                    int target_sdk_version,
+                                    bool enable_hidden_api_checks,
+                                    bool generate_compact_dex,
+                                    const char* compilation_reason);
+    void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore);
+
+    virtual std::string GetProperty(const std::string& key, const std::string& default_value);
+    virtual bool GetBoolProperty(const std::string& key, bool default_value);
+
+  private:
+    void AddArg(const std::string& arg);
+    void AddRuntimeArg(const std::string& arg);
+
+    std::string MapPropertyToArg(const std::string& property,
+                                 const std::string& format,
+                                 const std::string& default_value = "");
+
+    std::string MapPropertyToArgWithBackup(const std::string& property,
+                                           const std::string& backupProperty,
+                                           const std::string& format,
+                                           const std::string& default_value = "");
+
+    const std::string dex2oat_bin_;
+    ExecVHelper* execv_helper_;  // not owned
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_RUN_DEX2OAT_H
diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp
new file mode 100644
index 0000000..3813cf7
--- /dev/null
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -0,0 +1,585 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <android-base/logging.h>
+
+#include <gtest/gtest.h>
+
+#include "execv_helper.h"
+#include "run_dex2oat.h"
+#include "unique_file.h"
+
+namespace android {
+namespace installd {
+
+class RunDex2OatTest : public testing::Test {
+  public:
+    static constexpr const char* INPUT_PATH = "/dir/input/basename.apk";
+    static constexpr const char* OUTPUT_PATH = "/dir/output/basename.oat";
+    static constexpr const char* FLAG_UNUSED = "{{FLAG_UNUSED}}";
+
+    // UniqueFile closes FD. Avoid using standard I/O since the test is expected to print gtest
+    // results. Alternatively, mock out UniqueFile to avoid the side effect of close(2).
+    static constexpr int ZIP_FD = 3;
+    static constexpr int OAT_FD = 4;
+    static constexpr int INPUT_VDEX_FD = 5;
+    static constexpr int OUTPUT_VDEX_FD = 6;
+    static constexpr int IMAGE_FD = 7;
+    static constexpr int PROFILE_FD = 8;
+    static constexpr int DEX_METADATA_FD = 9;
+    static constexpr int SWAP_FD = 10;
+
+    using FakeSystemProperties = std::map<std::string, std::string>;
+
+    // A fake RunDex2Oat that allows to override (fake) system properties and starts with none.
+    class FakeRunDex2Oat : public RunDex2Oat {
+      private:
+        static constexpr const char* TRUE_STR = "true";
+        static constexpr const char* FALSE_STR = "false";
+
+      public:
+        FakeRunDex2Oat(ExecVHelper* execv_helper, FakeSystemProperties* properties)
+          : RunDex2Oat("/dir/bin/dex2oat", execv_helper), properties_(properties) { }
+
+        virtual ~FakeRunDex2Oat() {}
+
+        virtual std::string GetProperty(const std::string& key,
+                                        const std::string& default_value) override {
+            if (!properties_) {
+                return default_value;
+            }
+            auto iter = properties_->find(key);
+            if (iter == properties_->end()) {
+                return default_value;
+            }
+            return iter->second;
+        }
+
+        virtual bool GetBoolProperty(const std::string& key, bool default_value) override {
+            std::string value = GetProperty(key, "");
+            if (value == "") {
+                return default_value;
+            }
+            return value == TRUE_STR;
+        }
+
+      private:
+        FakeSystemProperties* properties_;
+    };
+
+    struct RunDex2OatArgs {
+        static std::unique_ptr<RunDex2OatArgs> MakeDefaultTestArgs() {
+            auto args = std::make_unique<RunDex2OatArgs>();
+            args->input_dex.reset(ZIP_FD, INPUT_PATH);
+            args->output_oat.reset(OAT_FD, OUTPUT_PATH);
+            args->input_vdex.reset(INPUT_VDEX_FD, "UNUSED_PATH");
+            args->output_vdex.reset(OUTPUT_VDEX_FD, "UNUSED_PATH");
+            args->instruction_set = "arm64";
+            args->compilation_reason = "rundex2oattest";
+            return args;
+        }
+
+        UniqueFile output_oat;
+        UniqueFile output_vdex;
+        UniqueFile output_image;
+        UniqueFile input_dex;
+        UniqueFile input_vdex;
+        UniqueFile dex_metadata;
+        UniqueFile profile;
+        int swap_fd = -1;
+        const char* instruction_set = nullptr;
+        const char* compiler_filter = "extract";
+        bool debuggable = false;
+        bool post_bootcomplete = false;
+        bool for_restore = false;
+        const char* class_loader_context = nullptr;
+        std::string class_loader_context_fds;
+        int target_sdk_version = 0;
+        bool enable_hidden_api_checks = false;
+        bool generate_compact_dex = true;
+        bool use_jitzygote_image = false;
+        const char* compilation_reason = nullptr;
+    };
+
+    class FakeExecVHelper : public ExecVHelper {
+      public:
+        bool HasArg(const std::string& arg) const {
+            auto end = argv_.end() - 1;  // To exclude the terminating nullptr
+            return find(argv_.begin(), end, arg) != end;
+        }
+
+        bool FlagNotUsed(const std::string& flag) const {
+            auto has_prefix = [flag](const char* arg) {
+                return strncmp(arg, flag.c_str(), flag.size()) == 0;
+            };
+            auto end = argv_.end() - 1;  // To exclude the terminating nullptr
+            return find_if(argv_.begin(), end, has_prefix) == end;
+        }
+
+        virtual void Exec(int exit_code) override {
+            std::string cmd;
+            for (auto arg : argv_) {
+                if (arg == nullptr) {
+                  continue;
+                }
+                cmd += arg;
+                cmd += " ";
+            }
+            LOG(DEBUG) << "FakeExecVHelper exit_code: " << exit_code << " cmd: " << cmd << "\n";
+        }
+    };
+
+    virtual void SetUp() override {
+        execv_helper_.reset(new FakeExecVHelper());
+        system_properties_.clear();
+        initializeDefaultExpectedFlags();
+    }
+
+    // Initializes the default flags expected to a run.  It currently matches to the expected flags
+    // with RunDex2OatArgs::MakeDefaultTestArgs.
+    //
+    // default_expected_flags_ defines a mapping of <flag_name, expected_value>, where flag_name is
+    // something like "--flag-name", and expected_value can be "=value" or ":value" (depending on
+    // its delimiter), "" (if no value is needed), or a special value of FLAG_UNUSED to indicates
+    // that it should not be used.
+    void initializeDefaultExpectedFlags() {
+        default_expected_flags_.clear();
+
+        // Files
+        default_expected_flags_["--zip-fd"] = "=" + std::to_string(ZIP_FD);
+        default_expected_flags_["--zip-location"] = "=basename.apk";
+        default_expected_flags_["--oat-fd"] = "=" + std::to_string(OAT_FD);
+        default_expected_flags_["--oat-location"] = "=" + std::string(OUTPUT_PATH);
+        default_expected_flags_["--input-vdex-fd"] = "=" + std::to_string(INPUT_VDEX_FD);
+        default_expected_flags_["--output-vdex-fd"] = "=" + std::to_string(OUTPUT_VDEX_FD);
+        default_expected_flags_["--classpath-dir"] = "=/dir/input";
+        default_expected_flags_["--app-image-fd"] = FLAG_UNUSED;
+        default_expected_flags_["--profile-file-fd"] = FLAG_UNUSED;
+        default_expected_flags_["--swap-fd"] = FLAG_UNUSED;
+        default_expected_flags_["--class-loader-context"] = FLAG_UNUSED;
+        default_expected_flags_["--class-loader-context-fds"] = FLAG_UNUSED;
+        default_expected_flags_["--updatable-bcp-packages-file"] =
+                "=/nonx/updatable-bcp-packages.txt";
+
+        // Arch
+        default_expected_flags_["--instruction-set"] = "=arm64";
+        default_expected_flags_["--instruction-set-features"] = FLAG_UNUSED;
+        default_expected_flags_["--instruction-set-variant"] = FLAG_UNUSED;
+        default_expected_flags_["--cpu-set"] = FLAG_UNUSED;
+
+        // Misc
+        default_expected_flags_["--compiler-filter"] = "=extract";
+        default_expected_flags_["--compilation-reason"] = "=rundex2oattest";
+        default_expected_flags_["--compact-dex-level"] = FLAG_UNUSED;
+        default_expected_flags_["-j"] = FLAG_UNUSED;
+        default_expected_flags_["--max-image-block-size"] = FLAG_UNUSED;
+        default_expected_flags_["--very-large-app-threshold"] = FLAG_UNUSED;
+        default_expected_flags_["--resolve-startup-const-strings"] = FLAG_UNUSED;
+
+        // Debug
+        default_expected_flags_["--debuggable"] = FLAG_UNUSED;
+        default_expected_flags_["--generate-debug-info"] = FLAG_UNUSED;
+        default_expected_flags_["--generate-mini-debug-info"] = FLAG_UNUSED;
+
+        // Runtime
+        // TODO(victorhsieh): Check if the previous flag is actually --runtime-arg.
+        default_expected_flags_["-Xms"] = FLAG_UNUSED;
+        default_expected_flags_["-Xmx"] = FLAG_UNUSED;
+        default_expected_flags_["-Xbootclasspath"] = FLAG_UNUSED;
+        default_expected_flags_["-Xtarget-sdk-version"] = FLAG_UNUSED;
+        default_expected_flags_["-Xhidden-api-policy"] = FLAG_UNUSED;
+        default_expected_flags_["-Xnorelocate"] = FLAG_UNUSED;
+
+        // Test only
+        default_expected_flags_["--foo"] = FLAG_UNUSED;
+        default_expected_flags_["--bar"] = FLAG_UNUSED;
+        default_expected_flags_["--baz"] = FLAG_UNUSED;
+    }
+
+    void SetExpectedFlagUsed(const std::string& flag, const std::string& value) {
+        auto iter = default_expected_flags_.find(flag);
+        ASSERT_NE(iter, default_expected_flags_.end()) << "Must define the default value";
+        iter->second = value;
+    }
+
+    void VerifyExpectedFlags() {
+        for (auto const& [flag, value] : default_expected_flags_) {
+            if (value == FLAG_UNUSED) {
+                EXPECT_TRUE(execv_helper_->FlagNotUsed(flag))
+                    << "Flag " << flag << " should be unused, but got the value " << value;
+            } else if (value == "") {
+                EXPECT_TRUE(execv_helper_->HasArg(flag))
+                    << "Flag " << flag << " should be specified without value, but got " << value;
+            } else {
+                EXPECT_TRUE(execv_helper_->HasArg(flag + value))
+                    << "Flag " << flag << value << " is not specificed";
+            }
+        }
+    }
+
+    void setSystemProperty(const std::string& key, const std::string& value) {
+        system_properties_[key] = value;
+    }
+
+    void CallRunDex2Oat(std::unique_ptr<RunDex2OatArgs> args) {
+        FakeRunDex2Oat runner(execv_helper_.get(), &system_properties_);
+        runner.Initialize(args->output_oat,
+                          args->output_vdex,
+                          args->output_image,
+                          args->input_dex,
+                          args->input_vdex,
+                          args->dex_metadata,
+                          args->profile,
+                          args->class_loader_context,
+                          args->class_loader_context_fds,
+                          args->swap_fd,
+                          args->instruction_set,
+                          args->compiler_filter,
+                          args->debuggable,
+                          args->post_bootcomplete,
+                          args->for_restore,
+                          args->target_sdk_version,
+                          args->enable_hidden_api_checks,
+                          args->generate_compact_dex,
+                          args->use_jitzygote_image,
+                          args->compilation_reason);
+        runner.Exec(/*exit_code=*/ 0);
+    }
+
+  private:
+    std::unique_ptr<FakeExecVHelper> execv_helper_;
+    std::map<std::string, std::string> default_expected_flags_;
+    FakeSystemProperties system_properties_;
+};
+
+TEST_F(RunDex2OatTest, BasicInputOutput) {
+    auto execv_helper = std::make_unique<FakeExecVHelper>();
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, WithAllOtherInputFds) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->output_image.reset(IMAGE_FD, "UNUSED_PATH");
+    args->profile.reset(PROFILE_FD, "UNUSED_PATH");
+    args->swap_fd = SWAP_FD;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--app-image-fd", "=" + std::to_string(IMAGE_FD));
+    SetExpectedFlagUsed("--profile-file-fd", "=" + std::to_string(PROFILE_FD));
+    SetExpectedFlagUsed("--swap-fd", "=" + std::to_string(SWAP_FD));
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, WithClassLoaderContext) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->class_loader_context = "CLASS_LOADER_CONTEXT";
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--class-loader-context", "=CLASS_LOADER_CONTEXT");
+    SetExpectedFlagUsed("--class-loader-context-fds", FLAG_UNUSED);
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, WithClassLoaderContextAndFds) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->class_loader_context = "CLASS_LOADER_CONTEXT";
+    args->class_loader_context_fds = "CLASS_LOADER_CONTEXT_FDS";
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--class-loader-context", "=CLASS_LOADER_CONTEXT");
+    SetExpectedFlagUsed("--class-loader-context-fds", "=CLASS_LOADER_CONTEXT_FDS");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, WithOnlyClassLoaderContextFds) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->class_loader_context_fds = "CLASS_LOADER_CONTEXT_FDS";
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--class-loader-context", FLAG_UNUSED);
+    SetExpectedFlagUsed("--class-loader-context-fds", FLAG_UNUSED);
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, DEX2OATBOOTCLASSPATH) {
+    ASSERT_EQ(nullptr, getenv("DEX2OATBOOTCLASSPATH"));
+    ASSERT_EQ(0, setenv("DEX2OATBOOTCLASSPATH", "foobar", /*override=*/ false))
+        << "Failed to setenv: " << strerror(errno);
+
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("-Xbootclasspath", ":foobar");
+    VerifyExpectedFlags();
+
+    ASSERT_EQ(0, unsetenv("DEX2OATBOOTCLASSPATH"))
+        << "Failed to setenv: " << strerror(errno);
+}
+
+TEST_F(RunDex2OatTest, UpdatableBootClassPath) {
+    setSystemProperty("dalvik.vm.dex2oat-updatable-bcp-packages-file", "/path/to/file");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--updatable-bcp-packages-file", "=/path/to/file");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, DoNotGenerateCompactDex) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->generate_compact_dex = false;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--compact-dex-level", "=none");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, DoNotGenerateCompactDexWithVdexInPlaceUpdate) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->generate_compact_dex = true;
+    args->input_vdex.reset(INPUT_VDEX_FD, "UNUSED_PATH");
+    args->output_vdex.reset(INPUT_VDEX_FD, "UNUSED_PATH");
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--compact-dex-level", "=none");
+    SetExpectedFlagUsed("--output-vdex-fd", "=" + std::to_string(INPUT_VDEX_FD));
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ISA) {
+    setSystemProperty("dalvik.vm.isa.x86.features", "a-x86-feature");
+    setSystemProperty("dalvik.vm.isa.x86.variant", "a-x86-variant");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->instruction_set = "x86";
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--instruction-set", "=x86");
+    SetExpectedFlagUsed("--instruction-set-features", "=a-x86-feature");
+    SetExpectedFlagUsed("--instruction-set-variant", "=a-x86-variant");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPreBootComplete) {
+    setSystemProperty("dalvik.vm.boot-dex2oat-cpu-set", "1,2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = false;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteNotForRestore) {
+    setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = false;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore) {
+    setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "1,2");
+    setSystemProperty("dalvik.vm.dex2oat-cpu-set", "2,3");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore_Backup) {
+    setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "");
+    setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--cpu-set", "=1,2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, Runtime) {
+    setSystemProperty("dalvik.vm.dex2oat-Xms", "1234m");
+    setSystemProperty("dalvik.vm.dex2oat-Xmx", "5678m");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->target_sdk_version = 30;
+    args->enable_hidden_api_checks = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-Xms", "1234m");
+    SetExpectedFlagUsed("-Xmx", "5678m");
+    SetExpectedFlagUsed("-Xtarget-sdk-version", ":30");
+    SetExpectedFlagUsed("-Xhidden-api-policy", ":enabled");
+    SetExpectedFlagUsed("-Xnorelocate", FLAG_UNUSED);
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, SkipRelocationInMinFramework) {
+    setSystemProperty("vold.decrypt", "trigger_restart_min_framework");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--compiler-filter", "=extract");
+    SetExpectedFlagUsed("-Xnorelocate", "");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, SkipRelocationIfDecryptedWithFullDiskEncryption) {
+    setSystemProperty("vold.decrypt", "1");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--compiler-filter", "=extract");
+    SetExpectedFlagUsed("-Xnorelocate", "");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, DalvikVmDex2oatFilter) {
+    setSystemProperty("dalvik.vm.dex2oat-filter", "speed");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->compiler_filter = nullptr;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--compiler-filter", "=speed");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ResolveStartupStartings) {
+    setSystemProperty("dalvik.vm.dex2oat-resolve-startup-strings", "false");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--resolve-startup-const-strings", "=false");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ResolveStartupStartingsOverride) {
+    setSystemProperty("dalvik.vm.dex2oat-resolve-startup-strings", "false");
+    setSystemProperty("persist.device_config.runtime.dex2oat_resolve_startup_strings", "true");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--resolve-startup-const-strings", "=true");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPreBootComplete) {
+    setSystemProperty("dalvik.vm.boot-dex2oat-threads", "2");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = false;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "2");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteNotForRestore) {
+    setSystemProperty("dalvik.vm.dex2oat-threads", "3");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = false;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "3");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore) {
+    setSystemProperty("dalvik.vm.restore-dex2oat-threads", "4");
+    setSystemProperty("dalvik.vm.dex2oat-threads", "5");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "4");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore_Backup) {
+    setSystemProperty("dalvik.vm.restore-dex2oat-threads", "");
+    setSystemProperty("dalvik.vm.dex2oat-threads", "5");
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->post_bootcomplete = true;
+    args->for_restore = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-j", "5");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, Debuggable) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->debuggable = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("--debuggable", "");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, AlwaysDebuggable) {
+    setSystemProperty("dalvik.vm.always_debuggable", "1");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--debuggable", "");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, GenerateDebugInfo) {
+    setSystemProperty("debug.generate-debug-info", "true");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--generate-debug-info", "");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, HiddenApiCheck) {
+    auto args = RunDex2OatArgs::MakeDefaultTestArgs();
+    args->enable_hidden_api_checks = true;
+    CallRunDex2Oat(std::move(args));
+
+    SetExpectedFlagUsed("-Xhidden-api-policy", ":enabled");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, Misc) {
+    setSystemProperty("dalvik.vm.dex2oat-max-image-block-size", "524288");
+    setSystemProperty("dalvik.vm.dex2oat-very-large", "100000");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--max-image-block-size", "=524288");
+    SetExpectedFlagUsed("--very-large-app-threshold", "=100000");
+    VerifyExpectedFlags();
+}
+
+TEST_F(RunDex2OatTest, ExtraFlags) {
+    setSystemProperty("dalvik.vm.dex2oat-flags", "--foo=123 --bar:456 --baz");
+    CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs());
+
+    SetExpectedFlagUsed("--foo", "=123");
+    SetExpectedFlagUsed("--bar", ":456");
+    SetExpectedFlagUsed("--baz", "");
+    VerifyExpectedFlags();
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/run_dex2oat_test.xml b/cmds/installd/run_dex2oat_test.xml
new file mode 100644
index 0000000..2467fe4
--- /dev/null
+++ b/cmds/installd/run_dex2oat_test.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Unittest of run_dex2oat">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <option name="null-device" value="true" />
+    <test class="com.android.tradefed.testtype.HostGTest" >
+        <option name="module-name" value="run_dex2oat_test" />
+    </test>
+</configuration>
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index bd45005..7c9e3b2 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -41,6 +41,21 @@
         "liblogwrap",
     ],
     test_config: "installd_cache_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
@@ -66,6 +81,21 @@
         "liblogwrap",
     ],
     test_config: "installd_service_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
@@ -93,6 +123,21 @@
         "libz",
     ],
     test_config: "installd_dexopt_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 5a5cb53..863cdfe 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -114,15 +114,14 @@
 class CacheTest : public testing::Test {
 protected:
     InstalldNativeService* service;
-    std::unique_ptr<std::string> testUuid;
+    std::optional<std::string> testUuid;
 
     virtual void SetUp() {
         setenv("ANDROID_LOG_TAGS", "*:v", 1);
         android::base::InitLogging(nullptr);
 
         service = new InstalldNativeService();
-        testUuid = std::make_unique<std::string>();
-        *testUuid = std::string(kTestUuid);
+        testUuid = kTestUuid;
         system("mkdir -p /data/local/tmp/user/0");
     }
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 16e4055..fbf1e0c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -193,7 +193,7 @@
     const uid_t kTestAppGid = multiuser_get_shared_gid(kTestUserId, kTestAppId);
 
     InstalldNativeService* service_;
-    std::unique_ptr<std::string> volume_uuid_;
+    std::optional<std::string> volume_uuid_;
     std::string package_name_;
     std::string apk_path_;
     std::string empty_dm_file_;
@@ -221,7 +221,7 @@
         ASSERT_TRUE(init_selinux());
         service_ = new InstalldNativeService();
 
-        volume_uuid_ = nullptr;
+        volume_uuid_ = std::nullopt;
         package_name_ = "com.installd.test.dexopt";
         se_info_ = "default";
         app_apk_dir_ = android_app_dir + package_name_;
@@ -294,7 +294,7 @@
         }
 
         // Create a secondary dex file on CE storage
-        const char* volume_uuid_cstr = volume_uuid_ == nullptr ? nullptr : volume_uuid_->c_str();
+        const char* volume_uuid_cstr = volume_uuid_ ? volume_uuid_->c_str() : nullptr;
         app_private_dir_ce_ = create_data_user_ce_package_path(
                 volume_uuid_cstr, kTestUserId, package_name_.c_str());
         secondary_dex_ce_ = app_private_dir_ce_ + "/secondary_ce.jar";
@@ -353,36 +353,32 @@
         if (class_loader_context == nullptr) {
             class_loader_context = "&";
         }
-        std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         int32_t dexopt_needed = 0;  // does not matter;
-        std::unique_ptr<std::string> out_path = nullptr;  // does not matter
+        std::optional<std::string> out_path; // does not matter
         int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
         std::string compiler_filter = "speed-profile";
-        std::unique_ptr<std::string> class_loader_context_ptr(
-                new std::string(class_loader_context));
-        std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         bool downgrade = false;
         int32_t target_sdk_version = 0;  // default
-        std::unique_ptr<std::string> profile_name_ptr = nullptr;
-        std::unique_ptr<std::string> dm_path_ptr = nullptr;
-        std::unique_ptr<std::string> compilation_reason_ptr = nullptr;
+        std::optional<std::string> profile_name;
+        std::optional<std::string> dm_path;
+        std::optional<std::string> compilation_reason;
 
         binder::Status result = service_->dexopt(path,
                                                  uid,
-                                                 package_name_ptr,
+                                                 package_name_,
                                                  kRuntimeIsa,
                                                  dexopt_needed,
                                                  out_path,
                                                  dex_flags,
                                                  compiler_filter,
                                                  volume_uuid_,
-                                                 class_loader_context_ptr,
-                                                 se_info_ptr,
+                                                 class_loader_context,
+                                                 se_info_,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr,
-                                                 dm_path_ptr,
-                                                 compilation_reason_ptr);
+                                                 profile_name,
+                                                 dm_path,
+                                                 compilation_reason);
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");
@@ -481,41 +477,35 @@
                            bool downgrade,
                            bool should_binder_call_succeed,
                            /*out */ binder::Status* binder_result) {
-        std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
-        std::unique_ptr<std::string> out_path(
-                oat_dir == nullptr ? nullptr : new std::string(oat_dir));
-        std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
-        std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
+        std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
+        std::string class_loader_context = "&";
         int32_t target_sdk_version = 0;  // default
-        std::unique_ptr<std::string> profile_name_ptr(new std::string("primary.prof"));
-        std::unique_ptr<std::string> dm_path_ptr = nullptr;
-        if (dm_path != nullptr) {
-            dm_path_ptr.reset(new std::string(dm_path));
-        }
-        std::unique_ptr<std::string> compilation_reason_ptr(new std::string("test-reason"));
+        std::string profile_name = "primary.prof";
+        std::optional<std::string> dm_path_opt = dm_path ? std::make_optional<std::string>(dm_path) : std::nullopt;
+        std::string compilation_reason = "test-reason";
 
         bool prof_result;
         ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
-                package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
-                dm_path_ptr, &prof_result));
+                package_name_, kTestUserId, kTestAppId, profile_name, apk_path_,
+                dm_path_opt, &prof_result));
         ASSERT_TRUE(prof_result);
 
         binder::Status result = service_->dexopt(apk_path_,
                                                  uid,
-                                                 package_name_ptr,
+                                                 package_name_,
                                                  kRuntimeIsa,
                                                  dexopt_needed,
                                                  out_path,
                                                  dex_flags,
                                                  compiler_filter,
                                                  volume_uuid_,
-                                                 class_loader_context_ptr,
-                                                 se_info_ptr,
+                                                 class_loader_context,
+                                                 se_info_,
                                                  downgrade,
                                                  target_sdk_version,
-                                                 profile_name_ptr,
-                                                 dm_path_ptr,
-                                                 compilation_reason_ptr);
+                                                 profile_name,
+                                                 dm_path_opt,
+                                                 compilation_reason);
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
 
         if (!should_binder_call_succeed) {
@@ -673,7 +663,7 @@
                           &status);
     EXPECT_STREQ(status.toString8().c_str(),
                  "Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
-                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
+                 "/data/app/com.installd.test.dexopt/base.jar failed: dex2oat error'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
@@ -992,7 +982,7 @@
         bool result;
         ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
-                /*dex_metadata*/ nullptr, &result));
+                /*dex_metadata*/ {}, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 0fb62ae..1e7559d 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -99,15 +99,14 @@
 class ServiceTest : public testing::Test {
 protected:
     InstalldNativeService* service;
-    std::unique_ptr<std::string> testUuid;
+    std::optional<std::string> testUuid;
 
     virtual void SetUp() {
         setenv("ANDROID_LOG_TAGS", "*:v", 1);
         android::base::InitLogging(nullptr);
 
         service = new InstalldNativeService();
-        testUuid = std::make_unique<std::string>();
-        *testUuid = std::string(kTestUuid);
+        testUuid = kTestUuid;
         system("mkdir -p /data/local/tmp/user/0");
 
         init_globals_from_data_and_root();
@@ -322,7 +321,7 @@
 
   // Request a snapshot of the CE content but not the DE content.
   int64_t ce_snapshot_inode;
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
   struct stat buf;
   memset(&buf, 0, sizeof(buf));
@@ -344,7 +343,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   // Request a snapshot of the DE content but not the CE content.
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
   // Only DE content snapshot was requested.
   ASSERT_EQ(ce_snapshot_inode, 0);
@@ -365,7 +364,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   // Request a snapshot of both the CE as well as the DE content.
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   ASSERT_TRUE(android::base::ReadFileToString(
@@ -407,10 +406,10 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   // Request snapshot for the package com.foo.
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
   // Now request snapshot with the same id for the package com.bar
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   // Check that both snapshots have correct data in them.
@@ -439,9 +438,9 @@
   ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
 
   int64_t ce_snapshot_inode;
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
   // No CE content snapshot was performed.
   ASSERT_EQ(ce_snapshot_inode, 0);
@@ -476,7 +475,7 @@
           "TEST_CONTENT_2_DE", fake_package_de_path + "/file2",
           0700, 10000, 20000, false /* follow_symlinks */));
 
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
 
   // Previous snapshot (with data for file1) must be cleared.
@@ -497,7 +496,7 @@
   ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
   ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
-  EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
+  EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_optional<std::string>("FOO"),
           "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
 }
 
@@ -524,7 +523,7 @@
   ASSERT_TRUE(android::base::WriteStringToFile(
           "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
-  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
   // The snapshot call must clear cache.
   struct stat sb;
@@ -558,7 +557,7 @@
           "TEST_CONTENT_DE", fake_package_de_path + "/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
 
-  ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
+  ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_optional<std::string>("TEST"),
           "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
 
   std::string ce_content, de_content;
@@ -584,7 +583,7 @@
 
   int64_t ce_snapshot_inode;
   // Request a snapshot of both the CE as well as the DE content.
-  ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+  ASSERT_TRUE(service->snapshotAppData(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
   // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
   ASSERT_NE(0, ce_snapshot_inode);
@@ -594,7 +593,7 @@
   ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 
 
-  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
           "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
   // Check snapshot is deleted.
   ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
@@ -615,7 +614,7 @@
           "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
           0700, 10000, 20000, false /* follow_symlinks */));
 
-  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 
   // Check snapshot is deleted.
@@ -624,7 +623,7 @@
   ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
 
   // Check that deleting already deleted snapshot is no-op.
-  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_optional<std::string>("TEST"),
           "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
 }
 
@@ -637,7 +636,7 @@
   ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
   ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
-  ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
+  ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_optional<std::string>("BAR"),
           "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
 }
 
@@ -669,7 +668,7 @@
           0700, 10000, 20000, false /* follow_symlinks */));
 
   ASSERT_TRUE(service->destroyCeSnapshotsNotSpecified(
-          std::make_unique<std::string>("TEST"), 0, { 1543, 77 }).isOk());
+          std::make_optional<std::string>("TEST"), 0, { 1543, 77 }).isOk());
 
   // Check only snapshots not specified are deleted.
   struct stat sb;
@@ -690,7 +689,7 @@
   ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
   ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
 
-  EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
+  EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_optional<std::string>("BAR"),
           "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
 }
 
diff --git a/cmds/installd/unique_file.cpp b/cmds/installd/unique_file.cpp
new file mode 100644
index 0000000..e99ce1e
--- /dev/null
+++ b/cmds/installd/unique_file.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unique_file.h"
+
+#include <string>
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace installd {
+
+UniqueFile::UniqueFile() : UniqueFile(-1, "") {}
+
+UniqueFile::UniqueFile(int value, std::string path) : UniqueFile(value, path, nullptr) {}
+
+UniqueFile::UniqueFile(int value, std::string path, CleanUpFunction cleanup)
+        : value_(value), path_(path), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+UniqueFile::UniqueFile(UniqueFile&& other) {
+    *this = std::move(other);
+}
+
+UniqueFile::~UniqueFile() {
+    reset();
+}
+
+UniqueFile& UniqueFile::operator=(UniqueFile&& other) {
+    value_ = other.value_;
+    path_ = other.path_;
+    cleanup_ = other.cleanup_;
+    do_cleanup_ = other.do_cleanup_;
+    auto_close_ = other.auto_close_;
+    other.release();
+    return *this;
+}
+
+void UniqueFile::reset() {
+    reset(-1, "");
+}
+
+void UniqueFile::reset(int new_value, std::string path, CleanUpFunction new_cleanup) {
+    if (auto_close_ && value_ >= 0) {
+        if (close(value_) < 0) {
+            PLOG(ERROR) << "Failed to close fd " << value_ << ", with path " << path;
+        }
+    }
+    if (do_cleanup_ && cleanup_ != nullptr) {
+        cleanup_(path_);
+    }
+
+    value_ = new_value;
+    path_ = path;
+    cleanup_ = new_cleanup;
+}
+
+void UniqueFile::release() {
+    value_ = -1;
+    path_ = "";
+    do_cleanup_ = false;
+    cleanup_ = nullptr;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/unique_file.h b/cmds/installd/unique_file.h
new file mode 100644
index 0000000..e85e23b
--- /dev/null
+++ b/cmds/installd/unique_file.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_UNIQUE_FILE_H
+#define ANDROID_INSTALLD_UNIQUE_FILE_H
+
+#include <functional>
+#include <string>
+
+namespace android {
+namespace installd {
+
+// A file management helper that serves two purposes:
+//
+// 1. Closes the file description on destruction, similar unique_fd.
+// 2. Runs a cleanup function on after close, if not cancelled.
+//
+// The class does not assume the relationship between the given fd and file path.
+//
+// Example:
+//
+//   UniqueFile file(open(...),
+//                           filepath,
+//                           [](const std::string& path) {
+//                               unlink(path.c_str());
+//                           });
+//   if (file.fd() == -1) {
+//       // Error opening...
+//   }
+//
+//   ...
+//   if (error) {
+//       // At this point, when the UniqueFile is destructed, the cleanup function will run
+//       // (e.g. to delete the file) after the fd is closed.
+//       return -1;
+//   }
+//
+//   (Success case)
+//   file.DisableCleanup();
+//   // At this point, when the UniqueFile is destructed, the cleanup function will not run
+//   // (e.g. leaving the file around) after the fd is closed.
+//
+class UniqueFile {
+ private:
+    using CleanUpFunction = std::function<void (const std::string&)>;
+
+ public:
+    UniqueFile();
+    UniqueFile(int value, std::string path);
+    UniqueFile(int value, std::string path, CleanUpFunction cleanup);
+    UniqueFile(UniqueFile&& other);
+    ~UniqueFile();
+
+    UniqueFile& operator=(UniqueFile&& other);
+
+    int fd() const {
+        return value_;
+    }
+
+    const std::string& path() const {
+      return path_;
+    }
+
+    void DisableAutoClose() {
+        auto_close_ = false;
+    }
+
+    void DisableCleanup() {
+        do_cleanup_ = false;
+    }
+
+    void reset();
+    void reset(int new_value, std::string path, CleanUpFunction new_cleanup = nullptr);
+
+ private:
+    void release();
+
+    int value_;
+    std::string path_;
+    CleanUpFunction cleanup_;
+    bool do_cleanup_;
+    bool auto_close_;
+};
+
+}  // namespace installd
+}  // namespace android
+
+#endif  // ANDROID_INSTALLD_UNIQUE_FILE_H
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 5afae4b..0cbb80f 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -16,6 +16,7 @@
     name: "liblshal",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -47,6 +48,7 @@
     name: "lshal_defaults",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -72,15 +74,18 @@
 cc_test {
     name: "lshal_test",
     test_suites: ["device-tests"],
-    defaults: ["lshal_defaults"],
+    defaults: [
+        "libvintf_static_user_defaults",
+        "lshal_defaults"
+    ],
     gtest: true,
     static_libs: [
-        "android.hardware.tests.baz@1.0",
+        "android.hardware.tests.inheritance@1.0",
         "libgmock",
+        "libvintf",
     ],
     shared_libs: [
         "libhidlbase",
-        "libvintf",
     ],
     srcs: [
         "test.cpp"
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index af22ac9..72958bd 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -39,7 +39,7 @@
     // Optargs cannnot be used because the flag should not be considered set
     // if it should really be contained in mOptions.
     if (std::string(arg.argv[optind]) == "-E") {
-        mExcludesParentInstances = true;
+        mParentDebugInfoLevel = ParentDebugInfoLevel::NOTHING;
         optind++;
     }
 
@@ -67,7 +67,7 @@
 
     return mLshal.emitDebugInfo(
             pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
-            mExcludesParentInstances,
+            mParentDebugInfoLevel,
             mLshal.out().buf(),
             mLshal.err());
 }
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index cd57e31..317cc28 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -21,6 +21,7 @@
 #include <android-base/macros.h>
 
 #include "Command.h"
+#include "ParentDebugInfoLevel.h"
 #include "utils.h"
 
 namespace android {
@@ -42,9 +43,8 @@
     std::string mInterfaceName;
     std::vector<std::string> mOptions;
 
-    // Outputs the actual descriptor of a hal instead of the debug output
-    // if the arguments provided are a superclass of the actual hal impl.
-    bool mExcludesParentInstances;
+    // See comment on ParentDebugInfoLevel.
+    ParentDebugInfoLevel mParentDebugInfoLevel = ParentDebugInfoLevel::FULL;
 
     DISALLOW_COPY_AND_ASSIGN(DebugCommand);
 };
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index fb11cee..22268ac 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -29,7 +29,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
 #include <hidl-util/FQName.h>
@@ -203,97 +202,14 @@
             lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
 }
 
-static bool scanBinderContext(pid_t pid,
-        const std::string &contextName,
-        std::function<void(const std::string&)> eachLine) {
-    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
-    if (!ifs.is_open()) {
-        ifs.open("/d/binder/proc/" + std::to_string(pid));
-        if (!ifs.is_open()) {
-            return false;
-        }
-    }
-
-    static const std::regex kContextLine("^context (\\w+)$");
-
-    bool isDesiredContext = false;
-    std::string line;
-    std::smatch match;
-    while(getline(ifs, line)) {
-        if (std::regex_search(line, match, kContextLine)) {
-            isDesiredContext = match.str(1) == contextName;
-            continue;
-        }
-
-        if (!isDesiredContext) {
-            continue;
-        }
-
-        eachLine(line);
-    }
-    return true;
-}
-
 bool ListCommand::getPidInfo(
-        pid_t serverPid, PidInfo *pidInfo) const {
-    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
-    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
-
-    std::smatch match;
-    return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
-        if (std::regex_search(line, match, kReferencePrefix)) {
-            const std::string &ptrString = "0x" + match.str(2); // use number after c
-            uint64_t ptr;
-            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
-                // Should not reach here, but just be tolerant.
-                err() << "Could not parse number " << ptrString << std::endl;
-                return;
-            }
-            const std::string proc = " proc ";
-            auto pos = line.rfind(proc);
-            if (pos != std::string::npos) {
-                for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
-                    int32_t pid;
-                    if (!::android::base::ParseInt(pidStr, &pid)) {
-                        err() << "Could not parse number " << pidStr << std::endl;
-                        return;
-                    }
-                    pidInfo->refPids[ptr].push_back(pid);
-                }
-            }
-
-            return;
-        }
-
-        if (std::regex_search(line, match, kThreadPrefix)) {
-            // "1" is waiting in binder driver
-            // "2" is poll. It's impossible to tell if these are in use.
-            //     and HIDL default code doesn't use it.
-            bool isInUse = match.str(1) != "1";
-            // "0" is a thread that has called into binder
-            // "1" is looper thread
-            // "2" is main looper thread
-            bool isHwbinderThread = match.str(2) != "0";
-
-            if (!isHwbinderThread) {
-                return;
-            }
-
-            if (isInUse) {
-                pidInfo->threadUsage++;
-            }
-
-            pidInfo->threadCount++;
-            return;
-        }
-
-        // not reference or thread line
-        return;
-    });
+        pid_t serverPid, BinderPidInfo *pidInfo) const {
+    const auto& status = getBinderPidInfo(BinderDebugContext::HWBINDER, serverPid, pidInfo);
+    return status == OK;
 }
 
-const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
-    auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+const BinderPidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+    auto pair = mCachedPidInfos.insert({serverPid, BinderPidInfo{}});
     if (pair.second /* did insertion take place? */) {
         if (!getPidInfo(serverPid, &pair.first->second)) {
             return nullptr;
@@ -555,7 +471,7 @@
                 std::stringstream ss;
                 auto pair = splitFirst(iName, '/');
                 mLshal.emitDebugInfo(pair.first, pair.second, {},
-                                     false /* excludesParentInstances */, ss,
+                                     ParentDebugInfoLevel::FQNAME_ONLY, ss,
                                      NullableOStream<std::ostream>(nullptr));
                 return ss.str();
             };
@@ -727,7 +643,7 @@
         entry->arch = fromBaseArchitecture(debugInfo.arch);
 
         if (debugInfo.pid != NO_PID) {
-            const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+            const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
             if (pidInfo == nullptr) {
                 handleError(IO_ERROR,
                             "no information for PID " + std::to_string(debugInfo.pid) +
@@ -916,6 +832,18 @@
     }
 }
 
+// Get all values of enum type T, assuming the first value is 0 and the last value is T::LAST.
+// T::LAST is not included in the returned list.
+template <typename T>
+std::vector<T> GetAllValues() {
+    using BaseType = std::underlying_type_t<T>;
+    std::vector<T> ret;
+    for (BaseType i = 0; i < static_cast<BaseType>(T::LAST); ++i) {
+        ret.push_back(static_cast<T>(i));
+    }
+    return ret;
+}
+
 void ListCommand::registerAllOptions() {
     int v = mOptions.size();
     // A list of acceptable command line options
@@ -989,6 +917,15 @@
        "    - declared: only declared in VINTF manifest but is not registered to hwservicemanager;\n"
        "    - N/A: no information for passthrough HALs."});
 
+    mOptions.push_back({'A', "all", no_argument, v++,
+                        [](ListCommand* thiz, const char*) {
+                            auto allColumns = GetAllValues<TableColumnType>();
+                            thiz->mSelectedColumns.insert(thiz->mSelectedColumns.end(),
+                                                          allColumns.begin(), allColumns.end());
+                            return OK;
+                        },
+                        "print all columns"});
+
     // long options without short alternatives
     mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
         thiz->mVintf = true;
@@ -1019,46 +956,55 @@
         thiz->mNeat = true;
         return OK;
     }, "output is machine parsable (no explanatory text).\nCannot be used with --debug."});
-    mOptions.push_back({'\0', "types", required_argument, v++, [](ListCommand* thiz, const char* arg) {
-        if (!arg) { return USAGE; }
+    mOptions.push_back(
+            {'\0', "types", required_argument, v++,
+             [](ListCommand* thiz, const char* arg) {
+                 if (!arg) {
+                     return USAGE;
+                 }
 
-        static const std::map<std::string, HalType> kHalTypeMap {
-            {"binderized", HalType::BINDERIZED_SERVICES},
-            {"b", HalType::BINDERIZED_SERVICES},
-            {"passthrough_clients", HalType::PASSTHROUGH_CLIENTS},
-            {"c", HalType::PASSTHROUGH_CLIENTS},
-            {"passthrough_libs", HalType::PASSTHROUGH_LIBRARIES},
-            {"l", HalType::PASSTHROUGH_LIBRARIES},
-            {"vintf", HalType::VINTF_MANIFEST},
-            {"v", HalType::VINTF_MANIFEST},
-            {"lazy", HalType::LAZY_HALS},
-            {"z", HalType::LAZY_HALS},
-        };
+                 static const std::map<std::string, std::vector<HalType>> kHalTypeMap{
+                         {"binderized", {HalType::BINDERIZED_SERVICES}},
+                         {"b", {HalType::BINDERIZED_SERVICES}},
+                         {"passthrough_clients", {HalType::PASSTHROUGH_CLIENTS}},
+                         {"c", {HalType::PASSTHROUGH_CLIENTS}},
+                         {"passthrough_libs", {HalType::PASSTHROUGH_LIBRARIES}},
+                         {"l", {HalType::PASSTHROUGH_LIBRARIES}},
+                         {"vintf", {HalType::VINTF_MANIFEST}},
+                         {"v", {HalType::VINTF_MANIFEST}},
+                         {"lazy", {HalType::LAZY_HALS}},
+                         {"z", {HalType::LAZY_HALS}},
+                         {"all", GetAllValues<HalType>()},
+                         {"a", GetAllValues<HalType>()},
+                 };
 
-        std::vector<std::string> halTypesArgs = split(std::string(arg), ',');
-        for (const auto& halTypeArg : halTypesArgs) {
-            if (halTypeArg.empty()) continue;
+                 std::vector<std::string> halTypesArgs = split(std::string(arg), ',');
+                 for (const auto& halTypeArg : halTypesArgs) {
+                     if (halTypeArg.empty()) continue;
 
-            const auto& halTypeIter = kHalTypeMap.find(halTypeArg);
-            if (halTypeIter == kHalTypeMap.end()) {
+                     const auto& halTypeIter = kHalTypeMap.find(halTypeArg);
+                     if (halTypeIter == kHalTypeMap.end()) {
+                         thiz->err() << "Unrecognized HAL type: " << halTypeArg << std::endl;
+                         return USAGE;
+                     }
 
-                thiz->err() << "Unrecognized HAL type: " << halTypeArg << std::endl;
-                return USAGE;
-            }
+                     // Append unique (non-repeated) HAL types to the reporting list
+                     for (auto halType : halTypeIter->second) {
+                         if (std::find(thiz->mListTypes.begin(), thiz->mListTypes.end(), halType) ==
+                             thiz->mListTypes.end()) {
+                             thiz->mListTypes.push_back(halType);
+                         }
+                     }
+                 }
 
-            // Append unique (non-repeated) HAL types to the reporting list
-            HalType halType = halTypeIter->second;
-            if (std::find(thiz->mListTypes.begin(), thiz->mListTypes.end(), halType) ==
-                thiz->mListTypes.end()) {
-                thiz->mListTypes.push_back(halType);
-            }
-        }
-
-        if (thiz->mListTypes.empty()) { return USAGE; }
-        return OK;
-    }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
-       "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
-       "passthrough_libs), (v|vintf), and (z|lazy).\nDefault is `bcl`."});
+                 if (thiz->mListTypes.empty()) {
+                     return USAGE;
+                 }
+                 return OK;
+             },
+             "comma-separated list of one or more sections.\nThe output is restricted to the "
+             "selected section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
+             "passthrough_libs), (v|vintf), (z|lazy), and (a|all).\nDefault is `b,c,l`."});
 }
 
 // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index acc0dcf..561f9cb 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -25,6 +25,7 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binderdebug/BinderDebug.h>
 #include <hidl-util/FqInstance.h>
 #include <vintf/HalManifest.h>
 #include <vintf/VintfObject.h>
@@ -40,18 +41,15 @@
 
 class Lshal;
 
-struct PidInfo {
-    std::map<uint64_t, Pids> refPids; // pids that are referenced
-    uint32_t threadUsage; // number of threads in use
-    uint32_t threadCount; // number of threads total
-};
-
 enum class HalType {
     BINDERIZED_SERVICES = 0,
     PASSTHROUGH_CLIENTS,
     PASSTHROUGH_LIBRARIES,
     VINTF_MANIFEST,
     LAZY_HALS,
+
+    // Not a real HalType. Used to determine all HalTypes.
+    LAST,
 };
 
 class ListCommand : public Command {
@@ -107,9 +105,9 @@
     // Get relevant information for a PID by parsing files under
     // /dev/binderfs/binder_logs or /d/binder.
     // It is a virtual member function so that it can be mocked.
-    virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+    virtual bool getPidInfo(pid_t serverPid, BinderPidInfo *info) const;
     // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
-    const PidInfo* getPidInfoCached(pid_t serverPid);
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid);
 
     void dumpTable(const NullableOStream<std::ostream>& out) const;
     void dumpVintf(const NullableOStream<std::ostream>& out) const;
@@ -188,7 +186,7 @@
     std::map<pid_t, std::string> mCmdlines;
 
     // Cache for getPidInfo.
-    std::map<pid_t, PidInfo> mCachedPidInfos;
+    std::map<pid_t, BinderPidInfo> mCachedPidInfos;
 
     // Cache for getPartition.
     std::map<pid_t, Partition> mPartitions;
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 132b31e..99cb93a 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -101,7 +101,7 @@
         const std::string &interfaceName,
         const std::string &instanceName,
         const std::vector<std::string> &options,
-        bool excludesParentInstances,
+        ParentDebugInfoLevel parentDebugInfoLevel,
         std::ostream &out,
         NullableOStream<std::ostream> err) const {
     using android::hidl::base::V1_0::IBase;
@@ -126,7 +126,7 @@
         return NO_INTERFACE;
     }
 
-    if (excludesParentInstances) {
+    if (parentDebugInfoLevel != ParentDebugInfoLevel::FULL) {
         const std::string descriptor = getDescriptor(base.get());
         if (descriptor.empty()) {
             std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed";
@@ -134,11 +134,14 @@
             LOG(ERROR) << msg;
         }
         if (descriptor != interfaceName) {
+            if (parentDebugInfoLevel == ParentDebugInfoLevel::FQNAME_ONLY) {
+                out << "[See " << descriptor << "/" << instanceName << "]";
+            }
             return OK;
         }
     }
 
-    PipeRelay relay(out);
+    PipeRelay relay(out, err, interfaceName, instanceName);
 
     if (relay.initCheck() != OK) {
         std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 830bd87..50279d4 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -25,6 +25,7 @@
 
 #include "Command.h"
 #include "NullableOStream.h"
+#include "ParentDebugInfoLevel.h"
 #include "utils.h"
 
 namespace android {
@@ -49,7 +50,7 @@
             const std::string &interfaceName,
             const std::string &instanceName,
             const std::vector<std::string> &options,
-            bool excludesParentInstances,
+            ParentDebugInfoLevel parentDebugInfoLevel,
             std::ostream &out,
             NullableOStream<std::ostream> err) const;
 
diff --git a/cmds/lshal/ParentDebugInfoLevel.h b/cmds/lshal/ParentDebugInfoLevel.h
new file mode 100644
index 0000000..12ac9c8
--- /dev/null
+++ b/cmds/lshal/ParentDebugInfoLevel.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+namespace android {
+namespace lshal {
+
+// Describe verbosity when dumping debug information on a HAL service by
+// referring to a parent HAL interface FQName (for example, when dumping debug information
+// on foo@1.0::IFoo but the HAL implementation is foo@1.1::IFoo).
+enum class ParentDebugInfoLevel {
+    // Write nothing.
+    NOTHING,
+    // Write a short description that includes the FQName of the real implementation.
+    FQNAME_ONLY,
+    // Write full debug info.
+    FULL,
+};
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 820679f..4e97636 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -23,7 +23,6 @@
 
 #include <atomic>
 
-#include <android-base/logging.h>
 #include <utils/Thread.h>
 
 namespace android {
@@ -31,8 +30,15 @@
 
 static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
 
+static std::string getThreadName(std::string interfaceName, const std::string &instanceName) {
+    auto dot = interfaceName.rfind(".");
+    if (dot != std::string::npos) interfaceName = interfaceName.substr(dot + 1);
+    return "RelayThread_" + interfaceName + "_" + instanceName;
+}
+
 struct PipeRelay::RelayThread : public Thread {
-    explicit RelayThread(int fd, std::ostream &os);
+    explicit RelayThread(int fd, std::ostream &os, const NullableOStream<std::ostream> &err,
+                         const std::string &fqName);
 
     bool threadLoop() override;
     void setFinished();
@@ -40,6 +46,7 @@
 private:
     int mFd;
     std::ostream &mOutStream;
+    NullableOStream<std::ostream> mErrStream;
 
     // If we were to use requestExit() and exitPending() instead, threadLoop()
     // may not run at all by the time ~PipeRelay is called (i.e. debug() has
@@ -47,13 +54,17 @@
     // read() are executed until data are drained.
     std::atomic_bool mFinished;
 
+    std::string mFqName;
+
     DISALLOW_COPY_AND_ASSIGN(RelayThread);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
-PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
-      : mFd(fd), mOutStream(os), mFinished(false) {}
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os,
+                                    const NullableOStream<std::ostream> &err,
+                                    const std::string &fqName)
+      : mFd(fd), mOutStream(os), mErrStream(err), mFinished(false), mFqName(fqName) {}
 
 bool PipeRelay::RelayThread::threadLoop() {
     char buffer[1024];
@@ -66,13 +77,14 @@
 
     int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
     if (res < 0) {
-        PLOG(INFO) << "select() failed";
+        mErrStream << "debug " << mFqName << ": select() failed";
         return false;
     }
 
     if (res == 0 || !FD_ISSET(mFd, &set)) {
         if (mFinished) {
-            LOG(WARNING) << "debug: timeout reading from pipe, output may be truncated.";
+            mErrStream << "debug " << mFqName
+                       << ": timeout reading from pipe, output may be truncated.";
             return false;
         }
         // timeout, but debug() has not returned, so wait for HAL to finish.
@@ -83,7 +95,7 @@
     ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
 
     if (n < 0) {
-        PLOG(ERROR) << "read() failed";
+        mErrStream << "debug " << mFqName << ": read() failed";
     }
 
     if (n <= 0) {
@@ -101,8 +113,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-PipeRelay::PipeRelay(std::ostream &os)
-    : mInitCheck(NO_INIT) {
+PipeRelay::PipeRelay(std::ostream &os, const NullableOStream<std::ostream> &err,
+                     const std::string &interfaceName, const std::string &instanceName)
+      : mInitCheck(NO_INIT) {
     int res = pipe(mFds);
 
     if (res < 0) {
@@ -110,8 +123,8 @@
         return;
     }
 
-    mThread = new RelayThread(mFds[0], os);
-    mInitCheck = mThread->run("RelayThread");
+    mThread = new RelayThread(mFds[0], os, err, interfaceName + "/" + instanceName);
+    mInitCheck = mThread->run(getThreadName(interfaceName, instanceName).c_str());
 }
 
 void PipeRelay::CloseFd(int *fd) {
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index 835016041..bd994b4 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -21,6 +21,8 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+#include "NullableOStream.h"
+
 namespace android {
 namespace lshal {
 
@@ -28,7 +30,10 @@
  * written to the "write"-end of the pair to the specified output stream "os".
  */
 struct PipeRelay {
-    explicit PipeRelay(std::ostream &os);
+    explicit PipeRelay(std::ostream& os,
+                       const NullableOStream<std::ostream>& err,
+                       const std::string& interfaceName,
+                       const std::string& instanceName);
     ~PipeRelay();
 
     status_t initCheck() const;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 0ff0c96d..476aa04 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -32,22 +32,28 @@
 namespace lshal {
 
 using android::procpartition::Partition;
-using Pids = std::vector<int32_t>;
+using Pids = std::vector<pid_t>;
 
 enum class TableColumnType : unsigned int {
-    INTERFACE_NAME,
+    INTERFACE_NAME = 0,
     TRANSPORT,
     SERVER_PID,
-    SERVER_CMD,
     SERVER_ADDR,
-    CLIENT_PIDS,
-    CLIENT_CMDS,
     ARCH,
     THREADS,
     RELEASED,
     HASH,
     VINTF,
     SERVICE_STATUS,
+    CLIENT_PIDS,
+
+    // Not a real TableColumnType. Used to determine all TableColumnTypes.
+    LAST,
+
+    // Not included in all TableColumnTypes because they replace *PID(S) when the
+    // --cmdline option is set.
+    SERVER_CMD,
+    CLIENT_CMDS,
 };
 
 enum : unsigned int {
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 3d550ba..b6ff28d 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -24,7 +24,7 @@
 
 #include <gtest/gtest.h>
 #include <gmock/gmock.h>
-#include <android/hardware/tests/baz/1.0/IQuux.h>
+#include <android/hardware/tests/inheritance/1.0/IChild.h>
 #include <hidl/HidlTransportSupport.h>
 #include <vintf/parse_xml.h>
 
@@ -44,6 +44,7 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::Void;
 using android::vintf::Arch;
 using android::vintf::CompatibilityMatrix;
 using android::vintf::gCompatibilityMatrixConverter;
@@ -59,10 +60,14 @@
 namespace android {
 namespace hardware {
 namespace tests {
-namespace baz {
+namespace inheritance {
 namespace V1_0 {
 namespace implementation {
-struct Quux : android::hardware::tests::baz::V1_0::IQuux {
+struct Child : android::hardware::tests::inheritance::V1_0::IChild {
+    ::android::hardware::Return<void> doChild() override { return Void(); }
+    ::android::hardware::Return<void> doParent() override { return Void(); }
+    ::android::hardware::Return<void> doGrandparent() override { return Void(); }
+
     ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
         const native_handle_t *handle = hh.getNativeHandle();
         if (handle->numFds < 1) {
@@ -76,7 +81,7 @@
         }
         ssize_t written = write(fd, content.c_str(), content.size());
         if (written != (ssize_t)content.size()) {
-            LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
+            LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
                     << content.size() << " bytes, errno = " << errno;
         }
         return Void();
@@ -85,7 +90,7 @@
 
 } // namespace implementation
 } // namespace V1_0
-} // namespace baz
+} // namespace inheritance
 } // namespace tests
 } // namespace hardware
 
@@ -124,18 +129,24 @@
 class DebugTest : public ::testing::Test {
 public:
     void SetUp() override {
-        using ::android::hardware::tests::baz::V1_0::IQuux;
-        using ::android::hardware::tests::baz::V1_0::implementation::Quux;
+        using ::android::hardware::tests::inheritance::V1_0::IChild;
+        using ::android::hardware::tests::inheritance::V1_0::IParent;
+        using ::android::hardware::tests::inheritance::V1_0::IGrandparent;
+        using ::android::hardware::tests::inheritance::V1_0::implementation::Child;
 
         err.str("");
         out.str("");
         serviceManager = new testing::NiceMock<MockServiceManager>();
-        ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
-            [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
-                if (iface == IQuux::descriptor && inst == "default")
-                    return new Quux();
-                return nullptr;
-            }));
+        ON_CALL(*serviceManager, get(_, _))
+                .WillByDefault(
+                        Invoke([](const auto& iface,
+                                  const auto& inst) -> ::android::hardware::Return<sp<IBase>> {
+                            if (inst != "default") return nullptr;
+                            if (iface == IChild::descriptor || iface == IParent::descriptor ||
+                                iface == IGrandparent::descriptor)
+                                return new Child();
+                            return nullptr;
+                        }));
 
         lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
     }
@@ -159,17 +170,17 @@
 
 TEST_F(DebugTest, Debug) {
     EXPECT_EQ(0u, callMain(lshal, {
-        "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
+        "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "foo", "bar"
     }));
-    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
+    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nfoo\nbar"));
     EXPECT_THAT(err.str(), IsEmpty());
 }
 
 TEST_F(DebugTest, Debug2) {
     EXPECT_EQ(0u, callMain(lshal, {
-        "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
+        "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild", "baz", "quux"
     }));
-    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
+    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\nbaz\nquux"));
     EXPECT_THAT(err.str(), IsEmpty());
 }
 
@@ -180,6 +191,22 @@
     EXPECT_THAT(err.str(), HasSubstr("does not exist"));
 }
 
+TEST_F(DebugTest, DebugParent) {
+    EXPECT_EQ(0u, callMain(lshal, {
+        "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
+    }));
+    EXPECT_THAT(out.str(), StrEq("android.hardware.tests.inheritance@1.0::IChild\ncalling parent"));
+    EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(DebugTest, DebugParentExclude) {
+    EXPECT_EQ(0u, callMain(lshal, {
+        "lshal", "debug", "-E", "android.hardware.tests.inheritance@1.0::IParent", "excluding"
+    }));
+    EXPECT_THAT(out.str(), IsEmpty());
+    EXPECT_THAT(err.str(), IsEmpty());
+}
+
 class MockLshal : public Lshal {
 public:
     MockLshal() {}
@@ -206,12 +233,12 @@
         return ListCommand::dumpVintf(out);
     }
     void internalPostprocess() { ListCommand::postprocess(); }
-    const PidInfo* getPidInfoCached(pid_t serverPid) {
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
         return ListCommand::getPidInfoCached(serverPid);
     }
 
     MOCK_METHOD0(postprocess, void());
-    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
+    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
     MOCK_METHOD1(getPartition, Partition(pid_t));
 
@@ -272,8 +299,8 @@
 static std::vector<pid_t> getClients(pid_t serverId) {
     return {serverId + 1, serverId + 3};
 }
-static PidInfo getPidInfoFromId(pid_t serverId) {
-    PidInfo info;
+static BinderPidInfo getPidInfoFromId(pid_t serverId) {
+    BinderPidInfo info;
     info.refPids[getPtr(serverId)] = getClients(serverId);
     info.threadUsage = 10 + serverId;
     info.threadCount = 20 + serverId;
@@ -336,7 +363,7 @@
     void initMockList() {
         mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
         ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
-            [](pid_t serverPid, PidInfo* info) {
+            [](pid_t serverPid, BinderPidInfo* info) {
                 *info = getPidInfoFromId(serverPid);
                 return true;
             }));
@@ -452,8 +479,7 @@
 }
 
 TEST_F(ListTest, DumpVintf) {
-    const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n"
-                                 "    <hal format=\"hidl\">\n"
+    const std::string expected = "    <hal format=\"hidl\">\n"
                                  "        <name>a.h.foo1</name>\n"
                                  "        <transport>hwbinder</transport>\n"
                                  "        <fqname>@1.0::IFoo/1</fqname>\n"
@@ -472,8 +498,7 @@
                                  "        <name>a.h.foo4</name>\n"
                                  "        <transport arch=\"32\">passthrough</transport>\n"
                                  "        <fqname>@4.0::IFoo/4</fqname>\n"
-                                 "    </hal>\n"
-                                 "</manifest>";
+                                 "    </hal>\n";
 
     optind = 1; // mimic Lshal::parseArg()
     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
@@ -681,8 +706,8 @@
 
 TEST_F(ListTest, UnknownHalType) {
     optind = 1; // mimic Lshal::parseArg()
-    EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,a"})));
-    EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a"));
+    EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,r"})));
+    EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: r"));
 }
 
 TEST_F(ListTest, Vintf) {
@@ -766,6 +791,156 @@
     EXPECT_EQ("", err.str());
 }
 
+TEST_F(ListTest, AllColumns) {
+    // clang-format off
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport Server PTR              Arch Thread Use R Hash                                                             VINTF Status Clients\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  1      0000000000002711 64   11/21      N 0000000000000000000000000000000000000000000000000000000000000000 X     alive  2 4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  2      0000000000002712 64   12/22      Y 0202020202020202020202020202020202020202020202020202020202020202 X     alive  3 5\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough N/A    N/A 32   N/A        ?      X     N/A    4 6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough N/A    N/A 32   N/A        ?      X     N/A    5 7\n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            Transport   Server PTR Arch Thread Use R Hash VINTF Status Clients\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough N/A    N/A 32   N/A        ?      X     N/A    6 8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough N/A    N/A 32   N/A        ?      X     N/A    7 9\n"
+        "\n";
+    // clang-format on
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--all"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, AllColumnsWithCmd) {
+    // clang-format off
+    const std::string expected =
+        "[fake description 0]\n"
+        "Interface            Transport Server CMD     PTR              Arch Thread Use R Hash                                                             VINTF Status Clients CMD\n"
+        "a.h.foo1@1.0::IFoo/1 hwbinder  command_line_1 0000000000002711 64   11/21      N 0000000000000000000000000000000000000000000000000000000000000000 X     alive  command_line_2;command_line_4\n"
+        "a.h.foo2@2.0::IFoo/2 hwbinder  command_line_2 0000000000002712 64   12/22      Y 0202020202020202020202020202020202020202020202020202020202020202 X     alive  command_line_3;command_line_5\n"
+        "\n"
+        "[fake description 1]\n"
+        "Interface            Transport   Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
+        "a.h.foo3@3.0::IFoo/3 passthrough            N/A 32   N/A        ?      X     N/A    command_line_4;command_line_6\n"
+        "a.h.foo4@4.0::IFoo/4 passthrough            N/A 32   N/A        ?      X     N/A    command_line_5;command_line_7\n"
+        "\n"
+        "[fake description 2]\n"
+        "Interface            Transport   Server CMD PTR Arch Thread Use R Hash VINTF Status Clients CMD\n"
+        "a.h.foo5@5.0::IFoo/5 passthrough            N/A 32   N/A        ?      X     N/A    command_line_6;command_line_8\n"
+        "a.h.foo6@6.0::IFoo/6 passthrough            N/A 32   N/A        ?      X     N/A    command_line_7;command_line_9\n"
+        "\n";
+    // clang-format on
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Am"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, AllSections) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=all"})));
+    using HalTypeBase = std::underlying_type_t<HalType>;
+    for (HalTypeBase i = 0; i < static_cast<HalTypeBase>(HalType::LAST); ++i) {
+        EXPECT_THAT(out.str(), HasSubstr("[fake description " + std::to_string(i) + "]"));
+    }
+    EXPECT_THAT(out.str(),
+                Not(HasSubstr("[fake description " +
+                              std::to_string(static_cast<HalTypeBase>(HalType::LAST)) + "]")));
+    EXPECT_EQ("", err.str());
+}
+
+// Fake service returned by mocked IServiceManager::get for DumpDebug.
+// The interfaceChain and getHashChain functions returns
+// foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
+class InheritingService : public IBase {
+public:
+    explicit InheritingService(pid_t id) : mId(id) {}
+    android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
+        cb(getInterfaceName(mId));
+        return hardware::Void();
+    }
+    android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+        std::vector<hidl_string> ret;
+        for (auto i = mId; i > 0; --i) {
+            ret.push_back(getInterfaceName(i));
+        }
+        ret.push_back(IBase::descriptor);
+        cb(ret);
+        return hardware::Void();
+    }
+    android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+        std::vector<hidl_hash> ret;
+        for (auto i = mId; i > 0; --i) {
+            ret.push_back(getHashFromId(i));
+        }
+        ret.push_back(getHashFromId(0xff));
+        cb(ret);
+        return hardware::Void();
+    }
+    android::hardware::Return<void> debug(const hidl_handle& hh,
+                                          const hidl_vec<hidl_string>&) override {
+        const native_handle_t* handle = hh.getNativeHandle();
+        if (handle->numFds < 1) {
+            return Void();
+        }
+        int fd = handle->data[0];
+        std::string content = "debug info for ";
+        content += getInterfaceName(mId);
+        ssize_t written = write(fd, content.c_str(), content.size());
+        if (written != (ssize_t)content.size()) {
+            LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
+                         << content.size() << " bytes, errno = " << errno;
+        }
+        return Void();
+    }
+
+private:
+    pid_t mId;
+};
+
+TEST_F(ListTest, DumpDebug) {
+    size_t inheritanceLevel = 3;
+    sp<IBase> service = new InheritingService(inheritanceLevel);
+
+    EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
+        std::vector<hidl_string> ret;
+        for (auto i = 1; i <= inheritanceLevel; ++i) {
+            ret.push_back(getInterfaceName(i) + "/default");
+        }
+        cb(ret);
+        return hardware::Void();
+    }));
+    EXPECT_CALL(*serviceManager, get(_, _))
+            .WillRepeatedly(
+                    Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
+                        int id = getIdFromInstanceName(instance);
+                        if (id > inheritanceLevel) return nullptr;
+                        return sp<IBase>(service);
+                    }));
+
+    const std::string expected = "[fake description 0]\n"
+                                 "Interface\n"
+                                 "a.h.foo1@1.0::IFoo/default\n"
+                                 "[See a.h.foo3@3.0::IFoo/default]\n"
+                                 "a.h.foo2@2.0::IFoo/default\n"
+                                 "[See a.h.foo3@3.0::IFoo/default]\n"
+                                 "a.h.foo3@3.0::IFoo/default\n"
+                                 "debug info for a.h.foo3@3.0::IFoo\n"
+                                 "\n";
+
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
+    EXPECT_EQ(expected, out.str());
+    EXPECT_EQ("", err.str());
+}
+
 class ListVintfTest : public ListTest {
 public:
     virtual void SetUp() override {
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 7277e85..b139251 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -44,6 +44,9 @@
     cflags: [
         "-DVENDORSERVICEMANAGER=1",
     ],
+    required: [
+        "vndservice",
+    ],
     srcs: ["main.cpp"],
 }
 
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index e80c321..0dbab4e 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -37,6 +37,27 @@
 namespace android {
 
 #ifndef VENDORSERVICEMANAGER
+struct ManifestWithDescription {
+    std::shared_ptr<const vintf::HalManifest> manifest;
+    const char* description;
+};
+// func true -> stop search and forEachManifest will return true
+static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
+    for (const ManifestWithDescription& mwd : {
+            ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
+            ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
+        }) {
+        if (mwd.manifest == nullptr) {
+          LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
+          // note, we explicitly do not retry here, so that we can detect VINTF
+          // or other bugs (b/151696835)
+          continue;
+        }
+        if (func(mwd)) return true;
+    }
+    return false;
+}
+
 static bool isVintfDeclared(const std::string& name) {
     size_t firstSlash = name.find('/');
     size_t lastDot = name.rfind('.', firstSlash);
@@ -49,31 +70,41 @@
     const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
     const std::string instance = name.substr(firstSlash+1);
 
-    struct ManifestWithDescription {
-        std::shared_ptr<const vintf::HalManifest> manifest;
-        const char* description;
-    };
-    for (const ManifestWithDescription& mwd : {
-            ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
-            ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
-        }) {
-        if (mwd.manifest == nullptr) {
-          LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
-          // note, we explicitly do not retry here, so that we can detect VINTF
-          // or other bugs (b/151696835)
-          continue;
-        }
+    bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
         if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
             LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
             return true;
         }
+        return false;  // continue
+    });
+
+    if (!found) {
+        // Although it is tested, explicitly rebuilding qualified name, in case it
+        // becomes something unexpected.
+        LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
+                   << " in the VINTF manifest.";
     }
 
-    // Although it is tested, explicitly rebuilding qualified name, in case it
-    // becomes something unexpected.
-    LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
-               << " in the VINTF manifest.";
-    return false;
+    return found;
+}
+
+static std::vector<std::string> getVintfInstances(const std::string& interface) {
+    size_t lastDot = interface.rfind('.');
+    if (lastDot == std::string::npos) {
+        LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface;
+        return {};
+    }
+    const std::string package = interface.substr(0, lastDot);
+    const std::string iface = interface.substr(lastDot+1);
+
+    std::vector<std::string> ret;
+    (void)forEachManifest([&](const ManifestWithDescription& mwd) {
+        auto instances = mwd.manifest->getAidlInstances(package, iface);
+        ret.insert(ret.end(), instances.begin(), instances.end());
+        return false;  // continue
+    });
+
+    return ret;
 }
 
 static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
@@ -331,6 +362,29 @@
     return Status::ok();
 }
 
+binder::Status ServiceManager::getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    std::vector<std::string> allInstances;
+#ifndef VENDORSERVICEMANAGER
+    allInstances = getVintfInstances(interface);
+#endif
+
+    outReturn->clear();
+
+    for (const std::string& instance : allInstances) {
+        if (mAccess->canFind(ctx, interface + "/" + instance)) {
+            outReturn->push_back(instance);
+        }
+    }
+
+    if (outReturn->size() == 0 && allInstances.size() != 0) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    return Status::ok();
+}
+
 void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
                                     ServiceCallbackMap::iterator* it,
                                     bool* found) {
@@ -440,7 +494,7 @@
     sp<BpBinder> bpBinder = binder->remoteBinder();
     if (bpBinder == nullptr) return -1;
 
-    return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle());
+    return ProcessState::self()->getStrongRefCountForNode(bpBinder);
 }
 
 void ServiceManager::handleClientCallbacks() {
@@ -569,4 +623,21 @@
     return Status::ok();
 }
 
+Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) {
+    if (!mAccess->canList(mAccess->getCallingContext())) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    outReturn->reserve(mNameToService.size());
+    for (auto const& [name, service] : mNameToService) {
+        ServiceDebugInfo info;
+        info.name = name;
+        info.debugPid = service.debugPid;
+
+        outReturn->push_back(std::move(info));
+    }
+
+    return Status::ok();
+}
+
 }  // namespace android
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index a2fc5a8..c089115 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -26,6 +26,7 @@
 
 using os::IClientCallback;
 using os::IServiceCallback;
+using os::ServiceDebugInfo;
 
 class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
 public:
@@ -44,9 +45,11 @@
                                               const sp<IServiceCallback>& callback) override;
 
     binder::Status isDeclared(const std::string& name, bool* outReturn) override;
+    binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                           const sp<IClientCallback>& cb) override;
     binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
+    binder::Status getServiceDebugInfo(std::vector<ServiceDebugInfo>* outReturn) override;
     void binderDied(const wp<IBinder>& who) override;
     void handleClientCallbacks();
 
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 2618906..627dfe6 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -45,10 +45,6 @@
         IPCThreadState::self()->setupPolling(&binder_fd);
         LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
 
-        // Flush after setupPolling(), to make sure the binder driver
-        // knows about this thread handling commands.
-        IPCThreadState::self()->flushCommands();
-
         int ret = looper->addFd(binder_fd,
                                 Looper::POLL_CALLBACK,
                                 Looper::EVENT_INPUT,
@@ -130,7 +126,7 @@
     }
 
     IPCThreadState::self()->setTheContextObject(manager);
-    ps->becomeContextManager(nullptr, nullptr);
+    ps->becomeContextManager();
 
     sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
 
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 152ac28..6d5070f 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,16 +3,11 @@
     user system
     group system readproc
     critical
-    onrestart restart healthd
-    onrestart restart zygote
+    onrestart restart apexd
     onrestart restart audioserver
-    onrestart restart media
-    onrestart restart surfaceflinger
-    onrestart restart inputflinger
-    onrestart restart drm
-    onrestart restart cameraserver
-    onrestart restart keystore
     onrestart restart gatekeeperd
-    onrestart restart thermalservice
+    onrestart class_restart main
+    onrestart class_restart hal
+    onrestart class_restart early_hal
     writepid /dev/cpuset/system-background/tasks
     shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index 3fa4d7d..756f6c3 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -3,4 +3,7 @@
     user system
     group system readproc
     writepid /dev/cpuset/system-background/tasks
+    onrestart class_restart main
+    onrestart class_restart hal
+    onrestart class_restart early_hal
     shutdown critical
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
index cc4c842..32bcc83 100644
--- a/cmds/surfacereplayer/OWNERS
+++ b/cmds/surfacereplayer/OWNERS
@@ -1,2 +1 @@
-mathias@google.com
-racarr@google.com
+include platform/frameworks/native:/services/surfaceflinger/OWNERS
diff --git a/data/etc/android.hardware.uwb.xml b/data/etc/android.hardware.uwb.xml
new file mode 100644
index 0000000..794ba27
--- /dev/null
+++ b/data/etc/android.hardware.uwb.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Adds the feature indicating support for the Ultra Wideband API -->
+<permissions>
+    <feature name="android.hardware.uwb" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2020-03-01.xml b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
new file mode 100644
index 0000000..f11e0bb
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2020-03-01 (0x07E40301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132383489" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2021-03-01.xml b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..b60697d
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
index 9c67d4a..d3ad45a 100644
--- a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2019-03-01 (0x07E30301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132317953" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
index 19b269b..84ba389 100644
--- a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2020-03-01 (0x07E40301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132383489" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..ae26269
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+     tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.vulkan.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
new file mode 100644
index 0000000..c62da0a
--- /dev/null
+++ b/data/etc/pc_core_hardware.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These are the hardware components that all handheld devices
+     must include. Devices with optional hardware must also include extra
+     hardware files, per the comments below.
+
+     Handheld devices include phones, mobile Internet devices (MIDs),
+     Personal Media Players (PMPs), small tablets (7" or less), and similar
+     devices.
+-->
+<permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
+    <feature name="android.hardware.audio.output" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.microphone" />
+    <feature name="android.hardware.screen.portrait" />
+    <feature name="android.hardware.screen.landscape" />
+    <feature name="android.hardware.location" />
+    <feature name="android.hardware.location.network" />
+
+    <!-- basic system services -->
+    <feature name="android.software.app_widgets" />
+    <feature name="android.software.voice_recognizers" />
+    <feature name="android.software.backup" />
+    <feature name="android.software.home_screen" />
+    <feature name="android.software.input_methods" />
+    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
+    <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
+
+    <!-- Feature to specify if the device supports adding device admins. -->
+    <feature name="android.software.device_admin" />
+
+    <!-- Feature to specify if the device support managed users. -->
+    <feature name="android.software.managed_users" />
+
+    <!-- Feature to specify if the device supports controls. -->
+    <feature name="android.software.controls" />
+
+    <!-- Feature to specify if the device supports freeform. -->
+    <feature name="android.software.freeform_window_management" />
+    <feature name="android.hardware.type.pc" />
+</permissions>
\ No newline at end of file
diff --git a/docs/Doxyfile b/docs/Doxyfile
index efa639d..a1bd960 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1621,7 +1621,23 @@
 # undefined via #undef or recursively expanded use the := operator
 # instead of the = operator.
 
-PREDEFINED             = __attribute__(x)=
+PREDEFINED             = \
+    "__ANDROID_API__=10000" \
+    "__BEGIN_DECLS=" \
+    "__END_DECLS=" \
+    "__INTRODUCED_IN(x)=" \
+    "__INTRODUCED_IN_32(x)=" \
+    "__INTRODUCED_IN_64(x)=" \
+    "__RENAME(x)=" \
+    "__RENAME_LDBL(x,y,z)=" \
+    "__printflike(x,y)=" \
+    "__attribute__(x)=" \
+    "__wur=" \
+    "__mallocfunc=" \
+    "__attribute_pure__=" \
+    "__attribute__(x)=" \
+    __ANDROID__ \
+    __BIONIC__ \
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
diff --git a/headers/Android.bp b/headers/Android.bp
index 5337235..8f41c2b 100644
--- a/headers/Android.bp
+++ b/headers/Android.bp
@@ -18,4 +18,11 @@
         "libstagefright_foundation_headers",
     ],
     min_sdk_version: "29",
+
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index dc37bbd..e65b224 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -321,6 +321,46 @@
     OMX_VIDEO_DolbyVisionLevelmax     = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONLEVELTYPE;
 
+/** AV1 Profile enum type */
+typedef enum OMX_VIDEO_AV1PROFILETYPE {
+    OMX_VIDEO_AV1ProfileMain8           = 0x00000001,
+    OMX_VIDEO_AV1ProfileMain10          = 0x00000002,
+    OMX_VIDEO_AV1ProfileMain10HDR10     = 0x00001000,
+    OMX_VIDEO_AV1ProfileMain10HDR10Plus = 0x00002000,
+    OMX_VIDEO_AV1ProfileUnknown         = 0x6EFFFFFF,
+    OMX_VIDEO_AV1ProfileMax             = 0x7FFFFFFF
+} OMX_VIDEO_AV1PROFILETYPE;
+
+/** AV1 Level enum type */
+typedef enum OMX_VIDEO_AV1LEVELTYPE {
+    OMX_VIDEO_AV1Level2         = 0x1,
+    OMX_VIDEO_AV1Level21        = 0x2,
+    OMX_VIDEO_AV1Level22        = 0x4,
+    OMX_VIDEO_AV1Level23        = 0x8,
+    OMX_VIDEO_AV1Level3         = 0x10,
+    OMX_VIDEO_AV1Level31        = 0x20,
+    OMX_VIDEO_AV1Level32        = 0x40,
+    OMX_VIDEO_AV1Level33        = 0x80,
+    OMX_VIDEO_AV1Level4         = 0x100,
+    OMX_VIDEO_AV1Level41        = 0x200,
+    OMX_VIDEO_AV1Level42        = 0x400,
+    OMX_VIDEO_AV1Level43        = 0x800,
+    OMX_VIDEO_AV1Level5         = 0x1000,
+    OMX_VIDEO_AV1Level51        = 0x2000,
+    OMX_VIDEO_AV1Level52        = 0x4000,
+    OMX_VIDEO_AV1Level53        = 0x8000,
+    OMX_VIDEO_AV1Level6         = 0x10000,
+    OMX_VIDEO_AV1Level61        = 0x20000,
+    OMX_VIDEO_AV1Level62        = 0x40000,
+    OMX_VIDEO_AV1Level63        = 0x80000,
+    OMX_VIDEO_AV1Level7         = 0x100000,
+    OMX_VIDEO_AV1Level71        = 0x200000,
+    OMX_VIDEO_AV1Level72        = 0x400000,
+    OMX_VIDEO_AV1Level73        = 0x800000,
+    OMX_VIDEO_AV1LevelUnknown   = 0x6EFFFFFF,
+    OMX_VIDEO_AV1LevelMax       = 0x7FFFFFFF
+} OMX_VIDEO_AV1LEVELTYPE;
+
 /**
  * Structure for configuring video compression intra refresh period
  *
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 2631b14..f195399 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -125,6 +125,8 @@
  * Note that {@link ADataSpace} only exposes a few values. This may return
  * {@link ADATASPACE_UNKNOWN}, even for Named ColorSpaces, if they have no
  * corresponding ADataSpace.
+ *
+ * Available since API level 30.
  */
 int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap)  __INTRODUCED_IN(30);
 
@@ -189,6 +191,8 @@
 /**
  *  User-defined function for writing the output of compression.
  *
+ *  Available since API level 30.
+ *
  *  @param userContext Pointer to user-defined data passed to
  *         {@link AndroidBitmap_compress}.
  *  @param data Compressed data of |size| bytes to write.
@@ -202,6 +206,8 @@
 /**
  *  Compress |pixels| as described by |info|.
  *
+ *  Available since API level 30.
+ *
  *  @param info Description of the pixels to compress.
  *  @param dataspace {@link ADataSpace} describing the color space of the
  *                   pixels.
@@ -234,6 +240,8 @@
  *
  *  Client must not modify it while a Bitmap is wrapping it.
  *
+ *  Available since API level 30.
+ *
  *  @param bitmap Handle to an android.graphics.Bitmap.
  *  @param outBuffer On success, is set to a pointer to the
  *         {@link AHardwareBuffer} associated with bitmap. This acquires
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index c1c4a72..e9f559c 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -129,9 +129,19 @@
  *
  * This api is thread-safe. Any thread is allowed to register a new refresh
  * rate callback for the choreographer instance.
+ *
+ * Note that in API level 30, this api is not guaranteed to be atomic with
+ * DisplayManager. That is, calling Display#getRefreshRate very soon after
+ * a refresh rate callback is invoked may return a stale refresh rate. If any
+ * Display properties would be required by this callback, then it is recommended
+ * to listen directly to DisplayManager.DisplayListener#onDisplayChanged events
+ * instead.
+ *
+ * Available since API level 30.
  */
 void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
-                                                AChoreographer_refreshRateCallback, void* data);
+                                                AChoreographer_refreshRateCallback, void* data)
+        __INTRODUCED_IN(30);
 
 /**
  * Unregisters a callback to be run when the display refresh rate changes, along
@@ -144,9 +154,12 @@
  * callback and associated data pointer are unregistered, then there is a
  * guarantee that when the unregistration completes that that callback will not
  * be run with the data pointer passed.
+ *
+ * Available since API level 30.
  */
 void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
-                                                  AChoreographer_refreshRateCallback, void* data);
+                                                  AChoreographer_refreshRateCallback, void* data)
+        __INTRODUCED_IN(30);
 #endif /* __ANDROID_API__ >= 30 */
 
 __END_DECLS
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 05f4340..ccf3e59 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,13 +58,13 @@
     ACONFIGURATION_ORIENTATION_ANY  = 0x0000,
     /**
      * Orientation: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
+     * <a href="/guide/topics/resources/providing-resources.html#OrientationQualifier">port</a>
      * resource qualifier.
      */
     ACONFIGURATION_ORIENTATION_PORT = 0x0001,
     /**
      * Orientation: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
+     * <a href="/guide/topics/resources/providing-resources.html#OrientationQualifier">land</a>
      * resource qualifier.
      */
     ACONFIGURATION_ORIENTATION_LAND = 0x0002,
@@ -75,7 +75,7 @@
     ACONFIGURATION_TOUCHSCREEN_ANY  = 0x0000,
     /**
      * Touchscreen: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
+     * <a href="/guide/topics/resources/providing-resources.html#TouchscreenQualifier">notouch</a>
      * resource qualifier.
      */
     ACONFIGURATION_TOUCHSCREEN_NOTOUCH  = 0x0001,
@@ -83,7 +83,7 @@
     ACONFIGURATION_TOUCHSCREEN_STYLUS  = 0x0002,
     /**
      * Touchscreen: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
+     * <a href="/guide/topics/resources/providing-resources.html#TouchscreenQualifier">finger</a>
      * resource qualifier.
      */
     ACONFIGURATION_TOUCHSCREEN_FINGER  = 0x0003,
@@ -92,43 +92,43 @@
     ACONFIGURATION_DENSITY_DEFAULT = 0,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">ldpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">ldpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_LOW = 120,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">mdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">mdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_MEDIUM = 160,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">tvdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">tvdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_TV = 213,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">hdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">hdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_HIGH = 240,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xhdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">xhdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_XHIGH = 320,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xxhdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">xxhdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_XXHIGH = 480,
     /**
      * Density: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">xxxhdpi</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">xxxhdpi</a>
      * resource qualifier.
      */
     ACONFIGURATION_DENSITY_XXXHIGH = 640,
@@ -141,19 +141,19 @@
     ACONFIGURATION_KEYBOARD_ANY  = 0x0000,
     /**
      * Keyboard: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ImeQualifier">nokeys</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYBOARD_NOKEYS  = 0x0001,
     /**
      * Keyboard: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ImeQualifier">qwerty</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYBOARD_QWERTY  = 0x0002,
     /**
      * Keyboard: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ImeQualifier">12key</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYBOARD_12KEY  = 0x0003,
@@ -162,25 +162,25 @@
     ACONFIGURATION_NAVIGATION_ANY  = 0x0000,
     /**
      * Navigation: value corresponding to the
-     * <a href="@@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
+     * <a href="@/guide/topics/resources/providing-resources.html#NavigationQualifier">nonav</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVIGATION_NONAV  = 0x0001,
     /**
      * Navigation: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavigationQualifier">dpad</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVIGATION_DPAD  = 0x0002,
     /**
      * Navigation: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavigationQualifier">trackball</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVIGATION_TRACKBALL  = 0x0003,
     /**
      * Navigation: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavigationQualifier">wheel</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVIGATION_WHEEL  = 0x0004,
@@ -189,19 +189,19 @@
     ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000,
     /**
      * Keyboard availability: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
+     * <a href="/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keysexposed</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYSHIDDEN_NO = 0x0001,
     /**
      * Keyboard availability: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
+     * <a href="/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyshidden</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYSHIDDEN_YES = 0x0002,
     /**
      * Keyboard availability: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyssoft</a>
+     * <a href="/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyssoft</a>
      * resource qualifier.
      */
     ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003,
@@ -210,13 +210,13 @@
     ACONFIGURATION_NAVHIDDEN_ANY = 0x0000,
     /**
      * Navigation availability: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavAvailQualifier">navexposed</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVHIDDEN_NO = 0x0001,
     /**
      * Navigation availability: value corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavAvailQualifier">navhidden</a>
      * resource qualifier.
      */
     ACONFIGURATION_NAVHIDDEN_YES = 0x0002,
@@ -226,28 +226,28 @@
     /**
      * Screen size: value indicating the screen is at least
      * approximately 320x426 dp units, corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">small</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENSIZE_SMALL = 0x01,
     /**
      * Screen size: value indicating the screen is at least
      * approximately 320x470 dp units, corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">normal</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENSIZE_NORMAL = 0x02,
     /**
      * Screen size: value indicating the screen is at least
      * approximately 480x640 dp units, corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">large</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENSIZE_LARGE = 0x03,
     /**
      * Screen size: value indicating the screen is at least
      * approximately 720x960 dp units, corresponding to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">xlarge</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENSIZE_XLARGE = 0x04,
@@ -256,13 +256,13 @@
     ACONFIGURATION_SCREENLONG_ANY = 0x00,
     /**
      * Screen layout: value that corresponds to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">notlong</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENLONG_NO = 0x1,
     /**
      * Screen layout: value that corresponds to the
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenAspectQualifier">long</a>
      * resource qualifier.
      */
     ACONFIGURATION_SCREENLONG_YES = 0x2,
@@ -275,13 +275,13 @@
     ACONFIGURATION_WIDE_COLOR_GAMUT_ANY = 0x00,
     /**
      * Wide color gamut: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">no
+     * <a href="/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">no
      * nowidecg</a> resource qualifier specified.
      */
     ACONFIGURATION_WIDE_COLOR_GAMUT_NO = 0x1,
     /**
      * Wide color gamut: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">
+     * <a href="/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">
      * widecg</a> resource qualifier specified.
      */
     ACONFIGURATION_WIDE_COLOR_GAMUT_YES = 0x2,
@@ -290,13 +290,13 @@
     ACONFIGURATION_HDR_ANY = 0x00,
     /**
      * HDR: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+     * <a href="/guide/topics/resources/providing-resources.html#HDRQualifier">
      * lowdr</a> resource qualifier specified.
      */
     ACONFIGURATION_HDR_NO = 0x1,
     /**
      * HDR: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">
+     * <a href="/guide/topics/resources/providing-resources.html#HDRQualifier">
      * highdr</a> resource qualifier specified.
      */
     ACONFIGURATION_HDR_YES = 0x2,
@@ -305,38 +305,38 @@
     ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">no
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">no
      * UI mode type</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">desk</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">car</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">car</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">television</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">television</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_TELEVISION = 0x04,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_APPLIANCE = 0x05,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_WATCH = 0x06,
     /**
      * UI mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">vr</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_TYPE_VR_HEADSET = 0x07,
 
@@ -344,12 +344,12 @@
     ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00,
     /**
      * UI night mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NightQualifier">notnight</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#NightQualifier">notnight</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_NIGHT_NO = 0x1,
     /**
      * UI night mode: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NightQualifier">night</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#NightQualifier">night</a> resource qualifier specified.
      */
     ACONFIGURATION_UI_MODE_NIGHT_YES = 0x2,
 
@@ -366,78 +366,78 @@
     ACONFIGURATION_LAYOUTDIR_ANY  = 0x00,
     /**
      * Layout direction: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldltr</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldltr</a> resource qualifier specified.
      */
     ACONFIGURATION_LAYOUTDIR_LTR  = 0x01,
     /**
      * Layout direction: value that corresponds to
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldrtl</a> resource qualifier specified.
+     * <a href="/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">ldrtl</a> resource qualifier specified.
      */
     ACONFIGURATION_LAYOUTDIR_RTL  = 0x02,
 
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
+     * <a href="/guide/topics/resources/providing-resources.html#MccQualifier">mcc</a>
      * configuration.
      */
     ACONFIGURATION_MCC = 0x0001,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
+     * <a href="/guide/topics/resources/providing-resources.html#MccQualifier">mnc</a>
      * configuration.
      */
     ACONFIGURATION_MNC = 0x0002,
     /**
      * Bit mask for
-     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
+     * <a href="/guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
      * configuration.
      */
     ACONFIGURATION_LOCALE = 0x0004,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#TouchscreenQualifier">touchscreen</a>
+     * <a href="/guide/topics/resources/providing-resources.html#TouchscreenQualifier">touchscreen</a>
      * configuration.
      */
     ACONFIGURATION_TOUCHSCREEN = 0x0008,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ImeQualifier">keyboard</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ImeQualifier">keyboard</a>
      * configuration.
      */
     ACONFIGURATION_KEYBOARD = 0x0010,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyboardHidden</a>
+     * <a href="/guide/topics/resources/providing-resources.html#KeyboardAvailQualifier">keyboardHidden</a>
      * configuration.
      */
     ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#NavigationQualifier">navigation</a>
+     * <a href="/guide/topics/resources/providing-resources.html#NavigationQualifier">navigation</a>
      * configuration.
      */
     ACONFIGURATION_NAVIGATION = 0x0040,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#OrientationQualifier">orientation</a>
+     * <a href="/guide/topics/resources/providing-resources.html#OrientationQualifier">orientation</a>
      * configuration.
      */
     ACONFIGURATION_ORIENTATION = 0x0080,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
+     * <a href="/guide/topics/resources/providing-resources.html#DensityQualifier">density</a>
      * configuration.
      */
     ACONFIGURATION_DENSITY = 0x0100,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">screen size</a>
+     * <a href="/guide/topics/resources/providing-resources.html#ScreenSizeQualifier">screen size</a>
      * configuration.
      */
     ACONFIGURATION_SCREEN_SIZE = 0x0200,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#VersionQualifier">platform version</a>
+     * <a href="/guide/topics/resources/providing-resources.html#VersionQualifier">platform version</a>
      * configuration.
      */
     ACONFIGURATION_VERSION = 0x0400,
@@ -447,27 +447,27 @@
     ACONFIGURATION_SCREEN_LAYOUT = 0x0800,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#UiModeQualifier">ui mode</a>
+     * <a href="/guide/topics/resources/providing-resources.html#UiModeQualifier">ui mode</a>
      * configuration.
      */
     ACONFIGURATION_UI_MODE = 0x1000,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest screen width</a>
+     * <a href="/guide/topics/resources/providing-resources.html#SmallestScreenWidthQualifier">smallest screen width</a>
      * configuration.
      */
     ACONFIGURATION_SMALLEST_SCREEN_SIZE = 0x2000,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">layout direction</a>
+     * <a href="/guide/topics/resources/providing-resources.html#LayoutDirectionQualifier">layout direction</a>
      * configuration.
      */
     ACONFIGURATION_LAYOUTDIR = 0x4000,
     ACONFIGURATION_SCREEN_ROUND = 0x8000,
     /**
      * Bit mask for
-     * <a href="@dacRoot/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">wide color gamut</a>
-     * and <a href="@dacRoot/guide/topics/resources/providing-resources.html#HDRQualifier">HDR</a> configurations.
+     * <a href="/guide/topics/resources/providing-resources.html#WideColorGamutQualifier">wide color gamut</a>
+     * and <a href="/guide/topics/resources/providing-resources.html#HDRQualifier">HDR</a> configurations.
      */
     ACONFIGURATION_COLOR_MODE = 0x10000,
     /**
diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h
index 293e5ac..ae208a6 100644
--- a/include/android/hardware_buffer_jni.h
+++ b/include/android/hardware_buffer_jni.h
@@ -39,9 +39,9 @@
  * Return the AHardwareBuffer wrapped by a Java HardwareBuffer object.
  *
  * This method does not acquire any additional reference to the AHardwareBuffer
- * that is returned. To keep the AHardwareBuffer live after the Java
- * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire()
- * to acquire an additional reference.
+ * that is returned. To keep the AHardwareBuffer alive after the Java
+ * HardwareBuffer object is closed, explicitly or by the garbage collector, be
+ * sure to use AHardwareBuffer_acquire() to acquire an additional reference.
  *
  * Available since API level 26.
  */
@@ -50,7 +50,18 @@
 
 /**
  * Return a new Java HardwareBuffer object that wraps the passed native
- * AHardwareBuffer object.
+ * AHardwareBuffer object. The Java HardwareBuffer will acquire a reference to
+ * the internal buffer and manage its lifetime. For example:
+ *
+ * <pre><code>
+ * AHardwareBuffer* buffer;
+ * AHardwareBuffer_allocate(..., &buffer);  // `buffer` has reference count 1
+ * jobject java_result = AHardwareBuffer_toHardwareBuffer(buffer);  // `buffer` has reference count 2.
+ * AHardwareBuffer_release(buffer); // `buffer` has reference count 1
+ * return result;  // The underlying buffer is kept alive by `java_result` and
+ *                 // will be set to 0 when it is closed on the Java side with
+ *                 // HardwareBuffer::close().
+ * </code></pre>
  *
  * Available since API level 26.
  */
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 3a87da0..d7e6e41 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -133,6 +133,8 @@
 /**
  * Create a new {@link AImageDecoder} from an {@link AAsset}.
  *
+ * Available since API level 30.
+ *
  * @param asset {@link AAsset} containing encoded image data. Client is still
  *              responsible for calling {@link AAsset_close} on it, which may be
  *              done after deleting the returned {@link AImageDecoder}.
@@ -162,6 +164,8 @@
 /**
  * Create a new {@link AImageDecoder} from a file descriptor.
  *
+ * Available since API level 30.
+ *
  * @param fd Seekable, readable, open file descriptor for encoded data.
  *           Client is still responsible for closing it, which may be done
  *           after deleting the returned {@link AImageDecoder}.
@@ -190,6 +194,8 @@
 /**
  * Create a new AImageDecoder from a buffer.
  *
+ * Available since API level 30.
+ *
  * @param buffer Pointer to encoded data. Must be valid for the entire time
  *               the {@link AImageDecoder} is used.
  * @param length Byte length of buffer.
@@ -217,12 +223,16 @@
 
 /**
  * Delete the AImageDecoder.
+ *
+ * Available since API level 30.
  */
 void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30);
 
 /**
  * Choose the desired output format.
  *
+ * Available since API level 30.
+ *
  * @param format {@link AndroidBitmapFormat} to use for the output.
  * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
  *         indicating the reason for the failure. On failure, the
@@ -247,6 +257,8 @@
  * Pass true to this method to leave them unpremultiplied. This has no effect on an
  * opaque image.
  *
+ * Available since API level 30.
+ *
  * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
  * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
  *         indicating the reason for the failure.
@@ -267,6 +279,8 @@
  * Ignored by {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
  * an {@link ADataSpace}.
  *
+ * Available since API level 30.
+ *
  * @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
  *                  specifies how to interpret the colors. By default,
  *                  AImageDecoder will decode into the ADataSpace specified by
@@ -292,6 +306,8 @@
  * specified by width and height, and the output image will be the size of the
  * crop rect.
  *
+ * Available since API level 30.
+ *
  * @param width Width of the output (prior to cropping).
  *              This will affect future calls to
  *              {@link AImageDecoder_getMinimumStride}, which will now return
@@ -319,6 +335,8 @@
  * others. This computes the most efficient target size to use to reach a
  * particular sampleSize.
  *
+ * Available since API level 30.
+ *
  * @param sampleSize A subsampling rate of the original image. Must be greater
  *                   than or equal to 1. A sampleSize of 2 means to skip every
  *                   other pixel/line, resulting in a width and height that are
@@ -344,6 +362,8 @@
  * the specified {@link ARect}. Clients will only need to allocate enough memory
  * for the cropped ARect.
  *
+ * Available since API level 30.
+ *
  * @param crop Rectangle describing a crop of the decode. It must be contained inside of
  *             the (possibly scaled, by {@link AImageDecoder_setTargetSize})
  *             image dimensions. This will affect future calls to
@@ -376,6 +396,8 @@
  *
  * This is owned by the {@link AImageDecoder} and will be destroyed when the
  * AImageDecoder is destroyed via {@link AImageDecoder_delete}.
+ *
+ * Available since API level 30.
  */
 const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(
         const AImageDecoder*) __INTRODUCED_IN(30);
@@ -385,6 +407,8 @@
  * pixel width of the output, unless {@link AImageDecoder_setTargetSize} is
  * used to choose a different size or {@link AImageDecoder_setCrop} is used to
  * set a crop rect.
+ *
+ * Available since API level 30.
  */
 int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
 
@@ -393,12 +417,16 @@
  * pixel height of the output, unless {@link AImageDecoder_setTargetSize} is
  * used to choose a different size or {@link AImageDecoder_setCrop} is used to
  * set a crop rect.
+ *
+ * Available since API level 30.
  */
 int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
 
 /**
  * Report the mimeType of the encoded image.
  *
+ * Available since API level 30.
+ *
  * @return a string literal describing the mime type.
  */
 const char* AImageDecoderHeaderInfo_getMimeType(
@@ -409,6 +437,8 @@
  * by default. {@link AImageDecoder} will try to choose one that is sensible
  * for the image and the system. Note that this does not indicate the
  * encoded format of the image.
+ *
+ * Available since API level 30.
  */
 int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(
         const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
@@ -419,6 +449,8 @@
  * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
  * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}, because
  * {@link AImageDecoder_decodeImage} will premultiply pixels by default.
+ *
+ * Available since API level 30.
  */
 int AImageDecoderHeaderInfo_getAlphaFlags(
         const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
@@ -429,6 +461,8 @@
  * By default, {@link AImageDecoder_decodeImage} will not do any color
  * conversion.
  *
+ * Available since API level 30.
+ *
  * @return The {@link ADataSpace} representing the way the colors
  *         are encoded (or {@link ADATASPACE_UNKNOWN} if there is not a
  *         corresponding ADataSpace). This specifies how to interpret the colors
@@ -452,12 +486,16 @@
  *
  * If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or
  * cropped (via {@link AImageDecoder_setCrop}), this takes those into account.
+ *
+ * Available since API level 30.
  */
 size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
 
 /**
  * Decode the image into pixels, using the settings of the {@link AImageDecoder}.
  *
+ * Available since API level 30.
+ *
  * @param decoder Opaque object representing the decoder.
  * @param pixels On success, will be filled with the result
  *               of the decode. Must be large enough to hold |size| bytes.
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 6efa4f7..5f74682 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -65,6 +65,10 @@
  * 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 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 FD_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.
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 3247fa1..83582d6 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -60,8 +60,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= 30
-
 enum AThermalStatus {
     /** Error in thermal status. */
     ATHERMAL_STATUS_ERROR = -1,
@@ -111,36 +109,45 @@
  */
 typedef void (*AThermal_StatusCallback)(void *data, AThermalStatus status);
 
+#if __ANDROID_API__ >= 30
+
 /**
   * Acquire an instance of the thermal manager. This must be freed using
   * {@link AThermal_releaseManager}.
   *
+  * Available since API level 30.
+  *
   * @return manager instance on success, nullptr on failure.
- */
-AThermalManager* AThermal_acquireManager();
+  */
+AThermalManager* AThermal_acquireManager() __INTRODUCED_IN(30);
 
 /**
  * Release the thermal manager pointer acquired via
  * {@link AThermal_acquireManager}.
  *
- * @param manager The manager to be released.
+ * Available since API level 30.
  *
+ * @param manager The manager to be released.
  */
-void AThermal_releaseManager(AThermalManager *manager);
+void AThermal_releaseManager(AThermalManager *manager) __INTRODUCED_IN(30);
 
 /**
   * Gets the current thermal status.
   *
+  * Available since API level 30.
+  *
   * @param manager The manager instance to use to query the thermal status.
   * Acquired via {@link AThermal_acquireManager}.
   *
   * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
-*/
-AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager);
+  */
+AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) __INTRODUCED_IN(30);
 
 /**
  * Register the thermal status listener for thermal status change.
  *
+ * Available since API level 30.
+ *
  * @param manager The manager instance to use to register.
  * Acquired via {@link AThermal_acquireManager}.
  * @param callback The callback function to be called when thermal status updated.
@@ -152,11 +159,13 @@
  *         EPIPE if communication with the system service has failed.
  */
 int AThermal_registerThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data);
+        AThermal_StatusCallback callback, void *data) __INTRODUCED_IN(30);
 
 /**
  * Unregister the thermal status listener previously resgistered.
  *
+ * Available since API level 30.
+ *
  * @param manager The manager instance to use to unregister.
  * Acquired via {@link AThermal_acquireManager}.
  * @param callback The callback function to be called when thermal status updated.
@@ -168,8 +177,7 @@
  *         EPIPE if communication with the system service has failed.
  */
 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data);
-
+        AThermal_StatusCallback callback, void *data) __INTRODUCED_IN(30);
 
 #endif  //  __ANDROID_API__ >= 30
 
diff --git a/include/android/trace.h b/include/android/trace.h
index d59690a..dbad6f6 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -115,7 +115,7 @@
 #endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
-};
+}
 #endif
 
 #endif // ANDROID_NATIVE_TRACE_H
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/include/binder/Enum.h
similarity index 61%
copy from libs/binder/ndk/test/IBinderNdkUnitTest.aidl
copy to include/binder/Enum.h
index 6e8e463..4c25654 100644
--- a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
+++ b/include/binder/Enum.h
@@ -14,14 +14,9 @@
  * limitations under the License.
  */
 
-// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
-// because it requires libbinder_ndk implementation details or APIs not
-// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
-// over here.
+#pragma once
 
-import IEmpty;
-
-interface IBinderNdkUnitTest {
-    void takeInterface(IEmpty test);
-    void forceFlushCommands();
-}
+#error Do not rely on global include files. All Android cc_* programs are given access to \
+    include_dirs for frameworks/native/include via global configuration, but this is legacy \
+    configuration. Instead, you should have a direct dependency on libbinder OR one of your \
+    dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/include/input/Input.h b/include/input/Input.h
index 54b4e5a..af9c41d 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -86,6 +86,13 @@
 constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
         AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
 
+/**
+ * This flag indicates that the point up event has been canceled.
+ * Typically this is used for palm event when the user has accidental touches.
+ * TODO: Adjust flag to public api
+ */
+constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
+
 enum {
     /* Used when a motion event is not associated with any display.
      * Typically used for non-pointer events. */
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 92da10c..0a00241 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -20,8 +20,8 @@
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
+#include <input/PropertyMap.h>
 #include <utils/Errors.h>
-#include <utils/PropertyMap.h>
 
 namespace android {
 
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
new file mode 100644
index 0000000..3d04331
--- /dev/null
+++ b/include/input/PropertyMap.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UTILS_PROPERTY_MAP_H
+#define _UTILS_PROPERTY_MAP_H
+
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Tokenizer.h>
+
+namespace android {
+
+/*
+ * Provides a mechanism for passing around string-based property key / value pairs
+ * and loading them from property files.
+ *
+ * The property files have the following simple structure:
+ *
+ * # Comment
+ * key = value
+ *
+ * Keys and values are any sequence of printable ASCII characters.
+ * The '=' separates the key from the value.
+ * The key and value may not contain whitespace.
+ *
+ * The '\' character is reserved for escape sequences and is not currently supported.
+ * The '"" character is reserved for quoting and is not currently supported.
+ * Files that contain the '\' or '"' character will fail to parse.
+ *
+ * The file must not contain duplicate keys.
+ *
+ * TODO Support escape sequences and quoted values when needed.
+ */
+class PropertyMap {
+public:
+    /* Creates an empty property map. */
+    PropertyMap();
+    ~PropertyMap();
+
+    /* Clears the property map. */
+    void clear();
+
+    /* Adds a property.
+     * Replaces the property with the same key if it is already present.
+     */
+    void addProperty(const String8& key, const String8& value);
+
+    /* Returns true if the property map contains the specified key. */
+    bool hasProperty(const String8& key) const;
+
+    /* Gets the value of a property and parses it.
+     * Returns true and sets outValue if the key was found and its value was parsed successfully.
+     * Otherwise returns false and does not modify outValue.  (Also logs a warning.)
+     */
+    bool tryGetProperty(const String8& key, String8& outValue) const;
+    bool tryGetProperty(const String8& key, bool& outValue) const;
+    bool tryGetProperty(const String8& key, int32_t& outValue) const;
+    bool tryGetProperty(const String8& key, float& outValue) const;
+
+    /* Adds all values from the specified property map. */
+    void addAll(const PropertyMap* map);
+
+    /* Gets the underlying property map. */
+    inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
+
+    /* Loads a property map from a file. */
+    static status_t load(const String8& filename, PropertyMap** outMap);
+
+private:
+    class Parser {
+        PropertyMap* mMap;
+        Tokenizer* mTokenizer;
+
+    public:
+        Parser(PropertyMap* map, Tokenizer* tokenizer);
+        ~Parser();
+        status_t parse();
+
+    private:
+        status_t parseType();
+        status_t parseKey();
+        status_t parseKeyProperty();
+        status_t parseModifier(const String8& token, int32_t* outMetaState);
+        status_t parseCharacterLiteral(char16_t* outCharacter);
+    };
+
+    KeyedVector<String8, String8> mProperties;
+};
+
+} // namespace android
+
+#endif // _UTILS_PROPERTY_MAP_H
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
index 853f0c9..964e318 100644
--- a/include/powermanager/IPowerManager.h
+++ b/include/powermanager/IPowerManager.h
@@ -46,10 +46,10 @@
         IS_POWER_SAVE_MODE           = IBinder::FIRST_CALL_TRANSACTION + 12,
         GET_POWER_SAVE_STATE         = IBinder::FIRST_CALL_TRANSACTION + 13,
         SET_POWER_SAVE_MODE_ENABLED  = IBinder::FIRST_CALL_TRANSACTION + 14,
-        REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 17,
-        REBOOT_SAFE_MODE             = IBinder::FIRST_CALL_TRANSACTION + 18,
-        SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 19,
-        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 20,
+        REBOOT                       = IBinder::FIRST_CALL_TRANSACTION + 21,
+        REBOOT_SAFE_MODE             = IBinder::FIRST_CALL_TRANSACTION + 22,
+        SHUTDOWN                     = IBinder::FIRST_CALL_TRANSACTION + 23,
+        CRASH                        = IBinder::FIRST_CALL_TRANSACTION + 24,
     };
 
     DECLARE_META_INTERFACE(PowerManager)
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index dae6eeb..15bd5c3 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -282,9 +282,8 @@
             LOG(FATAL) << "adbd_auth: unhandled packet type?";
         }
 
-        output_queue_.pop_front();
-
         ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
+        output_queue_.pop_front();
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index 09a5f39..cdd7764 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -35,6 +35,11 @@
     vendor_available: true,
     double_loadable: true,
     host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
 
     cflags: [
         "-Wall",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b24a577..ed079db 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -31,6 +31,11 @@
         "libutils_headers",
     ],
     min_sdk_version: "29",
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 // These interfaces are android-specific implementation unrelated to binder
@@ -78,7 +83,7 @@
     // or dessert updates. Instead, apex users should use libbinder_ndk.
     apex_available: [
         "//apex_available:platform",
-        // TODO(b/139016109) remove these three
+        // TODO(b/166468760) remove these three
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
@@ -99,6 +104,7 @@
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
         "Parcel.cpp",
+        "ParcelableHolder.cpp",
         "ParcelFileDescriptor.cpp",
         "PersistableBundle.cpp",
         "ProcessState.cpp",
@@ -106,6 +112,7 @@
         "Stability.cpp",
         "Status.cpp",
         "TextOutput.cpp",
+        "Utils.cpp",
         ":libbinder_aidl",
     ],
 
@@ -121,17 +128,26 @@
         vendor: {
             exclude_srcs: libbinder_device_interface_sources,
         },
+        darwin: {
+            enabled: false,
+        },
     },
 
     aidl: {
         export_aidl_headers: true,
     },
 
+    // TODO(b/142684679): for com.android.media which is compiled
+    // as vendor and used as system code.
+    use_apex_name_macro: true,
+
     cflags: [
         "-Wall",
         "-Wextra",
+        "-Wextra-semi",
         "-Werror",
         "-Wzero-as-null-pointer-constant",
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
     ],
     product_variables: {
         binder32bit: {
@@ -158,6 +174,34 @@
         misc_undefined: ["integer"],
     },
     min_sdk_version: "29",
+
+    tidy: true,
+    tidy_flags: [
+        // Only check our headers
+        "--header-filter=^.*frameworks/native/libs/binder/.*.h$",
+    ],
+    tidy_checks_as_errors: [
+        // Explicitly list the checks that should not occur in this module.
+        "abseil-*",
+        "android-*",
+        "bugprone-*",
+        "cert-*",
+        "clang-analyzer-*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "google-*",
+        "-google-readability-*",
+        "-google-runtime-references",
+        "misc-*",
+        "-misc-no-recursion",
+        "-misc-redundant-expression",
+        "-misc-unused-using-decls",
+        "performance*",
+        "portability*",
+    ],
 }
 
 // AIDL interface between libbinder and framework.jar
@@ -170,6 +214,7 @@
         "aidl/android/os/IClientCallback.aidl",
         "aidl/android/os/IServiceCallback.aidl",
         "aidl/android/os/IServiceManager.aidl",
+        "aidl/android/os/ServiceDebugInfo.aidl",
     ],
     path: "aidl",
 }
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 2174ce2..1c6b491 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -91,12 +91,12 @@
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
-    return noteOp(op, uid, callingPackage, std::unique_ptr<String16>(),
+    return noteOp(op, uid, callingPackage, {},
             String16("Legacy AppOpsManager.noteOp call"));
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-        const std::unique_ptr<String16>& attributionTag, const String16& message) {
+        const std::optional<String16>& attributionTag, const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
             ? service->noteOperation(op, uid, callingPackage, attributionTag,
@@ -108,12 +108,12 @@
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
         bool startIfModeDefault) {
-    return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, std::unique_ptr<String16>(),
+    return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, {},
             String16("Legacy AppOpsManager.startOpNoThrow call"));
 }
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-        bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
+        bool startIfModeDefault, const std::optional<String16>& attributionTag,
         const String16& message) {
     sp<IAppOpsService> service = getService();
     int32_t mode = service != nullptr
@@ -125,11 +125,11 @@
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
-    finishOp(op, uid, callingPackage, std::unique_ptr<String16>());
+    finishOp(op, uid, callingPackage, {});
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage,
-        const std::unique_ptr<String16>& attributionTag) {
+        const std::optional<String16>& attributionTag) {
     sp<IAppOpsService> service = getService();
     if (service != nullptr) {
         service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag);
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 6ca3b16..d964d25 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -133,6 +133,7 @@
 public:
     // unlocked objects
     bool mRequestingSid = false;
+    bool mInheritRt = false;
     sp<IBinder> mExtension;
     int mPolicy = SCHED_NORMAL;
     int mPriority = 0;
@@ -173,6 +174,10 @@
 {
     data.setDataPosition(0);
 
+    if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) {
+        reply->markSensitive();
+    }
+
     status_t err = NO_ERROR;
     switch (code) {
         case PING_TRANSACTION:
@@ -323,6 +328,27 @@
     return e->mPriority;
 }
 
+bool BBinder::isInheritRt() {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    return e && e->mInheritRt;
+}
+
+void BBinder::setInheritRt(bool inheritRt) {
+    Extras* e = mExtras.load(std::memory_order_acquire);
+
+    if (!e) {
+        if (!inheritRt) {
+            return;
+        }
+
+        e = getOrCreateExtras();
+        if (!e) return; // out of memory
+    }
+
+    e->mInheritRt = inheritRt;
+}
+
 pid_t BBinder::getDebugPid() {
     return getpid();
 }
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index d2b9b8f..bf4387a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -137,8 +137,8 @@
 }
 
 BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
-    : mHandle(handle)
-    , mStability(0)
+    : mStability(0)
+    , mHandle(handle)
     , mAlive(1)
     , mObitsSent(0)
     , mObituaries(nullptr)
@@ -223,13 +223,14 @@
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
             using android::internal::Stability;
 
-            auto stability = Stability::get(this);
-            auto required = privateVendor ? Stability::VENDOR : Stability::kLocalStability;
+            auto category = Stability::getCategory(this);
+            Stability::Level required = privateVendor ? Stability::VENDOR
+                : Stability::getLocalLevel();
 
-            if (CC_UNLIKELY(!Stability::check(stability, required))) {
+            if (CC_UNLIKELY(!Stability::check(category, required))) {
                 ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
-                    Stability::stabilityString(stability).c_str(),
-                    Stability::stabilityString(required).c_str());
+                    category.debugString().c_str(),
+                    Stability::levelString(required).c_str());
                 return BAD_TYPE;
             }
         }
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 8cf6097..88c85bf 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -18,7 +18,6 @@
 #include <binder/Debug.h>
 
 #include <cutils/atomic.h>
-#include <cutils/threads.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
@@ -91,22 +90,6 @@
 
 static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
 
-static thread_store_t   tls;
-
-BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
-{
-    ThreadState*  ts = (ThreadState*) thread_store_get( &tls );
-    if (ts) return ts;
-    ts = new ThreadState;
-    thread_store_set( &tls, ts, threadDestructor );
-    return ts;
-}
-
-void BufferedTextOutput::threadDestructor(void *st)
-{
-    delete ((ThreadState*)st);
-}
-
 static volatile int32_t gSequence = 0;
 
 static volatile int32_t gFreeBufferIndex = -1;
@@ -266,16 +249,14 @@
 BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
 {
     if ((mFlags&MULTITHREADED) != 0) {
-        ThreadState* ts = getThreadState();
-        if (ts) {
-            while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
-            BufferState* bs = ts->states[mIndex].get();
-            if (bs != nullptr && bs->seq == mSeq) return bs;
-            
-            ts->states.editItemAt(mIndex) = new BufferState(mIndex);
-            bs = ts->states[mIndex].get();
-            if (bs != nullptr) return bs;
-        }
+        thread_local ThreadState ts;
+        while (ts.states.size() <= (size_t)mIndex) ts.states.add(nullptr);
+        BufferState* bs = ts.states[mIndex].get();
+        if (bs != nullptr && bs->seq == mSeq) return bs;
+
+        ts.states.editItemAt(mIndex) = new BufferState(mIndex);
+        bs = ts.states[mIndex].get();
+        if (bs != nullptr) return bs;
     }
     
     return mGlobalState;
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index 1b27bb2..fdd532a 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -47,10 +47,7 @@
 private:
     struct BufferState;
     struct ThreadState;
-    
-    static  ThreadState*getThreadState();
-    static  void        threadDestructor(void *st);
-    
+
             BufferState*getBuffer() const;
             
     uint32_t            mFlags;
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 64c1ff6..3a62059 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -208,7 +208,7 @@
     }
 
     for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
-        long remain = length;
+        ssize_t remain = length;
 
         char* c = buffer;
         if (!oneLine && !cStyle) {
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 1eb5363..b81995c 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -108,6 +108,6 @@
 
 // ------------------------------------------------------------------------------------
 
-IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager");
+IMPLEMENT_META_INTERFACE(ActivityManager, "android.app.IActivityManager")
 
 } // namespace android
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index b9eb281..2b3f462 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -43,7 +43,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback");
+IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 0714723..1af5ab8 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -22,6 +22,8 @@
 #include <binder/Parcel.h>
 #include <utils/String8.h>
 
+#include <optional>
+
 namespace android {
 
 // ----------------------------------------------------------------------
@@ -47,7 +49,7 @@
     }
 
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-                const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
+                const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
                 const String16& message) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -64,7 +66,7 @@
     }
 
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-                const String16& packageName, const std::unique_ptr<String16>& attributionTag,
+                const String16& packageName, const std::optional<String16>& attributionTag,
                 bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -83,7 +85,7 @@
     }
 
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& attributionTag) {
+            const String16& packageName, const std::optional<String16>& attributionTag) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
         data.writeStrongBinder(token);
@@ -157,7 +159,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
+IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService")
 
 // ----------------------------------------------------------------------
 
@@ -182,7 +184,7 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> attributionTag;
+            std::optional<String16> attributionTag;
             data.readString16(&attributionTag);
             bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
             String16 message = data.readString16();
@@ -198,7 +200,7 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> attributionTag;
+            std::optional<String16> attributionTag;
             data.readString16(&attributionTag);
             bool startIfModeDefault = data.readInt32() == 1;
             bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
@@ -215,7 +217,7 @@
             int32_t code = data.readInt32();
             int32_t uid = data.readInt32();
             String16 packageName = data.readString16();
-            std::unique_ptr<String16> attributionTag;
+            std::optional<String16> attributionTag;
             data.readString16(&attributionTag);
             finishOperation(token, code, uid, packageName, attributionTag);
             reply->writeNoException();
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index a47dbac..d0085df 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -130,7 +130,7 @@
 
 };
 
-IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
+IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp
index 4198e49..f5fa817 100644
--- a/libs/binder/IMediaResourceMonitor.cpp
+++ b/libs/binder/IMediaResourceMonitor.cpp
@@ -38,10 +38,11 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor");
+IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor")
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply,
         uint32_t flags) {
     switch(code) {
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index c2bb811..cca8f81 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -82,10 +82,10 @@
     explicit BpMemoryHeap(const sp<IBinder>& impl);
     virtual ~BpMemoryHeap();
 
-    virtual int getHeapID() const;
-    virtual void* getBase() const;
-    virtual size_t getSize() const;
-    virtual uint32_t getFlags() const;
+    int getHeapID() const override;
+    void* getBase() const override;
+    size_t getSize() const override;
+    uint32_t getFlags() const override;
     off_t getOffset() const override;
 
 private:
@@ -223,7 +223,7 @@
 
 // ---------------------------------------------------------------------------
 
-IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory");
+IMPLEMENT_META_INTERFACE(Memory, "android.utils.IMemory")
 
 BnMemory::BnMemory() {
 }
@@ -388,7 +388,7 @@
 
 // ---------------------------------------------------------------------------
 
-IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
+IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap")
 
 BnMemoryHeap::BnMemoryHeap() {
 }
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 847b73a..5c34069 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -135,7 +135,7 @@
         out << "target.ptr=" << btd->target.ptr;
     }
     out << " (cookie " << btd->cookie << ")" << endl
-        << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(long)btd->flags << endl
+        << "code=" << TypeCode(btd->code) << ", flags=" << (void*)(uint64_t)btd->flags << endl
         << "data=" << btd->data.ptr.buffer << " (" << (void*)btd->data_size
         << " bytes)" << endl
         << "offsets=" << btd->data.ptr.offsets << " (" << (void*)btd->offsets_size
@@ -150,7 +150,7 @@
     uint32_t code = (uint32_t)*cmd++;
     size_t cmdIndex = code & 0xff;
     if (code == BR_ERROR) {
-        out << "BR_ERROR: " << (void*)(long)(*cmd++) << endl;
+        out << "BR_ERROR: " << (void*)(uint64_t)(*cmd++) << endl;
         return cmd;
     } else if (cmdIndex >= N) {
         out << "Unknown reply: " << code << endl;
@@ -177,21 +177,21 @@
         case BR_DECREFS: {
             const int32_t b = *cmd++;
             const int32_t c = *cmd++;
-            out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
+            out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c << ")";
         } break;
 
         case BR_ATTEMPT_ACQUIRE: {
             const int32_t p = *cmd++;
             const int32_t b = *cmd++;
             const int32_t c = *cmd++;
-            out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c
+            out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c
                 << "), pri=" << p;
         } break;
 
         case BR_DEAD_BINDER:
         case BR_CLEAR_DEATH_NOTIFICATION_DONE: {
             const int32_t c = *cmd++;
-            out << ": death cookie " << (void*)(long)c;
+            out << ": death cookie " << (void*)(uint64_t)c;
         } break;
 
         default:
@@ -232,7 +232,7 @@
 
         case BC_FREE_BUFFER: {
             const int32_t buf = *cmd++;
-            out << ": buffer=" << (void*)(long)buf;
+            out << ": buffer=" << (void*)(uint64_t)buf;
         } break;
 
         case BC_INCREFS:
@@ -247,7 +247,7 @@
         case BC_ACQUIRE_DONE: {
             const int32_t b = *cmd++;
             const int32_t c = *cmd++;
-            out << ": target=" << (void*)(long)b << " (cookie " << (void*)(long)c << ")";
+            out << ": target=" << (void*)(uint64_t)b << " (cookie " << (void*)(uint64_t)c << ")";
         } break;
 
         case BC_ATTEMPT_ACQUIRE: {
@@ -260,12 +260,12 @@
         case BC_CLEAR_DEATH_NOTIFICATION: {
             const int32_t h = *cmd++;
             const int32_t c = *cmd++;
-            out << ": handle=" << h << " (death cookie " << (void*)(long)c << ")";
+            out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")";
         } break;
 
         case BC_DEAD_BINDER_DONE: {
             const int32_t c = *cmd++;
-            out << ": death cookie " << (void*)(long)c;
+            out << ": death cookie " << (void*)(uint64_t)c;
         } break;
 
         default:
@@ -448,6 +448,14 @@
     return mLastTransactionBinderFlags;
 }
 
+void IPCThreadState::setCallRestriction(ProcessState::CallRestriction restriction) {
+    mCallRestriction = restriction;
+}
+
+ProcessState::CallRestriction IPCThreadState::getCallRestriction() const {
+    return mCallRestriction;
+}
+
 void IPCThreadState::restoreCallingIdentity(int64_t token)
 {
     mCallingUid = (int)(token>>32);
@@ -478,15 +486,30 @@
     }
 }
 
+bool IPCThreadState::flushIfNeeded()
+{
+    if (mIsLooper || mServingStackPointer != nullptr) {
+        return false;
+    }
+    // In case this thread is not a looper and is not currently serving a binder transaction,
+    // there's no guarantee that this thread will call back into the kernel driver any time
+    // soon. Therefore, flush pending commands such as BC_FREE_BUFFER, to prevent them from getting
+    // stuck in this thread's out buffer.
+    flushCommands();
+    return true;
+}
+
 void IPCThreadState::blockUntilThreadAvailable()
 {
     pthread_mutex_lock(&mProcess->mThreadCountLock);
+    mProcess->mWaitingForThreads++;
     while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
         ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n",
                 static_cast<unsigned long>(mProcess->mExecutingThreadsCount),
                 static_cast<unsigned long>(mProcess->mMaxThreads));
         pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
     }
+    mProcess->mWaitingForThreads--;
     pthread_mutex_unlock(&mProcess->mThreadCountLock);
 }
 
@@ -526,7 +549,12 @@
             }
             mProcess->mStarvationStartTimeMs = 0;
         }
-        pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+
+        // Cond broadcast can be expensive, so don't send it every time a binder
+        // call is processed. b/168806193
+        if (mProcess->mWaitingForThreads > 0) {
+            pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+        }
         pthread_mutex_unlock(&mProcess->mThreadCountLock);
     }
 
@@ -589,6 +617,7 @@
 
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
 
+    mIsLooper = true;
     status_t result;
     do {
         processPendingDerefs();
@@ -611,16 +640,18 @@
         (void*)pthread_self(), getpid(), result);
 
     mOut.writeInt32(BC_EXIT_LOOPER);
+    mIsLooper = false;
     talkWithDriver(false);
 }
 
-int IPCThreadState::setupPolling(int* fd)
+status_t IPCThreadState::setupPolling(int* fd)
 {
     if (mProcess->mDriverFD < 0) {
         return -EBADF;
     }
 
     mOut.writeInt32(BC_ENTER_LOOPER);
+    flushCommands();
     *fd = mProcess->mDriverFD;
     return 0;
 }
@@ -679,7 +710,7 @@
                 CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
                     ANDROID_LOG_ERROR);
             } else /* FATAL_IF_NOT_ONEWAY */ {
-                LOG_ALWAYS_FATAL("Process may not make oneway calls (code: %u).", code);
+                LOG_ALWAYS_FATAL("Process may not make non-oneway calls (code: %u).", code);
             }
         }
 
@@ -723,9 +754,11 @@
     LOG_REMOTEREFS("IPCThreadState::incStrongHandle(%d)\n", handle);
     mOut.writeInt32(BC_ACQUIRE);
     mOut.writeInt32(handle);
-    // Create a temp reference until the driver has handled this command.
-    proxy->incStrong(mProcess.get());
-    mPostWriteStrongDerefs.push(proxy);
+    if (!flushIfNeeded()) {
+        // Create a temp reference until the driver has handled this command.
+        proxy->incStrong(mProcess.get());
+        mPostWriteStrongDerefs.push(proxy);
+    }
 }
 
 void IPCThreadState::decStrongHandle(int32_t handle)
@@ -733,6 +766,7 @@
     LOG_REMOTEREFS("IPCThreadState::decStrongHandle(%d)\n", handle);
     mOut.writeInt32(BC_RELEASE);
     mOut.writeInt32(handle);
+    flushIfNeeded();
 }
 
 void IPCThreadState::incWeakHandle(int32_t handle, BpBinder *proxy)
@@ -740,9 +774,11 @@
     LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
     mOut.writeInt32(BC_INCREFS);
     mOut.writeInt32(handle);
-    // Create a temp reference until the driver has handled this command.
-    proxy->getWeakRefs()->incWeak(mProcess.get());
-    mPostWriteWeakDerefs.push(proxy->getWeakRefs());
+    if (!flushIfNeeded()) {
+        // Create a temp reference until the driver has handled this command.
+        proxy->getWeakRefs()->incWeak(mProcess.get());
+        mPostWriteWeakDerefs.push(proxy->getWeakRefs());
+    }
 }
 
 void IPCThreadState::decWeakHandle(int32_t handle)
@@ -750,6 +786,7 @@
     LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
     mOut.writeInt32(BC_DECREFS);
     mOut.writeInt32(handle);
+    flushIfNeeded();
 }
 
 status_t IPCThreadState::attemptIncStrongHandle(int32_t handle)
@@ -805,6 +842,7 @@
       mServingStackPointer(nullptr),
       mWorkSource(kUnsetWorkSource),
       mPropagateWorkSource(false),
+      mIsLooper(false),
       mStrictModePolicy(0),
       mLastTransactionBinderFlags(0),
       mCallRestriction(mProcess->mCallRestriction)
@@ -887,21 +925,21 @@
                             tr.data_size,
                             reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                             tr.offsets_size/sizeof(binder_size_t),
-                            freeBuffer, this);
+                            freeBuffer);
                     } else {
                         err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                         freeBuffer(nullptr,
                             reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                             tr.data_size,
                             reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                            tr.offsets_size/sizeof(binder_size_t), this);
+                            tr.offsets_size/sizeof(binder_size_t));
                     }
                 } else {
                     freeBuffer(nullptr,
                         reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                         tr.data_size,
                         reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                        tr.offsets_size/sizeof(binder_size_t), this);
+                        tr.offsets_size/sizeof(binder_size_t));
                     continue;
                 }
             }
@@ -1069,7 +1107,7 @@
 
 sp<BBinder> the_context_object;
 
-void IPCThreadState::setTheContextObject(sp<BBinder> obj)
+void IPCThreadState::setTheContextObject(const sp<BBinder>& obj)
 {
     the_context_object = obj;
 }
@@ -1175,7 +1213,7 @@
                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                 tr.data_size,
                 reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
+                tr.offsets_size/sizeof(binder_size_t), freeBuffer);
 
             const void* origServingStackPointer = mServingStackPointer;
             mServingStackPointer = &origServingStackPointer; // anything on the stack
@@ -1236,12 +1274,26 @@
             if ((tr.flags & TF_ONE_WAY) == 0) {
                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                 if (error < NO_ERROR) reply.setError(error);
-                sendReply(reply, 0);
+
+                constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
+                sendReply(reply, (tr.flags & kForwardReplyFlags));
             } else {
-                if (error != OK || reply.dataSize() != 0) {
-                    alog << "oneway function results will be dropped but finished with status "
-                         << statusToString(error)
-                         << " and parcel size " << reply.dataSize() << endl;
+                if (error != OK) {
+                    alog << "oneway function results for code " << tr.code
+                         << " on binder at "
+                         << reinterpret_cast<void*>(tr.target.ptr)
+                         << " will be dropped but finished with status "
+                         << statusToString(error);
+
+                    // ideally we could log this even when error == OK, but it
+                    // causes too much logspam because some manually-written
+                    // interfaces have clients that call methods which always
+                    // write results, sometimes as oneway methods.
+                    if (reply.dataSize() != 0) {
+                         alog << " and reply parcel size " << reply.dataSize();
+                    }
+
+                    alog << endl;
                 }
                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
             }
@@ -1360,7 +1412,7 @@
 void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
                                 size_t /*dataSize*/,
                                 const binder_size_t* /*objects*/,
-                                size_t /*objectsSize*/, void* /*cookie*/)
+                                size_t /*objectsSize*/)
 {
     //ALOGI("Freeing parcel %p", &parcel);
     IF_LOG_COMMANDS() {
@@ -1371,6 +1423,7 @@
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
     state->mOut.writePointer((uintptr_t)data);
+    state->flushIfNeeded();
 }
 
 } // namespace android
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index d9bf3cc..f94f413 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -103,7 +103,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
+IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index a38a27a..570edb9 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -84,7 +84,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService");
+IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
index 556288c..cd92217 100644
--- a/libs/binder/IResultReceiver.cpp
+++ b/libs/binder/IResultReceiver.cpp
@@ -42,7 +42,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver");
+IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index a9f2d73..ca067e2 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -18,6 +18,9 @@
 
 #include <binder/IServiceManager.h>
 
+#include <inttypes.h>
+#include <unistd.h>
+
 #include <android/os/BnServiceCallback.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
@@ -36,8 +39,6 @@
 
 #include "Static.h"
 
-#include <unistd.h>
-
 namespace android {
 
 using AidlServiceManager = android::os::IServiceManager;
@@ -73,6 +74,7 @@
     Vector<String16> listServices(int dumpsysPriority) override;
     sp<IBinder> waitForService(const String16& name16) override;
     bool isDeclared(const String16& name) override;
+    Vector<String16> getDeclaredInstances(const String16& interface) override;
 
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
@@ -206,6 +208,10 @@
  : mTheRealServiceManager(impl)
 {}
 
+// This implementation could be simplified and made more efficient by delegating
+// to waitForService. However, this changes the threading structure in some
+// cases and could potentially break prebuilts. Once we have higher logistical
+// complexity, this could be attempted.
 sp<IBinder> ServiceManagerShim::getService(const String16& name) const
 {
     static bool gSystemBootCompleted = false;
@@ -215,7 +221,8 @@
 
     const bool isVendorService =
         strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
-    const long timeout = uptimeMillis() + 5000;
+    constexpr int64_t timeout = 5000;
+    int64_t startTime = uptimeMillis();
     // Vendor code can't access system properties
     if (!gSystemBootCompleted && !isVendorService) {
 #ifdef __ANDROID__
@@ -227,17 +234,23 @@
 #endif
     }
     // retry interval in millisecond; note that vendor services stay at 100ms
-    const long sleepTime = gSystemBootCompleted ? 1000 : 100;
+    const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100;
+
+    ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
+          ProcessState::self()->getDriverName().c_str());
 
     int n = 0;
-    while (uptimeMillis() < timeout) {
+    while (uptimeMillis() - startTime < timeout) {
         n++;
-        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
-            ProcessState::self()->getDriverName().c_str());
         usleep(1000*sleepTime);
 
         sp<IBinder> svc = checkService(name);
-        if (svc != nullptr) return svc;
+        if (svc != nullptr) {
+            ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
+                  String8(name).string(), ProcessState::self()->getDriverName().c_str(),
+                  uptimeMillis() - startTime);
+            return svc;
+        }
     }
     ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
     return nullptr;
@@ -297,7 +310,7 @@
     // Simple RAII object to ensure a function call immediately before going out of scope
     class Defer {
     public:
-        Defer(std::function<void()>&& f) : mF(std::move(f)) {}
+        explicit Defer(std::function<void()>&& f) : mF(std::move(f)) {}
         ~Defer() { mF(); }
     private:
         std::function<void()> mF;
@@ -322,6 +335,11 @@
 
     while(true) {
         {
+            // It would be really nice if we could read binder commands on this
+            // thread instead of needing a threadpool to be started, but for
+            // instance, if we call getAndExecuteCommand, it might be the case
+            // that another thread serves the callback, and we never get a
+            // command, so we hang indefinitely.
             std::unique_lock<std::mutex> lock(waiter->mMutex);
             using std::literals::chrono_literals::operator""s;
             waiter->mCv.wait_for(lock, 1s, [&] {
@@ -330,6 +348,8 @@
             if (waiter->mBinder != nullptr) return waiter->mBinder;
         }
 
+        ALOGW("Waited one second for %s (is service started? are binder threads started and available?)", name.c_str());
+
         // Handle race condition for lazy services. Here is what can happen:
         // - the service dies (not processed by init yet).
         // - sm processes death notification.
@@ -343,8 +363,6 @@
             return nullptr;
         }
         if (out != nullptr) return out;
-
-        ALOGW("Waited one second for %s", name.c_str());
     }
 }
 
@@ -356,4 +374,18 @@
     return declared;
 }
 
+Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) {
+    std::vector<std::string> out;
+    if (!mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out).isOk()) {
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(out.size());
+    for (const std::string& instance : out) {
+        res.push(String16(instance.c_str()));
+    }
+    return res;
+}
+
 } // namespace android
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index a3e2b67..86dd5c4 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -52,7 +52,7 @@
     }
 };
 
-IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback");
+IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback")
 
 // ----------------------------------------------------------------------
 
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index b21af96..a1b08db 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -71,10 +71,11 @@
 
 // ----------------------------------------------------------------------
 
-IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver")
 
 // ----------------------------------------------------------------------
 
+// NOLINTNEXTLINE(google-default-arguments)
 status_t BnUidObserver::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index f2c5139..68ea8a6 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "log/log_main.h"
 #define LOG_TAG "AidlLazyServiceRegistrar"
 
 #include <binder/LazyServiceRegistrar.h>
@@ -37,6 +38,12 @@
                          bool allowIsolated, int dumpFlags);
     void forcePersist(bool persist);
 
+    void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
+
+    bool tryUnregister();
+
+    void reRegister();
+
 protected:
     Status onClients(const sp<IBinder>& service, bool clients) override;
 
@@ -48,14 +55,27 @@
     void tryShutdown();
 
     /**
+     * Try to shutdown the process, unless:
+     * - 'forcePersist' is 'true', or
+     * - The active services count callback returns 'true', or
+     * - Some services have clients.
+     */
+    void maybeTryShutdown();
+
+    /*
      * Counter of the number of services that currently have at least one client.
      */
     size_t mNumConnectedServices;
 
+    // previous value passed to the active services callback
+    std::optional<bool> mPreviousHasClients;
+
     struct Service {
         sp<IBinder> service;
         bool allowIsolated;
         int dumpFlags;
+
+        bool registered = true;
     };
     /**
      * Map of registered names and services
@@ -63,6 +83,9 @@
     std::map<std::string, Service> mRegisteredServices;
 
     bool mForcePersist;
+
+    // Callback used to report if there are services with clients
+    std::function<bool(bool)> mActiveServicesCallback;
 };
 
 class ClientCounterCallback {
@@ -77,6 +100,12 @@
      */
     void forcePersist(bool persist);
 
+    void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
+
+    bool tryUnregister();
+
+    void reRegister();
+
 private:
     sp<ClientCounterCallbackImpl> mImpl;
 };
@@ -109,8 +138,64 @@
 
 void ClientCounterCallbackImpl::forcePersist(bool persist) {
     mForcePersist = persist;
-    if(!mForcePersist) {
+    if (!mForcePersist) {
         // Attempt a shutdown in case the number of clients hit 0 while the flag was on
+        maybeTryShutdown();
+    }
+}
+
+bool ClientCounterCallbackImpl::tryUnregister() {
+    auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
+
+    for (auto& [name, entry] : mRegisteredServices) {
+        bool success = manager->tryUnregisterService(name, entry.service).isOk();
+
+        if (!success) {
+            ALOGI("Failed to unregister service %s", name.c_str());
+            return false;
+        }
+        entry.registered = false;
+    }
+
+    return true;
+}
+
+void ClientCounterCallbackImpl::reRegister() {
+    for (auto& [name, entry] : mRegisteredServices) {
+        // re-register entry if not already registered
+        if (entry.registered) {
+            continue;
+        }
+
+        if (!registerService(entry.service, name, entry.allowIsolated,
+                             entry.dumpFlags)) {
+            // Must restart. Otherwise, clients will never be able to get a hold of this service.
+            LOG_ALWAYS_FATAL("Bad state: could not re-register services");
+        }
+
+        entry.registered = true;
+    }
+}
+
+void ClientCounterCallbackImpl::maybeTryShutdown() {
+    if (mForcePersist) {
+        ALOGI("Shutdown prevented by forcePersist override flag.");
+        return;
+    }
+
+    bool handledInCallback = false;
+    if (mActiveServicesCallback != nullptr) {
+        bool hasClients = mNumConnectedServices != 0;
+        if (hasClients != mPreviousHasClients) {
+            handledInCallback = mActiveServicesCallback(hasClients);
+            mPreviousHasClients = hasClients;
+        }
+    }
+
+    // If there is no callback defined or the callback did not handle this
+    // client count change event, try to shutdown the process if its services
+    // have no clients.
+    if (!handledInCallback && mNumConnectedServices == 0) {
         tryShutdown();
     }
 }
@@ -130,53 +215,24 @@
           mNumConnectedServices, mRegisteredServices.size(),
           String8(service->getInterfaceDescriptor()).string(), clients);
 
-    tryShutdown();
+    maybeTryShutdown();
     return Status::ok();
 }
 
-void ClientCounterCallbackImpl::tryShutdown() {
-    if(mNumConnectedServices > 0) {
-        // Should only shut down if there are no clients
-        return;
-    }
+ void ClientCounterCallbackImpl::tryShutdown() {
+     ALOGI("Trying to shut down the service. No clients in use for any service in process.");
 
-    if(mForcePersist) {
-        ALOGI("Shutdown prevented by forcePersist override flag.");
-        return;
-    }
+    if (tryUnregister()) {
+         ALOGI("Unregistered all clients and exiting");
+         exit(EXIT_SUCCESS);
+     }
 
-    ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+    reRegister();
+}
 
-    auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
-
-    auto unRegisterIt = mRegisteredServices.begin();
-    for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
-        auto& entry = (*unRegisterIt);
-
-        bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk();
-
-        if (!success) {
-            ALOGI("Failed to unregister service %s", entry.first.c_str());
-            break;
-        }
-    }
-
-    if (unRegisterIt == mRegisteredServices.end()) {
-        ALOGI("Unregistered all clients and exiting");
-        exit(EXIT_SUCCESS);
-    }
-
-    for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
-         reRegisterIt++) {
-        auto& entry = (*reRegisterIt);
-
-        // re-register entry
-        if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated,
-                             entry.second.dumpFlags)) {
-            // Must restart. Otherwise, clients will never be able to get a hold of this service.
-            ALOGE("Bad state: could not re-register services");
-        }
-    }
+void ClientCounterCallbackImpl::setActiveServicesCallback(const std::function<bool(bool)>&
+                                                          activeServicesCallback) {
+    mActiveServicesCallback = activeServicesCallback;
 }
 
 ClientCounterCallback::ClientCounterCallback() {
@@ -192,6 +248,19 @@
     mImpl->forcePersist(persist);
 }
 
+void ClientCounterCallback::setActiveServicesCallback(const std::function<bool(bool)>&
+                                                      activeServicesCallback) {
+    mImpl->setActiveServicesCallback(activeServicesCallback);
+}
+
+bool ClientCounterCallback::tryUnregister() {
+    return mImpl->tryUnregister();
+}
+
+void ClientCounterCallback::reRegister() {
+    mImpl->reRegister();
+}
+
 }  // namespace internal
 
 LazyServiceRegistrar::LazyServiceRegistrar() {
@@ -215,5 +284,18 @@
     mClientCC->forcePersist(persist);
 }
 
+void LazyServiceRegistrar::setActiveServicesCallback(const std::function<bool(bool)>&
+                                                     activeServicesCallback) {
+    mClientCC->setActiveServicesCallback(activeServicesCallback);
+}
+
+bool LazyServiceRegistrar::tryUnregister() {
+    return mClientCC->tryUnregister();
+}
+
+void LazyServiceRegistrar::reRegister() {
+    mClientCC->reRegister();
+}
+
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index ebf91f9..b46b3e8 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -387,7 +387,7 @@
     while (cur) {
         if (cur->start == start) {
             LOG_FATAL_IF(cur->free,
-                "block at offset 0x%08lX of size 0x%08lX already freed",
+                "block at offset 0x%08lX of size 0x%08X already freed",
                 cur->start*kMemoryAlign, cur->size*kMemoryAlign);
 
             // merge freed blocks together
@@ -411,7 +411,7 @@
                 }
             #endif
             LOG_FATAL_IF(!freed->free,
-                "freed block at offset 0x%08lX of size 0x%08lX is not free!",
+                "freed block at offset 0x%08lX of size 0x%08X is not free!",
                 freed->start * kMemoryAlign, freed->size * kMemoryAlign);
 
             return freed;
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e4ea60f..e1cbc19 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -49,7 +49,7 @@
     int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
     ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
     if (fd >= 0) {
-        if (mapfd(fd, size) == NO_ERROR) {
+        if (mapfd(fd, true, size) == NO_ERROR) {
             if (flags & READ_ONLY) {
                 ashmem_set_prot_region(fd, PROT_READ);
             }
@@ -70,7 +70,7 @@
     if (fd >= 0) {
         const size_t pagesize = getpagesize();
         size = ((size + pagesize-1) & ~(pagesize-1));
-        if (mapfd(fd, size) == NO_ERROR) {
+        if (mapfd(fd, false, size) == NO_ERROR) {
             mDevice = device;
         }
     }
@@ -82,7 +82,7 @@
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
-    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
+    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
 }
 
 status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
@@ -98,7 +98,7 @@
     return NO_ERROR;
 }
 
-status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
+status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
 {
     if (size == 0) {
         // try to figure out the size automatically
@@ -116,8 +116,12 @@
     }
 
     if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+        int prot = PROT_READ;
+        if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
+            prot |= PROT_WRITE;
+        }
         void* base = (uint8_t*)mmap(nullptr, size,
-                PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+                prot, MAP_SHARED, fd, offset);
         if (base == MAP_FAILED) {
             ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
                     fd, size, strerror(errno));
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a5549fc..8087443 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -41,7 +41,6 @@
 #include <binder/TextOutput.h>
 
 #include <cutils/ashmem.h>
-#include <utils/Debug.h>
 #include <utils/Flattenable.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
@@ -50,6 +49,7 @@
 
 #include <private/binder/binder_module.h>
 #include "Static.h"
+#include "Utils.h"
 
 #define LOG_REFS(...)
 //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -78,9 +78,8 @@
 // many things compile this into prebuilts on the stack
 static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
 
-static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
-static size_t gParcelGlobalAllocSize = 0;
-static size_t gParcelGlobalAllocCount = 0;
+static std::atomic<size_t> gParcelGlobalAllocCount;
+static std::atomic<size_t> gParcelGlobalAllocSize;
 
 static size_t gMaxFds = 0;
 
@@ -165,14 +164,11 @@
     ALOGE("Invalid object type 0x%08x", obj.hdr.type);
 }
 
-status_t Parcel::finishFlattenBinder(
-    const sp<IBinder>& binder, const flat_binder_object& flat)
+status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
 {
-    status_t status = writeObject(flat, false);
-    if (status != OK) return status;
-
     internal::Stability::tryMarkCompilationUnit(binder.get());
-    return writeInt32(internal::Stability::get(binder.get()));
+    auto category = internal::Stability::getCategory(binder.get());
+    return writeInt32(category.repr());
 }
 
 status_t Parcel::finishUnflattenBinder(
@@ -182,7 +178,7 @@
     status_t status = readInt32(&stability);
     if (status != OK) return status;
 
-    status = internal::Stability::set(binder.get(), stability, true /*log*/);
+    status = internal::Stability::setRepr(binder.get(), stability, true /*log*/);
     if (status != OK) return status;
 
     *out = binder;
@@ -210,7 +206,7 @@
             if (proxy == nullptr) {
                 ALOGE("null proxy");
             }
-            const int32_t handle = proxy ? proxy->handle() : 0;
+            const int32_t handle = proxy ? proxy->getPrivateAccessorForHandle().handle() : 0;
             obj.hdr.type = BINDER_TYPE_HANDLE;
             obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
             obj.handle = handle;
@@ -226,6 +222,9 @@
             if (local->isRequestingSid()) {
                 obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
             }
+            if (local->isInheritRt()) {
+                obj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;
+            }
             obj.hdr.type = BINDER_TYPE_BINDER;
             obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
             obj.cookie = reinterpret_cast<uintptr_t>(local);
@@ -238,7 +237,10 @@
 
     obj.flags |= schedBits;
 
-    return finishFlattenBinder(binder, obj);
+    status_t status = writeObject(obj, false);
+    if (status != OK) return status;
+
+    return finishFlattenBinder(binder);
 }
 
 status_t Parcel::unflattenBinder(sp<IBinder>* out) const
@@ -276,17 +278,11 @@
 }
 
 size_t Parcel::getGlobalAllocSize() {
-    pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
-    size_t size = gParcelGlobalAllocSize;
-    pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
-    return size;
+    return gParcelGlobalAllocSize.load();
 }
 
 size_t Parcel::getGlobalAllocCount() {
-    pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
-    size_t count = gParcelGlobalAllocCount;
-    pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
-    return count;
+    return gParcelGlobalAllocCount.load();
 }
 
 const uint8_t* Parcel::data() const
@@ -510,6 +506,11 @@
     return mHasFds;
 }
 
+void Parcel::markSensitive() const
+{
+    mDeallocZero = true;
+}
+
 void Parcel::updateWorkSourceRequestHeaderPosition() const {
     // Only update the request headers once. We only want to point
     // to the first headers read/written.
@@ -528,14 +529,19 @@
 // Write RPC headers.  (previously just the interface token)
 status_t Parcel::writeInterfaceToken(const String16& interface)
 {
+    return writeInterfaceToken(interface.string(), interface.size());
+}
+
+status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
     const IPCThreadState* threadState = IPCThreadState::self();
     writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
     updateWorkSourceRequestHeaderPosition();
     writeInt32(threadState->shouldPropagateWorkSource() ?
             threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
     writeInt32(kHeader);
+
     // currently the interface identification token is just its name as a string
-    return writeString16(interface);
+    return writeString16(str, len);
 }
 
 bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
@@ -763,6 +769,13 @@
     return NO_ERROR;
 }
 
+status_t Parcel::writeUtf8AsUtf16(const std::optional<std::string>& str) {
+  if (!str) {
+    return writeInt32(-1);
+  }
+  return writeUtf8AsUtf16(*str);
+}
+
 status_t Parcel::writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) {
   if (!str) {
     return writeInt32(-1);
@@ -787,6 +800,12 @@
     return writeByteVectorInternal(val.data(), val.size());
 }
 
+status_t Parcel::writeByteVector(const std::optional<std::vector<int8_t>>& val)
+{
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(val->data(), val->size());
+}
+
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val)
 {
     if (!val) return writeInt32(-1);
@@ -797,6 +816,12 @@
     return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
 }
 
+status_t Parcel::writeByteVector(const std::optional<std::vector<uint8_t>>& val)
+{
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
+}
+
 status_t Parcel::writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val)
 {
     if (!val) return writeInt32(-1);
@@ -808,6 +833,11 @@
     return writeTypedVector(val, &Parcel::writeInt32);
 }
 
+status_t Parcel::writeInt32Vector(const std::optional<std::vector<int32_t>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeInt32);
+}
+
 status_t Parcel::writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeInt32);
@@ -818,6 +848,11 @@
     return writeTypedVector(val, &Parcel::writeInt64);
 }
 
+status_t Parcel::writeInt64Vector(const std::optional<std::vector<int64_t>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeInt64);
+}
+
 status_t Parcel::writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeInt64);
@@ -828,6 +863,11 @@
     return writeTypedVector(val, &Parcel::writeUint64);
 }
 
+status_t Parcel::writeUint64Vector(const std::optional<std::vector<uint64_t>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeUint64);
+}
+
 status_t Parcel::writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeUint64);
@@ -838,6 +878,11 @@
     return writeTypedVector(val, &Parcel::writeFloat);
 }
 
+status_t Parcel::writeFloatVector(const std::optional<std::vector<float>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeFloat);
+}
+
 status_t Parcel::writeFloatVector(const std::unique_ptr<std::vector<float>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeFloat);
@@ -848,6 +893,11 @@
     return writeTypedVector(val, &Parcel::writeDouble);
 }
 
+status_t Parcel::writeDoubleVector(const std::optional<std::vector<double>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeDouble);
+}
+
 status_t Parcel::writeDoubleVector(const std::unique_ptr<std::vector<double>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeDouble);
@@ -858,6 +908,11 @@
     return writeTypedVector(val, &Parcel::writeBool);
 }
 
+status_t Parcel::writeBoolVector(const std::optional<std::vector<bool>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeBool);
+}
+
 status_t Parcel::writeBoolVector(const std::unique_ptr<std::vector<bool>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeBool);
@@ -868,6 +923,11 @@
     return writeTypedVector(val, &Parcel::writeChar);
 }
 
+status_t Parcel::writeCharVector(const std::optional<std::vector<char16_t>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeChar);
+}
+
 status_t Parcel::writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeChar);
@@ -879,12 +939,23 @@
 }
 
 status_t Parcel::writeString16Vector(
+        const std::optional<std::vector<std::optional<String16>>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeString16);
+}
+
+status_t Parcel::writeString16Vector(
         const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeString16);
 }
 
 status_t Parcel::writeUtf8VectorAsUtf16Vector(
+                        const std::optional<std::vector<std::optional<std::string>>>& val) {
+    return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
+}
+
+status_t Parcel::writeUtf8VectorAsUtf16Vector(
                         const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) {
     return writeNullableTypedVector(val, &Parcel::writeUtf8AsUtf16);
 }
@@ -1006,6 +1077,7 @@
 {
     if (str == nullptr) return writeInt32(-1);
 
+    // NOTE: Keep this logic in sync with android_os_Parcel.cpp
     status_t err = writeInt32(len);
     if (err == NO_ERROR) {
         uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char));
@@ -1019,6 +1091,15 @@
     return err;
 }
 
+status_t Parcel::writeString16(const std::optional<String16>& str)
+{
+    if (!str) {
+        return writeInt32(-1);
+    }
+
+    return writeString16(*str);
+}
+
 status_t Parcel::writeString16(const std::unique_ptr<String16>& str)
 {
     if (!str) {
@@ -1037,6 +1118,7 @@
 {
     if (str == nullptr) return writeInt32(-1);
 
+    // NOTE: Keep this logic in sync with android_os_Parcel.cpp
     status_t err = writeInt32(len);
     if (err == NO_ERROR) {
         len *= sizeof(char16_t);
@@ -1061,11 +1143,20 @@
     return writeTypedVector(val, &Parcel::writeStrongBinder);
 }
 
+status_t Parcel::writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val)
+{
+    return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
+}
+
 status_t Parcel::writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val)
 {
     return writeNullableTypedVector(val, &Parcel::writeStrongBinder);
 }
 
+status_t Parcel::readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
+}
+
 status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
     return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
 }
@@ -1164,6 +1255,10 @@
     return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
 }
 
+status_t Parcel::writeUniqueFileDescriptorVector(const std::optional<std::vector<base::unique_fd>>& val) {
+    return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
+}
+
 status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
     return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
 }
@@ -1382,6 +1477,31 @@
     goto data_sorted;
 }
 
+status_t Parcel::readVectorSizeWithCoarseBoundCheck(int32_t *size) const {
+    int32_t requestedSize;
+    const status_t status = readInt32(&requestedSize);
+    if (status != NO_ERROR) return status;
+
+    // We permit negative sizes, which indicate presence of a nullable vector,
+    // i.e. a vector embedded in std::optional, std::unique_ptr, or std::shared_ptr.
+    if (requestedSize > 0) {
+        // Check if there are fewer bytes than vector elements.
+        // A lower bound is 1 byte per element, satisfied by some enum and int8_t and uint8_t.
+        const size_t availableBytes = dataAvail();
+        if (static_cast<size_t>(requestedSize) > availableBytes) {
+            // We have a size that is greater than the number of bytes available.
+            // On bounds failure we do not 'rewind' position by 4 bytes of the size already read.
+            ALOGW("%s: rejecting out of bounds vector size (requestedSize):%d "
+                    "Parcel{dataAvail:%zu mDataSize:%zu mDataPos:%zu mDataCapacity:%zu}",
+                    __func__, requestedSize, availableBytes, mDataSize, mDataPos, mDataCapacity);
+            return BAD_VALUE;
+        }
+    }
+
+    *size = requestedSize;
+    return NO_ERROR;
+}
+
 status_t Parcel::read(void* outData, size_t len) const
 {
     if (len > INT32_MAX) {
@@ -1439,7 +1559,7 @@
 
 template<class T>
 status_t Parcel::readAligned(T *pArg) const {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(T)) <= mDataSize) {
         if (mObjectsSize > 0) {
@@ -1472,7 +1592,7 @@
 
 template<class T>
 status_t Parcel::writeAligned(T val) {
-    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
+    static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
 
     if ((mDataPos+sizeof(val)) <= mDataCapacity) {
 restart_write:
@@ -1497,6 +1617,17 @@
     return readByteVectorInternal(val, size);
 }
 
+status_t Parcel::readByteVector(std::optional<std::vector<int8_t>>* val) const {
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (!*val) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal(&**val, size);
+}
+
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const {
     size_t size;
     if (status_t status = reserveOutVector(val, &size); status != OK) return status;
@@ -1508,6 +1639,17 @@
     return readByteVectorInternal(val->get(), size);
 }
 
+status_t Parcel::readByteVector(std::optional<std::vector<uint8_t>>* val) const {
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (!*val) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null byte vector.
+        return OK;
+    }
+    return readByteVectorInternal(&**val, size);
+}
+
 status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const {
     size_t size;
     if (status_t status = reserveOutVector(val, &size); status != OK) return status;
@@ -1519,6 +1661,10 @@
     return readByteVectorInternal(val->get(), size);
 }
 
+status_t Parcel::readInt32Vector(std::optional<std::vector<int32_t>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readInt32);
+}
+
 status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const {
     return readNullableTypedVector(val, &Parcel::readInt32);
 }
@@ -1527,6 +1673,10 @@
     return readTypedVector(val, &Parcel::readInt32);
 }
 
+status_t Parcel::readInt64Vector(std::optional<std::vector<int64_t>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readInt64);
+}
+
 status_t Parcel::readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const {
     return readNullableTypedVector(val, &Parcel::readInt64);
 }
@@ -1535,6 +1685,10 @@
     return readTypedVector(val, &Parcel::readInt64);
 }
 
+status_t Parcel::readUint64Vector(std::optional<std::vector<uint64_t>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readUint64);
+}
+
 status_t Parcel::readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const {
     return readNullableTypedVector(val, &Parcel::readUint64);
 }
@@ -1543,6 +1697,10 @@
     return readTypedVector(val, &Parcel::readUint64);
 }
 
+status_t Parcel::readFloatVector(std::optional<std::vector<float>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readFloat);
+}
+
 status_t Parcel::readFloatVector(std::unique_ptr<std::vector<float>>* val) const {
     return readNullableTypedVector(val, &Parcel::readFloat);
 }
@@ -1551,6 +1709,10 @@
     return readTypedVector(val, &Parcel::readFloat);
 }
 
+status_t Parcel::readDoubleVector(std::optional<std::vector<double>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readDouble);
+}
+
 status_t Parcel::readDoubleVector(std::unique_ptr<std::vector<double>>* val) const {
     return readNullableTypedVector(val, &Parcel::readDouble);
 }
@@ -1559,10 +1721,32 @@
     return readTypedVector(val, &Parcel::readDouble);
 }
 
+status_t Parcel::readBoolVector(std::optional<std::vector<bool>>* val) const {
+    const int32_t start = dataPosition();
+    int32_t size;
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
+    val->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    val->emplace();
+
+    status = readBoolVector(&**val);
+
+    if (status != OK) {
+        val->reset();
+    }
+
+    return status;
+}
+
 status_t Parcel::readBoolVector(std::unique_ptr<std::vector<bool>>* val) const {
     const int32_t start = dataPosition();
     int32_t size;
-    status_t status = readInt32(&size);
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
     val->reset();
 
     if (status != OK || size < 0) {
@@ -1583,7 +1767,7 @@
 
 status_t Parcel::readBoolVector(std::vector<bool>* val) const {
     int32_t size;
-    status_t status = readInt32(&size);
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
 
     if (status != OK) {
         return status;
@@ -1611,6 +1795,10 @@
     return OK;
 }
 
+status_t Parcel::readCharVector(std::optional<std::vector<char16_t>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readChar);
+}
+
 status_t Parcel::readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const {
     return readNullableTypedVector(val, &Parcel::readChar);
 }
@@ -1620,6 +1808,11 @@
 }
 
 status_t Parcel::readString16Vector(
+        std::optional<std::vector<std::optional<String16>>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readString16);
+}
+
+status_t Parcel::readString16Vector(
         std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const {
     return readNullableTypedVector(val, &Parcel::readString16);
 }
@@ -1629,6 +1822,11 @@
 }
 
 status_t Parcel::readUtf8VectorFromUtf16Vector(
+        std::optional<std::vector<std::optional<std::string>>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
+}
+
+status_t Parcel::readUtf8VectorFromUtf16Vector(
         std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const {
     return readNullableTypedVector(val, &Parcel::readUtf8FromUtf16);
 }
@@ -1744,17 +1942,6 @@
 
 #endif
 
-status_t Parcel::readIntPtr(intptr_t *pArg) const
-{
-    return readAligned(pArg);
-}
-
-
-intptr_t Parcel::readIntPtr() const
-{
-    return readAligned<intptr_t>();
-}
-
 status_t Parcel::readBool(bool *pArg) const
 {
     int32_t tmp = 0;
@@ -1820,6 +2007,21 @@
     return NO_ERROR;
 }
 
+status_t Parcel::readUtf8FromUtf16(std::optional<std::string>* str) const {
+    const int32_t start = dataPosition();
+    int32_t size;
+    status_t status = readInt32(&size);
+    str->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    str->emplace();
+    return readUtf8FromUtf16(&**str);
+}
+
 status_t Parcel::readUtf8FromUtf16(std::unique_ptr<std::string>* str) const {
     const int32_t start = dataPosition();
     int32_t size;
@@ -1898,6 +2100,29 @@
     return String16();
 }
 
+status_t Parcel::readString16(std::optional<String16>* pArg) const
+{
+    const int32_t start = dataPosition();
+    int32_t size;
+    status_t status = readInt32(&size);
+    pArg->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    pArg->emplace();
+
+    status = readString16(&**pArg);
+
+    if (status != OK) {
+        pArg->reset();
+    }
+
+    return status;
+}
+
 status_t Parcel::readString16(std::unique_ptr<String16>* pArg) const
 {
     const int32_t start = dataPosition();
@@ -2103,6 +2328,10 @@
     return OK;
 }
 
+status_t Parcel::readUniqueFileDescriptorVector(std::optional<std::vector<base::unique_fd>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
+}
+
 status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
     return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
 }
@@ -2297,22 +2526,17 @@
 }
 
 void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
-    const binder_size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)
+    const binder_size_t* objects, size_t objectsCount, release_func relFunc)
 {
-    binder_size_t minOffset = 0;
-    freeDataNoInit();
-    mError = NO_ERROR;
+    freeData();
+
     mData = const_cast<uint8_t*>(data);
     mDataSize = mDataCapacity = dataSize;
-    //ALOGI("setDataReference Setting data size of %p to %lu (pid=%d)", this, mDataSize, getpid());
-    mDataPos = 0;
-    ALOGV("setDataReference Setting data pos of %p to %zu", this, mDataPos);
     mObjects = const_cast<binder_size_t*>(objects);
     mObjectsSize = mObjectsCapacity = objectsCount;
-    mNextObjectHint = 0;
-    mObjectsSorted = false;
     mOwner = relFunc;
-    mOwnerCookie = relCookie;
+
+    binder_size_t minOffset = 0;
     for (size_t i = 0; i < mObjectsSize; i++) {
         binder_size_t offset = mObjects[i];
         if (offset < minOffset) {
@@ -2413,22 +2637,17 @@
     if (mOwner) {
         LOG_ALLOC("Parcel %p: freeing other owner data", this);
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
         releaseObjects();
         if (mData) {
             LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
-            pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
-            if (mDataCapacity <= gParcelGlobalAllocSize) {
-              gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
-            } else {
-              gParcelGlobalAllocSize = 0;
+            gParcelGlobalAllocSize -= mDataCapacity;
+            gParcelGlobalAllocCount--;
+            if (mDeallocZero) {
+                zeroMemory(mData, mDataSize);
             }
-            if (gParcelGlobalAllocCount > 0) {
-              gParcelGlobalAllocCount--;
-            }
-            pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
             free(mData);
         }
         if (mObjects) free(mObjects);
@@ -2448,7 +2667,22 @@
     size_t newSize = ((mDataSize+len)*3)/2;
     return (newSize <= mDataSize)
             ? (status_t) NO_MEMORY
-            : continueWrite(newSize);
+            : continueWrite(std::max(newSize, (size_t) 128));
+}
+
+static uint8_t* reallocZeroFree(uint8_t* data, size_t oldCapacity, size_t newCapacity, bool zero) {
+    if (!zero) {
+        return (uint8_t*)realloc(data, newCapacity);
+    }
+    uint8_t* newData = (uint8_t*)malloc(newCapacity);
+    if (!newData) {
+        return nullptr;
+    }
+
+    memcpy(newData, data, std::min(oldCapacity, newCapacity));
+    zeroMemory(data, oldCapacity);
+    free(data);
+    return newData;
 }
 
 status_t Parcel::restartWrite(size_t desired)
@@ -2464,7 +2698,7 @@
         return continueWrite(desired);
     }
 
-    uint8_t* data = (uint8_t*)realloc(mData, desired);
+    uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
     if (!data && desired > mDataCapacity) {
         mError = NO_MEMORY;
         return NO_MEMORY;
@@ -2474,13 +2708,15 @@
 
     if (data || desired == 0) {
         LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
-        pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
-        gParcelGlobalAllocSize += desired;
-        gParcelGlobalAllocSize -= mDataCapacity;
+        if (mDataCapacity > desired) {
+            gParcelGlobalAllocSize -= (mDataCapacity - desired);
+        } else {
+            gParcelGlobalAllocSize += (desired - mDataCapacity);
+        }
+
         if (!mData) {
             gParcelGlobalAllocCount++;
         }
-        pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
         mData = data;
         mDataCapacity = desired;
     }
@@ -2564,14 +2800,12 @@
             memcpy(objects, mObjects, objectsSize*sizeof(binder_size_t));
         }
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
+        mOwner(this, mData, mDataSize, mObjects, mObjectsSize);
         mOwner = nullptr;
 
         LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired);
-        pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
         gParcelGlobalAllocSize += desired;
         gParcelGlobalAllocCount++;
-        pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
 
         mData = data;
         mObjects = objects;
@@ -2615,14 +2849,12 @@
 
         // We own the data, so we can just do a realloc().
         if (desired > mDataCapacity) {
-            uint8_t* data = (uint8_t*)realloc(mData, desired);
+            uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
             if (data) {
                 LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity,
                         desired);
-                pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
                 gParcelGlobalAllocSize += desired;
                 gParcelGlobalAllocSize -= mDataCapacity;
-                pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
                 mData = data;
                 mDataCapacity = desired;
             } else {
@@ -2654,10 +2886,8 @@
         }
 
         LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired);
-        pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
         gParcelGlobalAllocSize += desired;
         gParcelGlobalAllocCount++;
-        pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
 
         mData = data;
         mDataSize = mDataPos = 0;
@@ -2687,6 +2917,7 @@
     mHasFds = false;
     mFdsKnown = true;
     mAllowFds = true;
+    mDeallocZero = false;
     mOwner = nullptr;
     mOpenAshmemSize = 0;
     mWorkSourceRequestHeaderPosition = 0;
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
new file mode 100644
index 0000000..2e86b74
--- /dev/null
+++ b/libs/binder/ParcelableHolder.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ParcelableHolder.h>
+
+#define RETURN_ON_FAILURE(expr)                     \
+    do {                                            \
+        android::status_t _status = (expr);         \
+        if (_status != android::OK) return _status; \
+    } while (false)
+
+namespace android {
+namespace os {
+status_t ParcelableHolder::writeToParcel(Parcel* p) const {
+    RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability())));
+    if (this->mParcelPtr) {
+        RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize()));
+        RETURN_ON_FAILURE(p->appendFrom(this->mParcelPtr.get(), 0, this->mParcelPtr->dataSize()));
+        return OK;
+    }
+    if (this->mParcelable) {
+        size_t sizePos = p->dataPosition();
+        RETURN_ON_FAILURE(p->writeInt32(0));
+        size_t dataStartPos = p->dataPosition();
+        RETURN_ON_FAILURE(p->writeString16(this->mParcelableName));
+        this->mParcelable->writeToParcel(p);
+        size_t dataSize = p->dataPosition() - dataStartPos;
+
+        p->setDataPosition(sizePos);
+        RETURN_ON_FAILURE(p->writeInt32(dataSize));
+        p->setDataPosition(p->dataPosition() + dataSize);
+        return OK;
+    }
+
+    RETURN_ON_FAILURE(p->writeInt32(0));
+    return OK;
+}
+
+status_t ParcelableHolder::readFromParcel(const Parcel* p) {
+    this->mStability = static_cast<Stability>(p->readInt32());
+    this->mParcelable = nullptr;
+    this->mParcelableName = std::nullopt;
+    int32_t rawDataSize;
+
+    status_t status = p->readInt32(&rawDataSize);
+    if (status != android::OK || rawDataSize < 0) {
+        this->mParcelPtr = nullptr;
+        return status != android::OK ? status : BAD_VALUE;
+    }
+    if (rawDataSize == 0) {
+        if (this->mParcelPtr) {
+            this->mParcelPtr = nullptr;
+        }
+        return OK;
+    }
+
+    size_t dataSize = rawDataSize;
+
+    size_t dataStartPos = p->dataPosition();
+
+    if (dataStartPos > SIZE_MAX - dataSize) {
+        this->mParcelPtr = nullptr;
+        return BAD_VALUE;
+    }
+
+    if (!this->mParcelPtr) {
+        this->mParcelPtr = std::make_unique<Parcel>();
+    }
+    this->mParcelPtr->freeData();
+
+    status = this->mParcelPtr->appendFrom(p, dataStartPos, dataSize);
+    if (status != android::OK) {
+        this->mParcelPtr = nullptr;
+        return status;
+    }
+    p->setDataPosition(dataStartPos + dataSize);
+    return OK;
+}
+} // namespace os
+} // namespace android
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index 75a6d22..6eae5ef 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -27,7 +27,7 @@
 
 // ----------------------------------------------------------------------------
 
-ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ;
+ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache)
 
 // ----------------------------------------------------------------------------
 
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index 97a6c94..c807cfe 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -34,10 +34,22 @@
 using android::sp;
 using android::status_t;
 using android::UNEXPECTED_NULL;
+
+using android::binder::VAL_BOOLEAN;
+using android::binder::VAL_INTEGER;
+using android::binder::VAL_LONG;
+using android::binder::VAL_DOUBLE;
+using android::binder::VAL_STRING;
+using android::binder::VAL_BOOLEANARRAY;
+using android::binder::VAL_INTARRAY;
+using android::binder::VAL_LONGARRAY;
+using android::binder::VAL_DOUBLEARRAY;
+using android::binder::VAL_STRINGARRAY;
+using android::binder::VAL_PERSISTABLEBUNDLE;
+
 using std::map;
 using std::set;
 using std::vector;
-using namespace ::android::binder;
 
 enum {
     // Keep them in sync with BUNDLE_MAGIC* in frameworks/base/core/java/android/os/BaseBundle.java.
diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp
index 00d6eef..f75141e 100644
--- a/libs/binder/ProcessInfoService.cpp
+++ b/libs/binder/ProcessInfoService.cpp
@@ -99,6 +99,6 @@
     }
 }
 
-ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService);
+ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService)
 
 } // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 4b773e8..c38249e 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -32,6 +32,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <mutex>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -73,38 +74,49 @@
 
 sp<ProcessState> ProcessState::self()
 {
-    Mutex::Autolock _l(gProcessMutex);
-    if (gProcess != nullptr) {
-        return gProcess;
-    }
-    gProcess = new ProcessState(kDefaultDriver);
-    return gProcess;
+    return init(kDefaultDriver, false /*requireDefault*/);
 }
 
 sp<ProcessState> ProcessState::initWithDriver(const char* driver)
 {
-    Mutex::Autolock _l(gProcessMutex);
-    if (gProcess != nullptr) {
-        // Allow for initWithDriver to be called repeatedly with the same
-        // driver.
-        if (!strcmp(gProcess->getDriverName().c_str(), driver)) {
-            return gProcess;
-        }
-        LOG_ALWAYS_FATAL("ProcessState was already initialized.");
-    }
-
-    if (access(driver, R_OK) == -1) {
-        ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
-        driver = "/dev/binder";
-    }
-
-    gProcess = new ProcessState(driver);
-    return gProcess;
+    return init(driver, true /*requireDefault*/);
 }
 
 sp<ProcessState> ProcessState::selfOrNull()
 {
-    Mutex::Autolock _l(gProcessMutex);
+    return init(nullptr, false /*requireDefault*/);
+}
+
+sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
+{
+    [[clang::no_destroy]] static sp<ProcessState> gProcess;
+    [[clang::no_destroy]] static std::mutex gProcessMutex;
+
+    if (driver == nullptr) {
+        std::lock_guard<std::mutex> l(gProcessMutex);
+        return gProcess;
+    }
+
+    [[clang::no_destroy]] static std::once_flag gProcessOnce;
+    std::call_once(gProcessOnce, [&](){
+        if (access(driver, R_OK) == -1) {
+            ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
+            driver = "/dev/binder";
+        }
+
+        std::lock_guard<std::mutex> l(gProcessMutex);
+        gProcess = new ProcessState(driver);
+    });
+
+    if (requireDefault) {
+        // Detect if we are trying to initialize with a different driver, and
+        // consider that an error. ProcessState will only be initialized once above.
+        LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
+                            "ProcessState was already initialized with %s,"
+                            " can't initialize with %s.",
+                            gProcess->getDriverName().c_str(), driver);
+    }
+
     return gProcess;
 }
 
@@ -112,14 +124,14 @@
 {
     sp<IBinder> context = getStrongProxyForHandle(0);
 
-    if (context == nullptr) {
-       ALOGW("Not able to get context object on %s.", mDriverName.c_str());
+    if (context) {
+        // The root object is special since we get it directly from the driver, it is never
+        // written by Parcell::writeStrongBinder.
+        internal::Stability::markCompilationUnit(context.get());
+    } else {
+        ALOGW("Not able to get context object on %s.", mDriverName.c_str());
     }
 
-    // The root object is special since we get it directly from the driver, it is never
-    // written by Parcell::writeStrongBinder.
-    internal::Stability::tryMarkCompilationUnit(context.get());
-
     return context;
 }
 
@@ -132,11 +144,9 @@
     }
 }
 
-bool ProcessState::becomeContextManager(context_check_func checkFunc, void* userData)
+bool ProcessState::becomeContextManager()
 {
     AutoMutex _l(mLock);
-    mBinderContextCheckFunc = checkFunc;
-    mBinderContextUserData = userData;
 
     flat_binder_object obj {
         .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
@@ -148,13 +158,11 @@
     if (result != 0) {
         android_errorWriteLog(0x534e4554, "121035042");
 
-        int dummy = 0;
-        result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+        int unused = 0;
+        result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);
     }
 
     if (result == -1) {
-        mBinderContextCheckFunc = nullptr;
-        mBinderContextUserData = nullptr;
         ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
     }
 
@@ -196,11 +204,11 @@
 // that the handle points to. Can only be used by the servicemanager.
 //
 // Returns -1 in case of failure, otherwise the strong reference count.
-ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) {
+ssize_t ProcessState::getStrongRefCountForNode(const sp<BpBinder>& binder) {
     binder_node_info_for_ref info;
     memset(&info, 0, sizeof(binder_node_info_for_ref));
 
-    info.handle = handle;
+    info.handle = binder->getPrivateAccessorForHandle().handle();
 
     status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
 
@@ -274,9 +282,17 @@
                 // a driver API to get a handle to the context manager with
                 // proper reference counting.
 
+                IPCThreadState* ipc = IPCThreadState::self();
+
+                CallRestriction originalCallRestriction = ipc->getCallRestriction();
+                ipc->setCallRestriction(CallRestriction::NONE);
+
                 Parcel data;
-                status_t status = IPCThreadState::self()->transact(
+                status_t status = ipc->transact(
                         0, IBinder::PING_TRANSACTION, data, nullptr, 0);
+
+                ipc->setCallRestriction(originalCallRestriction);
+
                 if (status == DEAD_OBJECT)
                    return nullptr;
             }
@@ -328,6 +344,8 @@
 }
 
 status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
+    LOG_ALWAYS_FATAL_IF(mThreadPoolStarted && maxThreads < mMaxThreads,
+           "Binder threadpool cannot be shrunk after starting");
     status_t result = NO_ERROR;
     if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
         mMaxThreads = maxThreads;
@@ -381,16 +399,15 @@
     , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
     , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
     , mExecutingThreadsCount(0)
+    , mWaitingForThreads(0)
     , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
     , mStarvationStartTimeMs(0)
-    , mBinderContextCheckFunc(nullptr)
-    , mBinderContextUserData(nullptr)
     , mThreadPoolStarted(false)
     , mThreadPoolSeq(1)
     , mCallRestriction(CallRestriction::NONE)
 {
 
-// TODO(b/139016109): enforce in build system
+// TODO(b/166468760): enforce in build system
 #if defined(__ANDROID_APEX__)
     LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
 #endif
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index e1565fa..339c538 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "Stability"
+
 #include <binder/Stability.h>
 
 #include <binder/BpBinder.h>
@@ -21,92 +23,152 @@
 namespace android {
 namespace internal {
 
+// the libbinder parcel format is currently unstable
+
+// oldest version which is supported
+constexpr uint8_t kBinderWireFormatOldest = 1;
+// current version
+constexpr uint8_t kBinderWireFormatVersion = 1;
+
+Stability::Category Stability::Category::currentFromLevel(Level level) {
+    return {
+        .version = kBinderWireFormatVersion,
+        .reserved = {0},
+        .level = level,
+    };
+}
+
+std::string Stability::Category::debugString() {
+    return levelString(level) + " wire protocol version "
+        + std::to_string(version);
+}
+
 void Stability::markCompilationUnit(IBinder* binder) {
-    status_t result = set(binder, kLocalStability, true /*log*/);
+    auto stability = Category::currentFromLevel(getLocalLevel());
+    status_t result = setRepr(binder, stability.repr(), true /*log*/);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 void Stability::markVintf(IBinder* binder) {
-    status_t result = set(binder, Level::VINTF, true /*log*/);
+    auto stability = Category::currentFromLevel(Level::VINTF);
+    status_t result = setRepr(binder, stability.repr(), true /*log*/);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
-    ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str());
+    auto stability = getCategory(binder.get());
+    ALOGE("%s: stability is %s", tag.c_str(), stability.debugString().c_str());
 }
 
 void Stability::markVndk(IBinder* binder) {
-    status_t result = set(binder, Level::VENDOR, true /*log*/);
+    auto stability = Category::currentFromLevel(Level::VENDOR);
+    status_t result = setRepr(binder, stability.repr(), true /*log*/);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) {
-    return check(get(binder.get()), Level::VINTF);
+    return check(getCategory(binder.get()), Level::VINTF);
 }
 
 void Stability::tryMarkCompilationUnit(IBinder* binder) {
-    (void) set(binder, kLocalStability, false /*log*/);
+    auto stability = Category::currentFromLevel(getLocalLevel());
+    (void) setRepr(binder, stability.repr(), false /*log*/);
 }
 
-status_t Stability::set(IBinder* binder, int32_t stability, bool log) {
-    Level currentStability = get(binder);
+Stability::Level Stability::getLocalLevel() {
+#ifdef __ANDROID_VNDK__
+    #ifdef __ANDROID_APEX__
+        // TODO(b/142684679) avoid use_vendor on system APEXes
+        #if !defined(__ANDROID_APEX_COM_ANDROID_MEDIA_SWCODEC__) \
+            && !defined(__ANDROID_APEX_TEST_COM_ANDROID_MEDIA_SWCODEC__)
+        #error VNDK + APEX only defined for com.android.media.swcodec
+        #endif
+        // TODO(b/142684679) avoid use_vendor on system APEXes
+        return Level::SYSTEM;
+    #else
+        return Level::VENDOR;
+    #endif
+#else
+    // TODO(b/139325195): split up stability levels for system/APEX.
+    return Level::SYSTEM;
+#endif
+}
+
+status_t Stability::setRepr(IBinder* binder, int32_t representation, bool log) {
+    auto current = getCategory(binder);
+    auto setting = Category::fromRepr(representation);
+
+    // If we have ahold of a binder with a newer declared version, then it
+    // should support older versions, and we will simply write our parcels with
+    // the current wire parcel format.
+    if (setting.version < kBinderWireFormatOldest) {
+        // always log, because this shouldn't happen
+        ALOGE("Cannot accept binder with older binder wire protocol version "
+              "%u. Versions less than %u are unsupported.", setting.version,
+               kBinderWireFormatOldest);
+        return BAD_TYPE;
+    }
 
     // null binder is always written w/ 'UNDECLARED' stability
     if (binder == nullptr) {
-        if (stability == UNDECLARED) {
+        if (setting.level == UNDECLARED) {
             return OK;
         } else {
             if (log) {
                 ALOGE("Null binder written with stability %s.",
-                    stabilityString(stability).c_str());
+                    levelString(setting.level).c_str());
             }
             return BAD_TYPE;
         }
     }
 
-    if (!isDeclaredStability(stability)) {
+    if (!isDeclaredLevel(setting.level)) {
         if (log) {
-            ALOGE("Can only set known stability, not %d.", stability);
+            ALOGE("Can only set known stability, not %u.", setting.level);
         }
         return BAD_TYPE;
     }
 
-    if (currentStability != Level::UNDECLARED && currentStability != stability) {
+    if (current.repr() != 0 && current != setting) {
         if (log) {
-            ALOGE("Interface being set with %s but it is already marked as %s.",
-                stabilityString(stability).c_str(), stabilityString(currentStability).c_str());
+            ALOGE("Interface being set with %s but it is already marked as %s",
+                  setting.debugString().c_str(),
+                  current.debugString().c_str());
         }
         return BAD_TYPE;
     }
 
-    if (currentStability == stability) return OK;
+    if (current == setting) return OK;
 
     BBinder* local = binder->localBinder();
     if (local != nullptr) {
-        local->mStability = static_cast<int32_t>(stability);
+        local->mStability = setting.repr();
     } else {
-        binder->remoteBinder()->mStability = static_cast<int32_t>(stability);
+        binder->remoteBinder()->mStability = setting.repr();
     }
 
     return OK;
 }
 
-Stability::Level Stability::get(IBinder* binder) {
-    if (binder == nullptr) return UNDECLARED;
+Stability::Category Stability::getCategory(IBinder* binder) {
+    if (binder == nullptr) {
+        return Category::currentFromLevel(Level::UNDECLARED);
+    }
 
     BBinder* local = binder->localBinder();
     if (local != nullptr) {
-        return static_cast<Stability::Level>(local->mStability);
+        return Category::fromRepr(local->mStability);
     }
 
-    return static_cast<Stability::Level>(binder->remoteBinder()->mStability);
+    return Category::fromRepr(binder->remoteBinder()->mStability);
 }
 
-bool Stability::check(int32_t provided, Level required) {
-    bool stable = (provided & required) == required;
+bool Stability::check(Category provided, Level required) {
+    bool stable = (provided.level & required) == required;
 
-    if (!isDeclaredStability(provided) && provided != UNDECLARED) {
-        ALOGE("Unknown stability when checking interface stability %d.", provided);
+    if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) {
+        ALOGE("Unknown stability when checking interface stability %d.",
+              provided.level);
 
         stable = false;
     }
@@ -114,18 +176,18 @@
     return stable;
 }
 
-bool Stability::isDeclaredStability(int32_t stability) {
+bool Stability::isDeclaredLevel(Level stability) {
     return stability == VENDOR || stability == SYSTEM || stability == VINTF;
 }
 
-std::string Stability::stabilityString(int32_t stability) {
-    switch (stability) {
+std::string Stability::levelString(Level level) {
+    switch (level) {
         case Level::UNDECLARED: return "undeclared stability";
         case Level::VENDOR: return "vendor stability";
         case Level::SYSTEM: return "system stability";
         case Level::VINTF: return "vintf stability";
     }
-    return "unknown stability " + std::to_string(stability);
+    return "unknown stability " + std::to_string(level);
 }
 
 }  // namespace internal
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index 779ed41..565f2e2 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -33,7 +33,7 @@
 {
 public:
     LogTextOutput() : BufferedTextOutput(MULTITHREADED) { }
-    virtual ~LogTextOutput() { };
+    virtual ~LogTextOutput() { }
 
 protected:
     virtual status_t writeLines(const struct iovec& vec, size_t N)
@@ -49,7 +49,7 @@
 {
 public:
     explicit FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
-    virtual ~FdTextOutput() { };
+    virtual ~FdTextOutput() { }
 
 protected:
     virtual status_t writeLines(const struct iovec& vec, size_t N)
@@ -68,9 +68,4 @@
 TextOutput& aout(*new FdTextOutput(STDOUT_FILENO));
 TextOutput& aerr(*new FdTextOutput(STDERR_FILENO));
 
-// ------------ ProcessState.cpp
-
-Mutex& gProcessMutex = *new Mutex;
-sp<ProcessState> gProcess;
-
 }   // namespace android
diff --git a/libs/binder/Static.h b/libs/binder/Static.h
index f8e0ee5..83524e8 100644
--- a/libs/binder/Static.h
+++ b/libs/binder/Static.h
@@ -27,8 +27,4 @@
 // For TextStream.cpp
 extern Vector<int32_t> gTextBuffers;
 
-// For ProcessState.cpp
-extern Mutex& gProcessMutex;
-extern sp<ProcessState> gProcess;
-
 }   // namespace android
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 674f065..b5a078c 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -193,13 +193,15 @@
     }
 
     status_t status = parcel->writeInt32(mException);
-    if (status != OK) { return status; }
+    if (status != OK) return status;
     if (mException == EX_NONE) {
         // We have no more information to write.
         return status;
     }
     status = parcel->writeString16(String16(mMessage));
+    if (status != OK) return status;
     status = parcel->writeInt32(0); // Empty remote stack trace header
+    if (status != OK) return status;
     if (mException == EX_SERVICE_SPECIFIC) {
         status = parcel->writeInt32(mErrorCode);
     } else if (mException == EX_PARCELABLE) {
@@ -243,10 +245,5 @@
     return ret;
 }
 
-std::stringstream& operator<< (std::stringstream& stream, const Status& s) {
-    stream << s.toString8().string();
-    return stream;
-}
-
 }  // namespace binder
 }  // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 9aa7651..2e90142 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -7,12 +7,25 @@
       "name": "binderVendorDoubleLoadTest"
     },
     {
+      "name": "binderAllocationLimits"
+    },
+    {
+      "name": "binderClearBufTest"
+    },
+    {
       "name": "binderDriverInterfaceTest"
     },
     {
       "name": "binderTextOutputTest"
     },
     {
+      "name": "binderParcelTest"
+    },
+    {
+      "name": "binderParcelTest",
+      "host": true
+    },
+    {
       "name": "binderLibTest"
     },
     {
@@ -28,7 +41,33 @@
       "name": "aidl_lazy_test"
     },
     {
+      "name": "aidl_integration_test"
+    },
+    {
       "name": "libbinderthreadstateutils_test"
+    },
+    {
+      "name": "CtsOsTestCases",
+      "options": [
+        {
+          "exclude-filter": "android.os.cts.BuildTest#testSdkInt"
+        },
+        {
+          "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
+        }
+      ]
+    },
+    {
+      "name": "libbinder_rs-internal_test"
+    },
+    {
+      "name": "rustBinderTest"
+    },
+    {
+      "name": "binderRustNdkInteropTest"
+    },
+    {
+      "name": "rustBinderSerializationTest"
     }
   ]
 }
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/Utils.cpp
similarity index 72%
copy from libs/binder/fuzzer/binder.h
copy to libs/binder/Utils.cpp
index b224ef4..90a4502 100644
--- a/libs/binder/fuzzer/binder.h
+++ b/libs/binder/Utils.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
-#include <binder/Parcel.h>
-#include <vector>
+#include "Utils.h"
 
-#include "parcel_fuzzer.h"
+#include <string.h>
 
-extern std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS;
+namespace android {
+
+void zeroMemory(uint8_t* data, size_t size) {
+    memset(data, 0, size);
+}
+
+}   // namespace android
diff --git a/libs/binder/fuzzer/parcel_fuzzer.h b/libs/binder/Utils.h
similarity index 72%
copy from libs/binder/fuzzer/parcel_fuzzer.h
copy to libs/binder/Utils.h
index 10cf17c..f94b158 100644
--- a/libs/binder/fuzzer/parcel_fuzzer.h
+++ b/libs/binder/Utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,5 +14,12 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+#include <cstdint>
+#include <stddef.h>
+
+namespace android {
+
+// avoid optimizations
+void zeroMemory(uint8_t* data, size_t size);
+
+}   // namespace android
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index ff15460..ce30050 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -18,6 +18,7 @@
 
 import android.os.IClientCallback;
 import android.os.IServiceCallback;
+import android.os.ServiceDebugInfo;
 
 /**
  * Basic interface for finding and publishing system services.
@@ -99,6 +100,14 @@
     boolean isDeclared(@utf8InCpp String name);
 
     /**
+     * Returns all declared instances for a particular interface.
+     *
+     * For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo' is
+     * passed here, then ["foo"] would be returned.
+     */
+    @utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
+
+    /**
      * Request a callback when the number of clients of the service changes.
      * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
      */
@@ -108,4 +117,9 @@
      * Attempt to unregister and remove a service. Will fail if the service is still in use.
      */
     void tryUnregisterService(@utf8InCpp String name, IBinder service);
+
+    /**
+     * Get debug information for all currently registered services.
+     */
+    ServiceDebugInfo[] getServiceDebugInfo();
 }
diff --git a/libs/binder/aidl/android/os/ServiceDebugInfo.aidl b/libs/binder/aidl/android/os/ServiceDebugInfo.aidl
new file mode 100644
index 0000000..b95d222
--- /dev/null
+++ b/libs/binder/aidl/android/os/ServiceDebugInfo.aidl
@@ -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.
+ */
+
+package android.os;
+
+/**
+ * Debug information associated with a registered service
+ * @hide
+ */
+parcelable ServiceDebugInfo {
+    /**
+     * Service name (see IServiceManager.addService/checkService/getService)
+     */
+    @utf8InCpp String name;
+    /**
+     * PID of service at the time of registration (may no longer be valid).
+     */
+    int debugPid;
+}
diff --git a/libs/binder/fuzzer/main.cpp b/libs/binder/fuzzer/main.cpp
deleted file mode 100644
index 6657edb..0000000
--- a/libs/binder/fuzzer/main.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2019 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 FUZZ_LOG_TAG "main"
-
-#include "binder.h"
-#include "binder_ndk.h"
-#include "hwbinder.h"
-#include "util.h"
-
-#include <android-base/logging.h>
-
-#include <cstdlib>
-#include <ctime>
-
-template <typename P>
-void doFuzz(
-        const std::vector<ParcelRead<P>>& reads,
-        const std::vector<uint8_t>& input,
-        const std::vector<uint8_t>& instructions) {
-
-    P p;
-    p.setData(input.data(), input.size());
-
-    // since we are only using a byte to index
-    CHECK(reads.size() <= 255) << reads.size();
-
-    for (size_t i = 0; i < instructions.size() - 1; i += 2) {
-        uint8_t a = instructions[i];
-        uint8_t readIdx = a % reads.size();
-
-        uint8_t b = instructions[i + 1];
-
-        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
-                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
-                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
-                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
-                   << " cap: " << p.dataCapacity();
-
-        reads[readIdx](p, b);
-    }
-}
-
-void fuzz(uint8_t options, const std::vector<uint8_t>& input, const std::vector<uint8_t>& instructions) {
-    uint8_t parcelType = options & 0x3;
-
-    switch (parcelType) {
-        case 0x0:
-            doFuzz<::android::hardware::Parcel>(HWBINDER_PARCEL_READ_FUNCTIONS, input,
-                                                instructions);
-            break;
-        case 0x1:
-            doFuzz<::android::Parcel>(BINDER_PARCEL_READ_FUNCTIONS, input, instructions);
-            break;
-        case 0x2:
-            doFuzz<NdkParcelAdapter>(BINDER_NDK_PARCEL_READ_FUNCTIONS, input, instructions);
-            break;
-        case 0x3:
-            /*reserved for future use*/
-            break;
-        default:
-            LOG_ALWAYS_FATAL("unknown parcel type %d", static_cast<int>(parcelType));
-    }
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    if (size <= 1) return 0;  // no use
-
-    // avoid timeouts, see b/142617274, b/142473153
-    if (size > 50000) return 0;
-
-    uint8_t options = *data;
-    data++;
-    size--;
-
-    // TODO: generate 'objects' data
-
-    // data to fill out parcel
-    size_t inputLen = size / 2;
-    std::vector<uint8_t> input(data, data + inputLen);
-    data += inputLen;
-    size -= inputLen;
-
-    // data to use to determine what to do
-    size_t instructionLen = size;
-    std::vector<uint8_t> instructions(data, data + instructionLen);
-    data += instructionLen;
-    size -= instructionLen;
-
-    CHECK(size == 0) << "size: " << size;
-
-    FUZZ_LOG() << "options: " << (int)options << " inputLen: " << inputLen << " instructionLen: " << instructionLen;
-    FUZZ_LOG() << "input: " << hexString(input);
-    FUZZ_LOG() << "instructions: " << hexString(instructions);
-
-    fuzz(options, input, instructions);
-    return 0;
-}
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 9108e31..b90dc86 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_ACTIVITY_MANAGER_H
-#define ANDROID_ACTIVITY_MANAGER_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -94,5 +93,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_ACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index d93935a..35c697e 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_APP_OPS_MANAGER_H
-#define ANDROID_APP_OPS_MANAGER_H
+#pragma once
 
 #include <binder/IAppOpsService.h>
 
 #include <utils/threads.h>
 
+#include <optional>
+
 #ifdef __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif
@@ -147,18 +148,18 @@
     //              const String16&) instead
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
-            const std::unique_ptr<String16>& attributionTag, const String16& message);
+            const std::optional<String16>& attributionTag, const String16& message);
     // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&,
     //              const String16&) instead
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
             bool startIfModeDefault);
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
-            bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
+            bool startIfModeDefault, const std::optional<String16>& attributionTag,
             const String16& message);
     // @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage,
-            const std::unique_ptr<String16>& attributionTag);
+            const std::optional<String16>& attributionTag);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
     void stopWatchingMode(const sp<IAppOpsCallback>& callback);
@@ -177,5 +178,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 4cf0515..7079544 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BINDER_H
-#define ANDROID_BINDER_H
+#pragma once
 
 #include <atomic>
 #include <stdint.h>
@@ -84,13 +83,15 @@
     // Appropriate values are:
     // SCHED_NORMAL: -20 <= priority <= 19
     // SCHED_RR/SCHED_FIFO: 1 <= priority <= 99
-    __attribute__((weak))
     void                setMinSchedulerPolicy(int policy, int priority);
-    __attribute__((weak))
     int                 getMinSchedulerPolicy();
-    __attribute__((weak))
     int                 getMinSchedulerPriority();
 
+    // Whether realtime scheduling policies are inherited.
+    bool                isInheritRt();
+    // This must be called before the object is sent to another process. Not thread safe.
+    void                setInheritRt(bool inheritRt);
+
     pid_t               getDebugPid();
 
 protected:
@@ -145,5 +146,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_BINDER_H
diff --git a/libs/binder/include/binder/BinderService.h b/libs/binder/include/binder/BinderService.h
index c17ae6f..5776f3c 100644
--- a/libs/binder/include/binder/BinderService.h
+++ b/libs/binder/include/binder/BinderService.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BINDER_SERVICE_H
-#define ANDROID_BINDER_SERVICE_H
+#pragma once
 
 #include <stdint.h>
 
@@ -64,4 +63,3 @@
 
 } // namespace android
 // ---------------------------------------------------------------------------
-#endif // ANDROID_BINDER_SERVICE_H
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 8e871b8..22300ac 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BPBINDER_H
-#define ANDROID_BPBINDER_H
+#pragma once
 
 #include <binder/IBinder.h>
 #include <utils/KeyedVector.h>
@@ -29,7 +28,8 @@
 
 namespace internal {
 class Stability;
-};
+}
+class ProcessState;
 
 using binder_proxy_limit_callback = void(*)(int);
 
@@ -38,8 +38,6 @@
 public:
     static BpBinder*    create(int32_t handle);
 
-    int32_t             handle() const;
-
     virtual const String16&    getInterfaceDescriptor() const;
     virtual bool        isBinderAlive() const;
     virtual status_t    pingBinder();
@@ -110,19 +108,34 @@
         KeyedVector<const void*, entry_t> mObjects;
     };
 
-protected:
+    class PrivateAccessorForHandle {
+    private:
+        friend BpBinder;
+        friend ::android::Parcel;
+        friend ::android::ProcessState;
+        explicit PrivateAccessorForHandle(const BpBinder* binder) : mBinder(binder) {}
+        int32_t handle() const { return mBinder->handle(); }
+        const BpBinder* mBinder;
+    };
+    const PrivateAccessorForHandle getPrivateAccessorForHandle() const {
+        return PrivateAccessorForHandle(this);
+    }
+
+private:
+    friend PrivateAccessorForHandle;
+
+    int32_t             handle() const;
                         BpBinder(int32_t handle,int32_t trackedUid);
     virtual             ~BpBinder();
     virtual void        onFirstRef();
     virtual void        onLastStrongRef(const void* id);
     virtual bool        onIncStrongAttempted(uint32_t flags, const void* id);
 
-private:
-    const   int32_t             mHandle;
-
     friend ::android::internal::Stability;
             int32_t             mStability;
 
+    const   int32_t             mHandle;
+
     struct Obituary {
         wp<DeathRecipient> recipient;
         void* cookie;
@@ -137,7 +150,6 @@
             volatile int32_t    mObitsSent;
             Vector<Obituary>*   mObituaries;
             ObjectManager       mObjects;
-            Parcel*             mConstantData;
     mutable String16            mDescriptorCache;
             int32_t             mTrackedUid;
 
@@ -154,5 +166,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_BPBINDER_H
diff --git a/libs/binder/include/binder/Debug.h b/libs/binder/include/binder/Debug.h
index 324e5c1..ac71e00 100644
--- a/libs/binder/include/binder/Debug.h
+++ b/libs/binder/include/binder/Debug.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_BINDER_DEBUG_H
-#define ANDROID_BINDER_DEBUG_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/cdefs.h>
@@ -45,5 +44,3 @@
 
 // ---------------------------------------------------------------------------
 } // namespace android
-
-#endif // ANDROID_BINDER_DEBUG_H
diff --git a/libs/binder/include/binder/Enums.h b/libs/binder/include/binder/Enums.h
index aec6f70..c6803bd 100644
--- a/libs/binder/include/binder/Enums.h
+++ b/libs/binder/include/binder/Enums.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #pragma once
 
 #include <iterator>
@@ -38,4 +39,4 @@
     constexpr auto end() const { return std::end(internal::enum_values<EnumType>); }
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index e0248f6..fde56a0 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IACTIVITY_MANAGER_H
-#define ANDROID_IACTIVITY_MANAGER_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -56,5 +55,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_IACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h
index 7664260..eb76f57 100644
--- a/libs/binder/include/binder/IAppOpsCallback.h
+++ b/libs/binder/include/binder/IAppOpsCallback.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IAPP_OPS_CALLBACK_H
-#define ANDROID_IAPP_OPS_CALLBACK_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -57,6 +55,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_IAPP_OPS_CALLBACK_H
-
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 1ffb8de..b0719d4 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IAPP_OPS_SERVICE_H
-#define ANDROID_IAPP_OPS_SERVICE_H
+#pragma once
 
 #include <binder/IAppOpsCallback.h>
 #include <binder/IInterface.h>
 
+#include <optional>
+
 #ifdef __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif
@@ -36,13 +36,13 @@
 
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
-            const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
+            const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
             const String16& message) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& attributionTag,
+            const String16& packageName, const std::optional<String16>& attributionTag,
             bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0;
     virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
-            const String16& packageName, const std::unique_ptr<String16>& attributionTag) = 0;
+            const String16& packageName, const std::optional<String16>& attributionTag) = 0;
     virtual void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback) = 0;
     virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
@@ -87,5 +87,3 @@
 // ----------------------------------------------------------------------
 
 } // namespace android
-
-#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h
index b786f89..6defc7f 100644
--- a/libs/binder/include/binder/IBatteryStats.h
+++ b/libs/binder/include/binder/IBatteryStats.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IBATTERYSTATS_H
-#define ANDROID_IBATTERYSTATS_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -82,5 +81,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_IBATTERYSTATS_H
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 64604b7..c8fb448 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IBINDER_H
-#define ANDROID_IBINDER_H
+#pragma once
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -64,6 +63,10 @@
         // Corresponds to TF_ONE_WAY -- an asynchronous call.
         FLAG_ONEWAY             = 0x00000001,
 
+        // Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call
+        // is made
+        FLAG_CLEAR_BUF          = 0x00000020,
+
         // Private userspace flag for transaction which is being requested from
         // a vendor context.
         FLAG_PRIVATE_VENDOR     = 0x10000000,
@@ -173,6 +176,10 @@
      * The @a cookie is optional -- if non-NULL, it should be a
      * memory address that you own (that is, you know it is unique).
      *
+     * @note When all references to the binder being linked to are dropped, the
+     * recipient is automatically unlinked. So, you must hold onto a binder in
+     * order to receive death notifications about it.
+     *
      * @note You will only receive death notifications for remote binders,
      * as local binders by definition can't die without you dying as well.
      * Trying to use this function on a local binder will result in an
@@ -249,5 +256,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_IBINDER_H
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 7116154..f4a21dd 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IINTERFACE_H
-#define ANDROID_IINTERFACE_H
+#pragma once
 
 #include <binder/Binder.h>
 
@@ -335,5 +333,3 @@
 
 } // namespace internal
 } // namespace android
-
-#endif // ANDROID_IINTERFACE_H
diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h
index da2b7cf..f92d557 100644
--- a/libs/binder/include/binder/IMediaResourceMonitor.h
+++ b/libs/binder/include/binder/IMediaResourceMonitor.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_I_MEDIA_RESOURCE_MONITOR_H
-#define ANDROID_I_MEDIA_RESOURCE_MONITOR_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -46,6 +45,7 @@
 
 class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> {
 public:
+    // NOLINTNEXTLINE(google-default-arguments)
     virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
             uint32_t flags = 0);
 };
@@ -57,5 +57,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_I_MEDIA_RESOURCE_MONITOR_H
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 1a36eb0..d8b7ec1 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IMEMORY_H
-#define ANDROID_IMEMORY_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -124,5 +123,3 @@
 // ----------------------------------------------------------------------------
 
 } // namespace android
-
-#endif // ANDROID_IMEMORY_H
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 8ac7165..0183324 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IPC_THREAD_STATE_H
-#define ANDROID_IPC_THREAD_STATE_H
+#pragma once
 
 #include <utils/Errors.h>
 #include <binder/Parcel.h>
@@ -32,6 +31,8 @@
 class IPCThreadState
 {
 public:
+    using CallRestriction = ProcessState::CallRestriction;
+
     static  IPCThreadState*     self();
     static  IPCThreadState*     selfOrNull();  // self(), but won't instantiate
 
@@ -47,23 +48,37 @@
     // binder transactions to be processed.
     //
     // returns: 0 in case of success, a value < 0 in case of error
-    __attribute__((weak))
     static  status_t            freeze(pid_t pid, bool enabled, uint32_t timeout_ms);
 
     // Provide information about the state of a frozen process
-    __attribute__((weak))
     static  status_t            getProcessFreezeInfo(pid_t pid, bool *sync_received,
                                                     bool *async_received);
             sp<ProcessState>    process();
             
             status_t            clearLastError();
 
+            /**
+             * Returns the PID of the process which has made the current binder
+             * call. If not in a binder call, this will return getpid. If the
+             * call is oneway, this will return 0.
+             */
             pid_t               getCallingPid() const;
-            // nullptr if unavailable
-            //
-            // this can't be restored once it's cleared, and it does not return the
-            // context of the current process when not in a binder call.
+
+            /**
+             * Returns the SELinux security identifier of the process which has
+             * made the current binder call. If not in a binder call this will
+             * return nullptr. If this isn't requested with
+             * Binder::setRequestingSid, it will also return nullptr.
+             *
+             * This can't be restored once it's cleared, and it does not return the
+             * context of the current process when not in a binder call.
+             */
             const char*         getCallingSid() const;
+
+            /**
+             * Returns the UID of the process which has made the current binder
+             * call. If not in a binder call, this will return 0.
+             */
             uid_t               getCallingUid() const;
 
             void                setStrictModePolicy(int32_t policy);
@@ -85,13 +100,17 @@
             void                setLastTransactionBinderFlags(int32_t flags);
             int32_t             getLastTransactionBinderFlags() const;
 
+            void                setCallRestriction(CallRestriction restriction);
+            CallRestriction     getCallRestriction() const;
+
             int64_t             clearCallingIdentity();
             // Restores PID/UID (not SID)
             void                restoreCallingIdentity(int64_t token);
-            
-            int                 setupPolling(int* fd);
+
+            status_t            setupPolling(int* fd);
             status_t            handlePolledCommands();
             void                flushCommands();
+            bool                flushIfNeeded();
 
             void                joinThreadPool(bool isMain = true);
             
@@ -128,7 +147,7 @@
             void                blockUntilThreadAvailable();
 
             // Service manager registration
-            void                setTheContextObject(sp<BBinder> obj);
+            void                setTheContextObject(const sp<BBinder>& obj);
 
             // WARNING: DO NOT USE THIS API
             //
@@ -143,7 +162,6 @@
             // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
             // side.
             static const int32_t kUnsetWorkSource = -1;
-
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -168,9 +186,8 @@
     static  void                threadDestructor(void *st);
     static  void                freeBuffer(Parcel* parcel,
                                            const uint8_t* data, size_t dataSize,
-                                           const binder_size_t* objects, size_t objectsSize,
-                                           void* cookie);
-    
+                                           const binder_size_t* objects, size_t objectsSize);
+
     const   sp<ProcessState>    mProcess;
             Vector<BBinder*>    mPendingStrongDerefs;
             Vector<RefBase::weakref_type*> mPendingWeakDerefs;
@@ -188,14 +205,12 @@
             int32_t             mWorkSource;
             // Whether the work source should be propagated.
             bool                mPropagateWorkSource;
+            bool                mIsLooper;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
-
-            ProcessState::CallRestriction mCallRestriction;
+            CallRestriction     mCallRestriction;
 };
 
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 4b66df8..a4f93d9 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IPERMISSION_CONTROLLER_H
-#define ANDROID_IPERMISSION_CONTROLLER_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -70,6 +68,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_IPERMISSION_CONTROLLER_H
-
diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include/binder/IProcessInfoService.h
index ca30ad3..622f231 100644
--- a/libs/binder/include/binder/IProcessInfoService.h
+++ b/libs/binder/include/binder/IProcessInfoService.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H
-#define ANDROID_I_PROCESS_INFO_SERVICE_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -51,5 +50,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_I_PROCESS_INFO_SERVICE_H
diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h
index 70e99e7..5434445 100644
--- a/libs/binder/include/binder/IResultReceiver.h
+++ b/libs/binder/include/binder/IResultReceiver.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IRESULT_RECEIVER_H
-#define ANDROID_IRESULT_RECEIVER_H
+#pragma once
 
 #include <binder/IInterface.h>
 
@@ -51,6 +49,3 @@
 // ----------------------------------------------------------------------
 
 } // namespace android
-
-#endif // ANDROID_IRESULT_RECEIVER_H
-
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 1d520c1..5f0d056 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_ISERVICE_MANAGER_H
-#define ANDROID_ISERVICE_MANAGER_H
+#pragma once
 
 #include <binder/IInterface.h>
 #include <utils/Vector.h>
@@ -96,6 +94,11 @@
      * service.
      */
     virtual bool isDeclared(const String16& name) = 0;
+
+    /**
+     * Get all instances of a service as declared in the VINTF manifest
+     */
+    virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
@@ -159,6 +162,3 @@
 bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
 
 } // namespace android
-
-#endif // ANDROID_ISERVICE_MANAGER_H
-
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index b7ab6ea..6d3fe4a 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_ISHELL_CALLBACK_H
-#define ANDROID_ISHELL_CALLBACK_H
+#pragma once
 
 #include <binder/IInterface.h>
 
@@ -27,7 +25,7 @@
 class IShellCallback : public IInterface
 {
 public:
-    DECLARE_META_INTERFACE(ShellCallback);
+    DECLARE_META_INTERFACE(ShellCallback)
 
     virtual int openFile(const String16& path, const String16& seLinuxContext,
             const String16& mode) = 0;
@@ -52,6 +50,3 @@
 // ----------------------------------------------------------------------
 
 } // namespace android
-
-#endif // ANDROID_ISHELL_CALLBACK_H
-
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
index d070390..9291c0b 100644
--- a/libs/binder/include/binder/IUidObserver.h
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-//
-#ifndef ANDROID_IUID_OBSERVER_H
-#define ANDROID_IUID_OBSERVER_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -64,5 +62,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_IUID_OBSERVER_H
diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h
index c7e7a50..a8faa3f 100644
--- a/libs/binder/include/binder/IpPrefix.h
+++ b/libs/binder/include/binder/IpPrefix.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_IP_PREFIX_H
-#define ANDROID_IP_PREFIX_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -74,8 +73,8 @@
 private:
     union InternalUnion {
         InternalUnion() = default;
-        explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { };
-        explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { };
+        explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { }
+        explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { }
         struct in6_addr mIn6Addr;
         struct in_addr mInAddr;
     } mUnion;
@@ -90,5 +89,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif  // ANDROID_IP_PREFIX_H
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 6d711bc..9659732 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <functional>
+
 #include <binder/IServiceManager.h>
 #include <binder/Status.h>
 #include <utils/StrongPointer.h>
@@ -26,7 +28,19 @@
 class ClientCounterCallback;
 }  // namespace internal
 
-/** Exits when all services registered through this object have 0 clients */
+/**
+ * Exits when all services registered through this object have 0 clients
+ *
+ * In order to use this class, it's expected that your service:
+ * - registers all services in the process with this API
+ * - configures services as oneshot in init .rc files
+ * - configures services as disabled in init.rc files, unless a client is
+ *   guaranteed early in boot, in which case, forcePersist should also be used
+ *   to avoid races.
+ * - uses 'interface' declarations in init .rc files
+ *
+ * For more information on init .rc configuration, see system/core/init/README.md
+ **/
 class LazyServiceRegistrar {
    public:
      static LazyServiceRegistrar& getInstance();
@@ -41,10 +55,43 @@
       */
      void forcePersist(bool persist);
 
+     /**
+      * Set a callback that is invoked when the active service count (i.e. services with clients)
+      * registered with this process drops to zero (or becomes nonzero).
+      * The callback takes a boolean argument, which is 'true' if there is
+      * at least one service with clients.
+      *
+      * Callback return value:
+      * - false: Default behavior for lazy services (shut down the process if there
+      *          are no clients).
+      * - true:  Don't shut down the process even if there are no clients.
+      *
+      * This callback gives a chance to:
+      * 1 - Perform some additional operations before exiting;
+      * 2 - Prevent the process from exiting by returning "true" from the
+      *     callback.
+      *
+      * This method should be called before 'registerService' to avoid races.
+      */
+     void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
+
+    /**
+      * Try to unregister all services previously registered with 'registerService'.
+      * Returns 'true' if successful.
+      */
+     bool tryUnregister();
+
+     /**
+      * Re-register services that were unregistered by 'tryUnregister'.
+      * This method should be called in the case 'tryUnregister' fails
+      * (and should be called on the same thread).
+      */
+     void reRegister();
+
    private:
      std::shared_ptr<internal::ClientCounterCallback> mClientCC;
      LazyServiceRegistrar();
 };
 
 }  // namespace binder
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/libs/binder/include/binder/MemoryBase.h b/libs/binder/include/binder/MemoryBase.h
index 4dd3638..61a029c 100644
--- a/libs/binder/include/binder/MemoryBase.h
+++ b/libs/binder/include/binder/MemoryBase.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MEMORY_BASE_H
-#define ANDROID_MEMORY_BASE_H
+#pragma once
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -47,5 +46,3 @@
 
 // ---------------------------------------------------------------------------
 } // namespace android
-
-#endif // ANDROID_MEMORY_BASE_H
diff --git a/libs/binder/include/binder/MemoryDealer.h b/libs/binder/include/binder/MemoryDealer.h
index 6c1c412..e727772 100644
--- a/libs/binder/include/binder/MemoryDealer.h
+++ b/libs/binder/include/binder/MemoryDealer.h
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MEMORY_DEALER_H
-#define ANDROID_MEMORY_DEALER_H
-
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -60,5 +58,3 @@
 
 // ----------------------------------------------------------------------------
 } // namespace android
-
-#endif // ANDROID_MEMORY_DEALER_H
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 3fccddc..dd76943 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_MEMORY_HEAP_BASE_H
-#define ANDROID_MEMORY_HEAP_BASE_H
+#pragma once
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -51,34 +50,28 @@
 
     /*
      * maps memory from ashmem, with the given name for debugging
+     * if the READ_ONLY flag is set, the memory will be writeable by the calling process,
+     * but not by others. this is NOT the case with the other ctors.
      */
     explicit MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = nullptr);
 
     virtual ~MemoryHeapBase();
 
     /* implement IMemoryHeap interface */
-    virtual int         getHeapID() const;
+    int         getHeapID() const override;
 
     /* virtual address of the heap. returns MAP_FAILED in case of error */
-    virtual void*       getBase() const;
+    void*       getBase() const override;
 
-    virtual size_t      getSize() const;
-    virtual uint32_t    getFlags() const;
-            off_t       getOffset() const override;
+    size_t      getSize() const override;
+    uint32_t    getFlags() const override;
+    off_t       getOffset() const override;
 
     const char*         getDevice() const;
 
     /* this closes this heap -- use carefully */
     void dispose();
 
-    /* this is only needed as a workaround, use only if you know
-     * what you are doing */
-    status_t setDevice(const char* device) {
-        if (mDevice == nullptr)
-            mDevice = device;
-        return mDevice ? NO_ERROR : ALREADY_EXISTS;
-    }
-
 protected:
             MemoryHeapBase();
     // init() takes ownership of fd
@@ -86,7 +79,7 @@
             int flags = 0, const char* device = nullptr);
 
 private:
-    status_t mapfd(int fd, size_t size, off_t offset = 0);
+    status_t mapfd(int fd, bool writeableByCaller, size_t size, off_t offset = 0);
 
     int         mFD;
     size_t      mSize;
@@ -99,5 +92,3 @@
 
 // ---------------------------------------------------------------------------
 } // namespace android
-
-#endif // ANDROID_MEMORY_HEAP_BASE_H
diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h
deleted file mode 100644
index b605bd3..0000000
--- a/libs/binder/include/binder/Nullable.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <memory>
-#include <utility>
-
-namespace android {
-
-namespace aidl {
-
-// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr
-// usage:
-//     nullable<Foo> a;
-//     nullable<Foo> b = make_nullable<Foo>(...);
-//     auto c = make_nullable<Foo>(...);
-//     c.reset();
-//     c = make_nullable<Foo>(...);
-//     c = std::move(a);
-
-template <typename T>
-using nullable = std::unique_ptr<T>;
-
-template <typename T, typename... Args>
-inline nullable<T> make_nullable(Args&&... args) {
-    return std::make_unique<T>(std::forward<Args>(args)...);
-}
-
-} // namespace aidl
-
-} // namespace android
\ No newline at end of file
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index c1f64fb..54c49e4 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PARCEL_H
-#define ANDROID_PARCEL_H
+#pragma once
 
 #include <map> // for legacy reasons
 #include <string>
@@ -34,18 +33,20 @@
 #include <binder/Parcelable.h>
 
 #ifdef BINDER_IPC_32BIT
+//NOLINTNEXTLINE(google-runtime-int) b/173188702
 typedef unsigned int binder_size_t;
 #else
+//NOLINTNEXTLINE(google-runtime-int) b/173188702
 typedef unsigned long long binder_size_t;
 #endif
 
+struct flat_binder_object;
 
 // ---------------------------------------------------------------------------
 namespace android {
 
 template <typename T> class Flattenable;
 template <typename T> class LightFlattenable;
-struct flat_binder_object;
 class IBinder;
 class IPCThreadState;
 class ProcessState;
@@ -84,8 +85,16 @@
 
     bool                hasFileDescriptors() const;
 
+    // Zeros data when reallocating. Other mitigations may be added
+    // in the future.
+    //
+    // WARNING: some read methods may make additional copies of data.
+    // In order to verify this, heap dumps should be used.
+    void                markSensitive() const;
+
     // Writes the RPC header.
     status_t            writeInterfaceToken(const String16& interface);
+    status_t            writeInterfaceToken(const char16_t* str, size_t len);
 
     // Parses the RPC header, returning true if the interface name
     // in the header matches the expected interface from the caller.
@@ -121,7 +130,8 @@
     status_t            writeString8(const String8& str);
     status_t            writeString8(const char* str, size_t len);
     status_t            writeString16(const String16& str);
-    status_t            writeString16(const std::unique_ptr<String16>& str);
+    status_t            writeString16(const std::optional<String16>& str);
+    status_t            writeString16(const std::unique_ptr<String16>& str) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeString16(const char16_t* str, size_t len);
     status_t            writeStrongBinder(const sp<IBinder>& val);
     status_t            writeInt32Array(size_t len, const int32_t *val);
@@ -132,34 +142,49 @@
 
     // Take a UTF8 encoded string, convert to UTF16, write it to the parcel.
     status_t            writeUtf8AsUtf16(const std::string& str);
-    status_t            writeUtf8AsUtf16(const std::unique_ptr<std::string>& str);
+    status_t            writeUtf8AsUtf16(const std::optional<std::string>& str);
+    status_t            writeUtf8AsUtf16(const std::unique_ptr<std::string>& str) __attribute__((deprecated("use std::optional version instead")));
 
-    status_t            writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val);
+    status_t            writeByteVector(const std::optional<std::vector<int8_t>>& val);
+    status_t            writeByteVector(const std::unique_ptr<std::vector<int8_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeByteVector(const std::vector<int8_t>& val);
-    status_t            writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val);
+    status_t            writeByteVector(const std::optional<std::vector<uint8_t>>& val);
+    status_t            writeByteVector(const std::unique_ptr<std::vector<uint8_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeByteVector(const std::vector<uint8_t>& val);
-    status_t            writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val);
+    status_t            writeInt32Vector(const std::optional<std::vector<int32_t>>& val);
+    status_t            writeInt32Vector(const std::unique_ptr<std::vector<int32_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeInt32Vector(const std::vector<int32_t>& val);
-    status_t            writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val);
+    status_t            writeInt64Vector(const std::optional<std::vector<int64_t>>& val);
+    status_t            writeInt64Vector(const std::unique_ptr<std::vector<int64_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeInt64Vector(const std::vector<int64_t>& val);
-    status_t            writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val);
+    status_t            writeUint64Vector(const std::optional<std::vector<uint64_t>>& val);
+    status_t            writeUint64Vector(const std::unique_ptr<std::vector<uint64_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeUint64Vector(const std::vector<uint64_t>& val);
-    status_t            writeFloatVector(const std::unique_ptr<std::vector<float>>& val);
+    status_t            writeFloatVector(const std::optional<std::vector<float>>& val);
+    status_t            writeFloatVector(const std::unique_ptr<std::vector<float>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeFloatVector(const std::vector<float>& val);
-    status_t            writeDoubleVector(const std::unique_ptr<std::vector<double>>& val);
+    status_t            writeDoubleVector(const std::optional<std::vector<double>>& val);
+    status_t            writeDoubleVector(const std::unique_ptr<std::vector<double>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeDoubleVector(const std::vector<double>& val);
-    status_t            writeBoolVector(const std::unique_ptr<std::vector<bool>>& val);
+    status_t            writeBoolVector(const std::optional<std::vector<bool>>& val);
+    status_t            writeBoolVector(const std::unique_ptr<std::vector<bool>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeBoolVector(const std::vector<bool>& val);
-    status_t            writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val);
+    status_t            writeCharVector(const std::optional<std::vector<char16_t>>& val);
+    status_t            writeCharVector(const std::unique_ptr<std::vector<char16_t>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeCharVector(const std::vector<char16_t>& val);
     status_t            writeString16Vector(
-                            const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val);
+                            const std::optional<std::vector<std::optional<String16>>>& val);
+    status_t            writeString16Vector(
+                            const std::unique_ptr<std::vector<std::unique_ptr<String16>>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeString16Vector(const std::vector<String16>& val);
     status_t            writeUtf8VectorAsUtf16Vector(
-                            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val);
+                            const std::optional<std::vector<std::optional<std::string>>>& val);
+    status_t            writeUtf8VectorAsUtf16Vector(
+                            const std::unique_ptr<std::vector<std::unique_ptr<std::string>>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeUtf8VectorAsUtf16Vector(const std::vector<std::string>& val);
 
-    status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val);
+    status_t            writeStrongBinderVector(const std::optional<std::vector<sp<IBinder>>>& val);
+    status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
 
     // Write an Enum vector with underlying type int8_t.
@@ -167,22 +192,32 @@
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            writeEnumVector(const std::vector<T>& val);
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
     // Write an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            writeEnumVector(const std::vector<T>& val);
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val);
+    status_t            writeEnumVector(const std::optional<std::vector<T>>& val);
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
 
     template<typename T>
-    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val);
+    status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val);
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val);
+    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    template<typename T>
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")));
+    template<typename T>
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
     template<typename T>
     status_t            writeParcelableVector(const std::vector<T>& val);
 
     template<typename T>
-    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable);
+    status_t            writeNullableParcelable(const std::optional<T>& parcelable);
+    template<typename T>
+    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")));
 
     status_t            writeParcelable(const Parcelable& parcelable);
 
@@ -195,7 +230,9 @@
     template<typename T>
     status_t            writeVectorSize(const std::vector<T>& val);
     template<typename T>
-    status_t            writeVectorSize(const std::unique_ptr<std::vector<T>>& val);
+    status_t            writeVectorSize(const std::optional<std::vector<T>>& val);
+    template<typename T>
+    status_t            writeVectorSize(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")));
 
     // Place a native_handle into the parcel (the native_handle's file-
     // descriptors are dup'ed, so it is safe to delete the native_handle
@@ -230,7 +267,9 @@
     // Place a vector of file desciptors into the parcel. Each descriptor is
     // dup'd as in writeDupFileDescriptor
     status_t            writeUniqueFileDescriptorVector(
-                            const std::unique_ptr<std::vector<base::unique_fd>>& val);
+                            const std::optional<std::vector<base::unique_fd>>& val);
+    status_t            writeUniqueFileDescriptorVector(
+                            const std::unique_ptr<std::vector<base::unique_fd>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeUniqueFileDescriptorVector(
                             const std::vector<base::unique_fd>& val);
 
@@ -268,8 +307,6 @@
     status_t            readFloat(float *pArg) const;
     double              readDouble() const;
     status_t            readDouble(double *pArg) const;
-    intptr_t            readIntPtr() const;
-    status_t            readIntPtr(intptr_t *pArg) const;
     bool                readBool() const;
     status_t            readBool(bool *pArg) const;
     char16_t            readChar() const;
@@ -279,7 +316,8 @@
 
     // Read a UTF16 encoded string, convert to UTF8
     status_t            readUtf8FromUtf16(std::string* str) const;
-    status_t            readUtf8FromUtf16(std::unique_ptr<std::string>* str) const;
+    status_t            readUtf8FromUtf16(std::optional<std::string>* str) const;
+    status_t            readUtf8FromUtf16(std::unique_ptr<std::string>* str) const __attribute__((deprecated("use std::optional version instead")));
 
     const char*         readCString() const;
     String8             readString8() const;
@@ -287,35 +325,44 @@
     const char*         readString8Inplace(size_t* outLen) const;
     String16            readString16() const;
     status_t            readString16(String16* pArg) const;
-    status_t            readString16(std::unique_ptr<String16>* pArg) const;
+    status_t            readString16(std::optional<String16>* pArg) const;
+    status_t            readString16(std::unique_ptr<String16>* pArg) const __attribute__((deprecated("use std::optional version instead")));
     const char16_t*     readString16Inplace(size_t* outLen) const;
     sp<IBinder>         readStrongBinder() const;
     status_t            readStrongBinder(sp<IBinder>* val) const;
     status_t            readNullableStrongBinder(sp<IBinder>* val) const;
 
-
     // Read an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            readEnumVector(std::vector<T>* val) const;
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
     // Read an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            readEnumVector(std::vector<T>* val) const;
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const;
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
+    template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
+    status_t            readEnumVector(std::optional<std::vector<T>>* val) const;
 
     template<typename T>
     status_t            readParcelableVector(
-                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const;
+                            std::optional<std::vector<std::optional<T>>>* val) const;
+    template<typename T>
+    status_t            readParcelableVector(
+                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     template<typename T>
     status_t            readParcelableVector(std::vector<T>* val) const;
 
     status_t            readParcelable(Parcelable* parcelable) const;
 
     template<typename T>
-    status_t            readParcelable(std::unique_ptr<T>* parcelable) const;
+    status_t            readParcelable(std::optional<T>* parcelable) const;
+    template<typename T>
+    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")));
 
     template<typename T>
     status_t            readStrongBinder(sp<T>* val) const;
@@ -323,32 +370,46 @@
     template<typename T>
     status_t            readNullableStrongBinder(sp<T>* val) const;
 
-    status_t            readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const;
+    status_t            readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
+    status_t            readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
 
-    status_t            readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const;
+    status_t            readByteVector(std::optional<std::vector<int8_t>>* val) const;
+    status_t            readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readByteVector(std::vector<int8_t>* val) const;
-    status_t            readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const;
+    status_t            readByteVector(std::optional<std::vector<uint8_t>>* val) const;
+    status_t            readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readByteVector(std::vector<uint8_t>* val) const;
-    status_t            readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const;
+    status_t            readInt32Vector(std::optional<std::vector<int32_t>>* val) const;
+    status_t            readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readInt32Vector(std::vector<int32_t>* val) const;
-    status_t            readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const;
+    status_t            readInt64Vector(std::optional<std::vector<int64_t>>* val) const;
+    status_t            readInt64Vector(std::unique_ptr<std::vector<int64_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readInt64Vector(std::vector<int64_t>* val) const;
-    status_t            readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const;
+    status_t            readUint64Vector(std::optional<std::vector<uint64_t>>* val) const;
+    status_t            readUint64Vector(std::unique_ptr<std::vector<uint64_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readUint64Vector(std::vector<uint64_t>* val) const;
-    status_t            readFloatVector(std::unique_ptr<std::vector<float>>* val) const;
+    status_t            readFloatVector(std::optional<std::vector<float>>* val) const;
+    status_t            readFloatVector(std::unique_ptr<std::vector<float>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readFloatVector(std::vector<float>* val) const;
-    status_t            readDoubleVector(std::unique_ptr<std::vector<double>>* val) const;
+    status_t            readDoubleVector(std::optional<std::vector<double>>* val) const;
+    status_t            readDoubleVector(std::unique_ptr<std::vector<double>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readDoubleVector(std::vector<double>* val) const;
-    status_t            readBoolVector(std::unique_ptr<std::vector<bool>>* val) const;
+    status_t            readBoolVector(std::optional<std::vector<bool>>* val) const;
+    status_t            readBoolVector(std::unique_ptr<std::vector<bool>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readBoolVector(std::vector<bool>* val) const;
-    status_t            readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const;
+    status_t            readCharVector(std::optional<std::vector<char16_t>>* val) const;
+    status_t            readCharVector(std::unique_ptr<std::vector<char16_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readCharVector(std::vector<char16_t>* val) const;
     status_t            readString16Vector(
-                            std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const;
+                            std::optional<std::vector<std::optional<String16>>>* val) const;
+    status_t            readString16Vector(
+                            std::unique_ptr<std::vector<std::unique_ptr<String16>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readString16Vector(std::vector<String16>* val) const;
     status_t            readUtf8VectorFromUtf16Vector(
-                            std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const;
+                            std::optional<std::vector<std::optional<std::string>>>* val) const;
+    status_t            readUtf8VectorFromUtf16Vector(
+                            std::unique_ptr<std::vector<std::unique_ptr<std::string>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readUtf8VectorFromUtf16Vector(std::vector<std::string>* val) const;
 
     template<typename T>
@@ -360,12 +421,17 @@
     template<typename T>
     status_t            resizeOutVector(std::vector<T>* val) const;
     template<typename T>
-    status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const;
+    status_t            resizeOutVector(std::optional<std::vector<T>>* val) const;
+    template<typename T>
+    status_t            resizeOutVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")));
     template<typename T>
     status_t            reserveOutVector(std::vector<T>* val, size_t* size) const;
     template<typename T>
-    status_t            reserveOutVector(std::unique_ptr<std::vector<T>>* val,
+    status_t            reserveOutVector(std::optional<std::vector<T>>* val,
                                          size_t* size) const;
+    template<typename T>
+    status_t            reserveOutVector(std::unique_ptr<std::vector<T>>* val,
+                                         size_t* size) const __attribute__((deprecated("use std::optional version instead")));
 
     // Like Parcel.java's readExceptionCode().  Reads the first int32
     // off of a Parcel's header, returning 0 or the negative error
@@ -399,7 +465,9 @@
 
     // Retrieve a vector of smart file descriptors from the parcel.
     status_t            readUniqueFileDescriptorVector(
-                            std::unique_ptr<std::vector<base::unique_fd>>* val) const;
+                            std::optional<std::vector<base::unique_fd>>* val) const;
+    status_t            readUniqueFileDescriptorVector(
+                            std::unique_ptr<std::vector<base::unique_fd>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readUniqueFileDescriptorVector(
                             std::vector<base::unique_fd>* val) const;
 
@@ -421,27 +489,21 @@
     // uid.
     uid_t               readCallingWorkSourceUid() const;
 
+    void                print(TextOutput& to, uint32_t flags = 0) const;
+
 private:
     typedef void        (*release_func)(Parcel* parcel,
                                         const uint8_t* data, size_t dataSize,
-                                        const binder_size_t* objects, size_t objectsSize,
-                                        void* cookie);
-                        
+                                        const binder_size_t* objects, size_t objectsSize);
+
     uintptr_t           ipcData() const;
     size_t              ipcDataSize() const;
     uintptr_t           ipcObjects() const;
     size_t              ipcObjectsCount() const;
     void                ipcSetDataReference(const uint8_t* data, size_t dataSize,
                                             const binder_size_t* objects, size_t objectsCount,
-                                            release_func relFunc, void* relCookie);
-    
-public:
-    void                print(TextOutput& to, uint32_t flags = 0) const;
+                                            release_func relFunc);
 
-private:
-                        Parcel(const Parcel& o);
-    Parcel&             operator=(const Parcel& o);
-    
     status_t            finishWrite(size_t len);
     void                releaseObjects();
     void                acquireObjects();
@@ -455,10 +517,14 @@
     void                initState();
     void                scanForFds() const;
     status_t            validateReadData(size_t len) const;
+
+    // Reads an int32 size and does a coarse bounds check against the number
+    // of available bytes in the Parcel.
+    status_t            readVectorSizeWithCoarseBoundCheck(int32_t *size) const;
+
     void                updateWorkSourceRequestHeaderPosition() const;
 
-    status_t            finishFlattenBinder(const sp<IBinder>& binder,
-                                            const flat_binder_object& flat);
+    status_t            finishFlattenBinder(const sp<IBinder>& binder);
     status_t            finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
     status_t            flattenBinder(const sp<IBinder>& binder);
     status_t            unflattenBinder(sp<IBinder>* out) const;
@@ -492,21 +558,30 @@
     status_t            unsafeReadTypedVector(std::vector<T>* val,
                                               status_t(Parcel::*read_func)(U*) const) const;
     template<typename T>
-    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
+    status_t            readNullableTypedVector(std::optional<std::vector<T>>* val,
                                                 status_t(Parcel::*read_func)(T*) const) const;
     template<typename T>
+    status_t            readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
+                                                status_t(Parcel::*read_func)(T*) const) const __attribute__((deprecated("use std::optional version instead")));
+    template<typename T>
     status_t            readTypedVector(std::vector<T>* val,
                                         status_t(Parcel::*read_func)(T*) const) const;
     template<typename T, typename U>
     status_t            unsafeWriteTypedVector(const std::vector<T>& val,
                                                status_t(Parcel::*write_func)(U));
     template<typename T>
-    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
                                                  status_t(Parcel::*write_func)(const T&));
     template<typename T>
     status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                                 status_t(Parcel::*write_func)(const T&)) __attribute__((deprecated("use std::optional version instead")));
+    template<typename T>
+    status_t            writeNullableTypedVector(const std::optional<std::vector<T>>& val,
                                                  status_t(Parcel::*write_func)(T));
     template<typename T>
+    status_t            writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
+                                                 status_t(Parcel::*write_func)(T)) __attribute__((deprecated("use std::optional version instead")));
+    template<typename T>
     status_t            writeTypedVector(const std::vector<T>& val,
                                          status_t(Parcel::*write_func)(const T&));
     template<typename T>
@@ -531,8 +606,14 @@
     mutable bool        mHasFds;
     bool                mAllowFds;
 
+    // if this parcelable is involved in a secure transaction, force the
+    // data to be overridden with zero when deallocated
+    mutable bool        mDeallocZero;
+
     release_func        mOwner;
-    void*               mOwnerCookie;
+
+    // TODO(167966510): reserved for binder/version/stability
+    void*               mReserved = reinterpret_cast<void*>(0xAAAAAAAA);
 
     class Blob {
     public:
@@ -691,6 +772,15 @@
 }
 
 template<typename T>
+status_t Parcel::writeVectorSize(const std::optional<std::vector<T>>& val) {
+    if (!val) {
+        return writeInt32(-1);
+    }
+
+    return writeVectorSize(*val);
+}
+
+template<typename T>
 status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) {
     if (!val) {
         return writeInt32(-1);
@@ -702,6 +792,7 @@
 template<typename T>
 status_t Parcel::resizeOutVector(std::vector<T>* val) const {
     int32_t size;
+    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -715,8 +806,26 @@
 }
 
 template<typename T>
+status_t Parcel::resizeOutVector(std::optional<std::vector<T>>* val) const {
+    int32_t size;
+    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
+    status_t err = readInt32(&size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    val->reset();
+    if (size >= 0) {
+        val->emplace(size_t(size));
+    }
+
+    return OK;
+}
+
+template<typename T>
 status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
     int32_t size;
+    // used for allocating 'out' vector args, do not use readVectorSizeWithCoarseBoundCheck() here
     status_t err = readInt32(&size);
     if (err != NO_ERROR) {
         return err;
@@ -733,7 +842,7 @@
 template<typename T>
 status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const {
     int32_t read_size;
-    status_t err = readInt32(&read_size);
+    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
     if (err != NO_ERROR) {
         return err;
     }
@@ -747,10 +856,29 @@
 }
 
 template<typename T>
+status_t Parcel::reserveOutVector(std::optional<std::vector<T>>* val, size_t* size) const {
+    int32_t read_size;
+    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (read_size >= 0) {
+        *size = static_cast<size_t>(read_size);
+        val->emplace();
+        (*val)->reserve(*size);
+    } else {
+        val->reset();
+    }
+
+    return OK;
+}
+
+template<typename T>
 status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val,
                                   size_t* size) const {
     int32_t read_size;
-    status_t err = readInt32(&read_size);
+    status_t err = readVectorSizeWithCoarseBoundCheck(&read_size);
     if (err != NO_ERROR) {
         return err;
     }
@@ -803,7 +931,7 @@
         std::vector<T>* val,
         status_t(Parcel::*read_func)(U*) const) const {
     int32_t size;
-    status_t status = this->readInt32(&size);
+    status_t status = this->readVectorSizeWithCoarseBoundCheck(&size);
 
     if (status != OK) {
         return status;
@@ -841,11 +969,35 @@
 }
 
 template<typename T>
+status_t Parcel::readNullableTypedVector(std::optional<std::vector<T>>* val,
+                                         status_t(Parcel::*read_func)(T*) const) const {
+    const size_t start = dataPosition();
+    int32_t size;
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
+    val->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    val->emplace();
+
+    status = unsafeReadTypedVector(&**val, read_func);
+
+    if (status != OK) {
+       val->reset();
+    }
+
+    return status;
+}
+
+template<typename T>
 status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
                                          status_t(Parcel::*read_func)(T*) const) const {
     const size_t start = dataPosition();
     int32_t size;
-    status_t status = readInt32(&size);
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
     val->reset();
 
     if (status != OK || size < 0) {
@@ -901,6 +1053,16 @@
 }
 
 template<typename T>
+status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
+                                          status_t(Parcel::*write_func)(const T&)) {
+    if (!val) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, write_func);
+}
+
+template<typename T>
 status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
                                           status_t(Parcel::*write_func)(const T&)) {
     if (val.get() == nullptr) {
@@ -911,6 +1073,16 @@
 }
 
 template<typename T>
+status_t Parcel::writeNullableTypedVector(const std::optional<std::vector<T>>& val,
+                                          status_t(Parcel::*write_func)(T)) {
+    if (!val) {
+        return this->writeInt32(-1);
+    }
+
+    return unsafeWriteTypedVector(*val, write_func);
+}
+
+template<typename T>
 status_t Parcel::writeNullableTypedVector(const std::unique_ptr<std::vector<T>>& val,
                                           status_t(Parcel::*write_func)(T)) {
     if (val.get() == nullptr) {
@@ -926,10 +1098,34 @@
 }
 
 template<typename T>
+status_t Parcel::readParcelableVector(std::optional<std::vector<std::optional<T>>>* val) const {
+    const size_t start = dataPosition();
+    int32_t size;
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
+    val->reset();
+
+    if (status != OK || size < 0) {
+        return status;
+    }
+
+    setDataPosition(start);
+    val->emplace();
+
+    using NullableT = std::optional<T>;
+    status = unsafeReadTypedVector<NullableT, NullableT>(&**val, &Parcel::readParcelable);
+
+    if (status != OK) {
+        val->reset();
+    }
+
+    return status;
+}
+
+template<typename T>
 status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
     const size_t start = dataPosition();
     int32_t size;
-    status_t status = readInt32(&size);
+    status_t status = readVectorSizeWithCoarseBoundCheck(&size);
     val->reset();
 
     if (status != OK || size < 0) {
@@ -939,7 +1135,8 @@
     setDataPosition(start);
     val->reset(new std::vector<std::unique_ptr<T>>());
 
-    status = unsafeReadTypedVector(val->get(), &Parcel::readParcelable<T>);
+    using NullableT = std::unique_ptr<T>;
+    status = unsafeReadTypedVector<NullableT, NullableT>(val->get(), &Parcel::readParcelable);
 
     if (status != OK) {
         val->reset();
@@ -949,6 +1146,29 @@
 }
 
 template<typename T>
+status_t Parcel::readParcelable(std::optional<T>* parcelable) const {
+    const size_t start = dataPosition();
+    int32_t present;
+    status_t status = readInt32(&present);
+    parcelable->reset();
+
+    if (status != OK || !present) {
+        return status;
+    }
+
+    setDataPosition(start);
+    parcelable->emplace();
+
+    status = readParcelable(&**parcelable);
+
+    if (status != OK) {
+        parcelable->reset();
+    }
+
+    return status;
+}
+
+template<typename T>
 status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
     const size_t start = dataPosition();
     int32_t present;
@@ -972,6 +1192,11 @@
 }
 
 template<typename T>
+status_t Parcel::writeNullableParcelable(const std::optional<T>& parcelable) {
+    return writeRawNullableParcelable(parcelable ? &*parcelable : nullptr);
+}
+
+template<typename T>
 status_t Parcel::writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
     return writeRawNullableParcelable(parcelable.get());
 }
@@ -982,6 +1207,16 @@
 }
 
 template<typename T>
+status_t Parcel::writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val) {
+    if (!val) {
+        return this->writeInt32(-1);
+    }
+
+    using NullableT = std::optional<T>;
+    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
+}
+
+template<typename T>
 status_t Parcel::writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) {
     if (val.get() == nullptr) {
         return this->writeInt32(-1);
@@ -996,7 +1231,18 @@
         return this->writeInt32(-1);
     }
 
-    return unsafeWriteTypedVector(*val, &Parcel::writeNullableParcelable<T>);
+    using NullableT = std::unique_ptr<T>;
+    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
+}
+
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    using NullableT = std::optional<T>;
+    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
 }
 
 template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
@@ -1013,6 +1259,11 @@
     return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val.data()), val.size());
 }
 template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
+    if (!val) return writeInt32(-1);
+    return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
 status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
     if (!val) return writeInt32(-1);
     return writeByteVectorInternal(reinterpret_cast<const int8_t*>(val->data()), val->size());
@@ -1022,6 +1273,10 @@
     return writeTypedVector(val, &Parcel::writeEnum);
 }
 template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::writeEnumVector(const std::optional<std::vector<T>>& val) {
+    return writeNullableTypedVector(val, &Parcel::writeEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
 status_t Parcel::writeEnumVector(const std::unique_ptr<std::vector<T>>& val) {
     return writeNullableTypedVector(val, &Parcel::writeEnum);
 }
@@ -1053,6 +1308,17 @@
     return readByteVectorInternal(val, size);
 }
 template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
+    size_t size;
+    if (status_t status = reserveOutVector(val, &size); status != OK) return status;
+    if (!*val) {
+        // reserveOutVector does not create the out vector if size is < 0.
+        // This occurs when writing a null Enum vector.
+        return OK;
+    }
+    return readByteVectorInternal(&**val, size);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
 status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
     size_t size;
     if (status_t status = reserveOutVector(val, &size); status != OK) return status;
@@ -1068,6 +1334,10 @@
     return readTypedVector(val, &Parcel::readEnum);
 }
 template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
+status_t Parcel::readEnumVector(std::optional<std::vector<T>>* val) const {
+    return readNullableTypedVector(val, &Parcel::readEnum);
+}
+template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>>
 status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const {
     return readNullableTypedVector(val, &Parcel::readEnum);
 }
@@ -1083,5 +1353,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_PARCEL_H
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 4635ad8..9896fd7 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PARCEL_FILE_DESCRIPTOR_H_
-#define ANDROID_PARCEL_FILE_DESCRIPTOR_H_
+#pragma once
 
 #include <android-base/unique_fd.h>
 #include <binder/Parcel.h>
@@ -31,7 +30,8 @@
 public:
     ParcelFileDescriptor();
     explicit ParcelFileDescriptor(android::base::unique_fd fd);
-    ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { }
+    ParcelFileDescriptor(ParcelFileDescriptor&& other) noexcept : mFd(std::move(other.mFd)) { }
+    ParcelFileDescriptor& operator=(ParcelFileDescriptor&& other) noexcept = default;
     ~ParcelFileDescriptor() override;
 
     int get() const { return mFd.get(); }
@@ -43,22 +43,22 @@
     android::status_t readFromParcel(const android::Parcel* parcel) override;
 
     inline bool operator!=(const ParcelFileDescriptor& rhs) const {
-        return mFd != rhs.mFd;
+        return mFd.get() != rhs.mFd.get();
     }
     inline bool operator<(const ParcelFileDescriptor& rhs) const {
-        return mFd < rhs.mFd;
+        return mFd.get() < rhs.mFd.get();
     }
     inline bool operator<=(const ParcelFileDescriptor& rhs) const {
-        return mFd <= rhs.mFd;
+        return mFd.get() <= rhs.mFd.get();
     }
     inline bool operator==(const ParcelFileDescriptor& rhs) const {
-        return mFd == rhs.mFd;
+        return mFd.get() == rhs.mFd.get();
     }
     inline bool operator>(const ParcelFileDescriptor& rhs) const {
-        return mFd > rhs.mFd;
+        return mFd.get() > rhs.mFd.get();
     }
     inline bool operator>=(const ParcelFileDescriptor& rhs) const {
-        return mFd >= rhs.mFd;
+        return mFd.get() >= rhs.mFd.get();
     }
 private:
     android::base::unique_fd mFd;
@@ -66,5 +66,3 @@
 
 } // namespace os
 } // namespace android
-
-#endif // ANDROID_OS_PARCEL_FILE_DESCRIPTOR_H_
diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h
index a9166e2..2c652be 100644
--- a/libs/binder/include/binder/Parcelable.h
+++ b/libs/binder/include/binder/Parcelable.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PARCELABLE_H
-#define ANDROID_PARCELABLE_H
+#pragma once
 
 #include <vector>
 
@@ -52,6 +51,21 @@
     //
     // Returns android::OK on success and an appropriate error otherwise.
     virtual status_t readFromParcel(const Parcel* parcel) = 0;
+
+    // WARNING: for use by auto-generated code only (AIDL). Should not be used
+    // manually, or there is a risk of breaking CTS, GTS, VTS, or CTS-on-GSI
+    // tests.
+    enum class Stability : int32_t {
+        STABILITY_LOCAL,
+        STABILITY_VINTF, // corresponds to @VintfStability
+    };
+
+    // 'Stable' means this parcelable is guaranteed to be stable for multiple
+    // years.
+    // It must be guaranteed by setting stability field in aidl_interface.
+    // WARNING: getStability() is only expected to be overridden by auto-generated
+    // code. Returns true if this parcelable is stable.
+    virtual Stability getStability() const { return Stability::STABILITY_LOCAL; }
 };  // class Parcelable
 
 #if defined(__clang__)
@@ -59,5 +73,3 @@
 #endif
 
 }  // namespace android
-
-#endif // ANDROID_PARCELABLE_H
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
new file mode 100644
index 0000000..9e4475c
--- /dev/null
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <mutex>
+#include <optional>
+#include <tuple>
+
+namespace android {
+namespace os {
+/*
+ * C++ implementation of the Java class android.os.ParcelableHolder
+ */
+class ParcelableHolder : public android::Parcelable {
+public:
+    ParcelableHolder() = delete;
+    explicit ParcelableHolder(Stability stability) : mStability(stability){}
+    virtual ~ParcelableHolder() = default;
+    ParcelableHolder(const ParcelableHolder& other) {
+        mParcelable = other.mParcelable;
+        mParcelableName = other.mParcelableName;
+        if (other.mParcelPtr) {
+            mParcelPtr = std::make_unique<Parcel>();
+            mParcelPtr->appendFrom(other.mParcelPtr.get(), 0, other.mParcelPtr->dataSize());
+        }
+        mStability = other.mStability;
+    }
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    void reset() {
+        this->mParcelable = nullptr;
+        this->mParcelableName = std::nullopt;
+        this->mParcelPtr = nullptr;
+    }
+
+    template <typename T>
+    status_t setParcelable(T&& p) {
+        using Tt = typename std::decay<T>::type;
+        return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p)));
+    }
+
+    template <typename T>
+    status_t setParcelable(std::shared_ptr<T> p) {
+        static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
+        if (p && this->getStability() > p->getStability()) {
+            return android::BAD_VALUE;
+        }
+        this->mParcelable = p;
+        this->mParcelableName = T::getParcelableDescriptor();
+        this->mParcelPtr = nullptr;
+        return android::OK;
+    }
+
+    template <typename T>
+    status_t getParcelable(std::shared_ptr<T>* ret) const {
+        static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
+        const String16& parcelableDesc = T::getParcelableDescriptor();
+        if (!this->mParcelPtr) {
+            if (!this->mParcelable || !this->mParcelableName) {
+                ALOGD("empty ParcelableHolder");
+                *ret = nullptr;
+                return android::OK;
+            } else if (parcelableDesc != *mParcelableName) {
+                ALOGD("extension class name mismatch expected:%s actual:%s",
+                      String8(*mParcelableName).c_str(), String8(parcelableDesc).c_str());
+                *ret = nullptr;
+                return android::BAD_VALUE;
+            }
+            *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            return android::OK;
+        }
+        this->mParcelPtr->setDataPosition(0);
+        status_t status = this->mParcelPtr->readString16(&this->mParcelableName);
+        if (status != android::OK || parcelableDesc != this->mParcelableName) {
+            this->mParcelableName = std::nullopt;
+            *ret = nullptr;
+            return status;
+        }
+        this->mParcelable = std::make_shared<T>();
+        status = mParcelable.get()->readFromParcel(this->mParcelPtr.get());
+        if (status != android::OK) {
+            this->mParcelableName = std::nullopt;
+            this->mParcelable = nullptr;
+            *ret = nullptr;
+            return status;
+        }
+        this->mParcelPtr = nullptr;
+        *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        return android::OK;
+    }
+
+    Stability getStability() const override { return mStability; }
+
+    inline bool operator!=(const ParcelableHolder& rhs) const {
+        return this != &rhs;
+    }
+    inline bool operator<(const ParcelableHolder& rhs) const {
+        return this < &rhs;
+    }
+    inline bool operator<=(const ParcelableHolder& rhs) const {
+        return this <= &rhs;
+    }
+    inline bool operator==(const ParcelableHolder& rhs) const {
+        return this == &rhs;
+    }
+    inline bool operator>(const ParcelableHolder& rhs) const {
+        return this > &rhs;
+    }
+    inline bool operator>=(const ParcelableHolder& rhs) const {
+        return this >= &rhs;
+    }
+
+private:
+    mutable std::shared_ptr<Parcelable> mParcelable;
+    mutable std::optional<String16> mParcelableName;
+    mutable std::unique_ptr<Parcel> mParcelPtr;
+    Stability mStability;
+};
+} // namespace os
+} // namespace android
diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
index c258215..835a3a8 100644
--- a/libs/binder/include/binder/PermissionCache.h
+++ b/libs/binder/include/binder/PermissionCache.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef BINDER_PERMISSION_H
-#define BINDER_PERMISSION_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -82,5 +81,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif /* BINDER_PERMISSION_H */
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
index 4db522a..e658574 100644
--- a/libs/binder/include/binder/PermissionController.h
+++ b/libs/binder/include/binder/PermissionController.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PERMISSION_CONTROLLER_H
-#define ANDROID_PERMISSION_CONTROLLER_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -65,5 +64,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_PERMISSION_CONTROLLER_H
diff --git a/libs/binder/include/binder/PersistableBundle.h b/libs/binder/include/binder/PersistableBundle.h
index 322fef9..4517cf2 100644
--- a/libs/binder/include/binder/PersistableBundle.h
+++ b/libs/binder/include/binder/PersistableBundle.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PERSISTABLE_BUNDLE_H
-#define ANDROID_PERSISTABLE_BUNDLE_H
+#pragma once
 
 #include <map>
 #include <set>
@@ -128,5 +127,3 @@
 }  // namespace os
 
 }  // namespace android
-
-#endif  // ANDROID_PERSISTABLE_BUNDLE_H
diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include/binder/ProcessInfoService.h
index 6bfd1bc..6b3b5ce 100644
--- a/libs/binder/include/binder/ProcessInfoService.h
+++ b/libs/binder/include/binder/ProcessInfoService.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PROCESS_INFO_SERVICE_H
-#define ANDROID_PROCESS_INFO_SERVICE_H
+#pragma once
 
 #ifndef __ANDROID_VNDK__
 
@@ -83,6 +82,3 @@
 #else // __ANDROID_VNDK__
 #error "This header is not visible to vendors"
 #endif // __ANDROID_VNDK__
-
-#endif // ANDROID_PROCESS_INFO_SERVICE_H
-
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index e57ff1c..2405ab6 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_PROCESS_STATE_H
-#define ANDROID_PROCESS_STATE_H
+#pragma once
 
 #include <binder/IBinder.h>
 #include <utils/KeyedVector.h>
@@ -42,20 +41,16 @@
      * any call to ProcessState::self(). The default is /dev/vndbinder
      * for processes built with the VNDK and /dev/binder for those
      * which are not.
+     *
+     * If this is called with nullptr, the behavior is the same as selfOrNull.
      */
     static  sp<ProcessState>    initWithDriver(const char *driver);
 
             sp<IBinder>         getContextObject(const sp<IBinder>& caller);
 
             void                startThreadPool();
-                        
-    typedef bool (*context_check_func)(const String16& name,
-                                       const sp<IBinder>& caller,
-                                       void* userData);
 
-            bool                becomeContextManager(
-                                    context_check_func checkFunc,
-                                    void* userData);
+            bool                becomeContextManager();
 
             sp<IBinder>         getStrongProxyForHandle(int32_t handle);
             void                expungeHandle(int32_t handle, IBinder* binder);
@@ -75,7 +70,7 @@
                                 // 2. Temporary strong references held by the kernel during a
                                 //    transaction on the node.
                                 // It does NOT include local strong references to the node
-            ssize_t             getStrongRefCountForNodeByHandle(int32_t handle);
+            ssize_t             getStrongRefCountForNode(const sp<BpBinder>& binder);
 
             enum class CallRestriction {
                 // all calls okay
@@ -90,6 +85,8 @@
             void setCallRestriction(CallRestriction restriction);
 
 private:
+    static  sp<ProcessState>    init(const char *defaultDriver, bool requireDefault);
+
     friend class IPCThreadState;
     
             explicit            ProcessState(const char* driver);
@@ -110,11 +107,14 @@
             int                 mDriverFD;
             void*               mVMStart;
 
-            // Protects thread count variable below.
+            // Protects thread count and wait variables below.
             pthread_mutex_t     mThreadCountLock;
+            // Broadcast whenever mWaitingForThreads > 0
             pthread_cond_t      mThreadCountDecrement;
             // Number of binder threads current executing a command.
             size_t              mExecutingThreadsCount;
+            // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
+            size_t              mWaitingForThreads;
             // Maximum number for binder threads allowed for this process.
             size_t              mMaxThreads;
             // Time when thread pool was emptied
@@ -124,9 +124,6 @@
 
             Vector<handle_entry>mHandleToObject;
 
-            context_check_func  mBinderContextCheckFunc;
-            void*               mBinderContextUserData;
-
             String8             mRootDir;
             bool                mThreadPoolStarted;
     volatile int32_t            mThreadPoolSeq;
@@ -137,5 +134,3 @@
 } // namespace android
 
 // ---------------------------------------------------------------------------
-
-#endif // ANDROID_PROCESS_STATE_H
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 2894482..12272ba 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -26,6 +26,29 @@
 
 namespace internal {
 
+// Stability encodes how a binder changes over time. There are two levels of
+// stability:
+// 1). the interface stability - this is how a particular set of API calls (a
+//   particular ordering of things like writeInt32/readInt32) are changed over
+//   time. If one release, we have 'writeInt32' and the next release, we have
+//   'writeInt64', then this interface doesn't have a very stable
+//   Stability::Level. Usually this ordering is controlled by a .aidl file.
+// 2). the wire format stability - this is how these API calls map to actual
+//   bytes that are written to the wire (literally, this is how they are written
+//   to the kernel inside of IBinder::transact, but it may be expanded to other
+//   wires in the future). For instance, writeInt32 in binder translates to
+//   writing a 4-byte little-endian integer in two's complement. You can imagine
+//   in the future, we change writeInt32/readInt32 to instead write 8-bytes with
+//   that integer and some check bits. In this case, the wire format changes,
+//   but as long as a client libbinder knows to keep on writing a 4-byte value
+//   to old servers, and new servers know how to interpret the 8-byte result,
+//   they can still communicate.
+//
+// Every binder object has a stability level associated with it, and when
+// communicating with a binder, we make sure that the command we sent is one
+// that it knows how to process. The summary of stability of a binder is
+// represented by a Stability::Category object.
+
 // WARNING: These APIs are only ever expected to be called by auto-generated code.
 //     Instead of calling them, you should set the stability of a .aidl interface
 class Stability final {
@@ -73,7 +96,7 @@
 
     static void tryMarkCompilationUnit(IBinder* binder);
 
-    enum Level : int32_t {
+    enum Level : uint8_t {
         UNDECLARED = 0,
 
         VENDOR = 0b000011,
@@ -81,22 +104,54 @@
         VINTF = 0b111111,
     };
 
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
-    static constexpr Level kLocalStability = Level::VENDOR;
-#else
-    static constexpr Level kLocalStability = Level::SYSTEM;
-#endif
+    // This is the format of stability passed on the wire.
+    struct Category {
+        static inline Category fromRepr(int32_t representation) {
+            return *reinterpret_cast<Category*>(&representation);
+        }
+        int32_t repr() const {
+            return *reinterpret_cast<const int32_t*>(this);
+        }
+        static inline Category currentFromLevel(Level level);
+
+        bool operator== (const Category& o) const {
+            return repr() == o.repr();
+        }
+        bool operator!= (const Category& o) const {
+            return !(*this == o);
+        }
+
+        std::string debugString();
+
+        // This is the version of the wire protocol associated with the host
+        // process of a particular binder. As the wire protocol changes, if
+        // sending a transaction to a binder with an old version, the Parcel
+        // class must write parcels according to the version documented here.
+        uint8_t version;
+
+        uint8_t reserved[2];
+
+        // bitmask of Stability::Level
+        Level level;
+    };
+    static_assert(sizeof(Category) == sizeof(int32_t));
+
+    // returns the stability according to how this was built
+    static Level getLocalLevel();
 
     // applies stability to binder if stability level is known
     __attribute__((warn_unused_result))
-    static status_t set(IBinder* binder, int32_t stability, bool log);
+    static status_t setRepr(IBinder* binder, int32_t representation, bool log);
 
-    static Level get(IBinder* binder);
+    // get stability information as encoded on the wire
+    static Category getCategory(IBinder* binder);
 
-    static bool check(int32_t provided, Level required);
+    // whether a transaction on binder is allowed, if the transaction
+    // is done from a context with a specific stability level
+    static bool check(Category provided, Level required);
 
-    static bool isDeclaredStability(int32_t stability);
-    static std::string stabilityString(int32_t stability);
+    static bool isDeclaredLevel(Level level);
+    static std::string levelString(Level level);
 
     Stability();
 };
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index 7d889b6..c30ae01 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -18,7 +18,8 @@
 #define ANDROID_BINDER_STATUS_H
 
 #include <cstdint>
-#include <sstream>
+#include <sstream> // historical
+#include <ostream>
 
 #include <binder/Parcel.h>
 #include <utils/String8.h>
@@ -153,8 +154,9 @@
     String8 mMessage;
 };  // class Status
 
-// For gtest output logging
-std::stringstream& operator<< (std::stringstream& stream, const Status& s);
+static inline std::ostream& operator<< (std::ostream& o, const Status& s) {
+    return o << s.toString8();
+}
 
 }  // namespace binder
 }  // namespace android
diff --git a/libs/binder/include/binder/TextOutput.h b/libs/binder/include/binder/TextOutput.h
index f66406f..bf9c92b 100644
--- a/libs/binder/include/binder/TextOutput.h
+++ b/libs/binder/include/binder/TextOutput.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_TEXTOUTPUT_H
-#define ANDROID_TEXTOUTPUT_H
+#pragma once
 
 #include <utils/Errors.h>
 #include <utils/String8.h>
@@ -50,12 +49,18 @@
 
 // ---------------------------------------------------------------------------
 
+// DO NOT USE: prefer libutils/libbase logs, which don't require static data to
+// be allocated.
 // Text output stream for printing to the log (via utils/Log.h).
 extern TextOutput& alog;
 
+// DO NOT USE: prefer libutils/libbase logs, which don't require static data to
+// be allocated.
 // Text output stream for printing to stdout.
 extern TextOutput& aout;
 
+// DO NOT USE: prefer libutils/libbase logs, which don't require static data to
+// be allocated.
 // Text output stream for printing to stderr.
 extern TextOutput& aerr;
 
@@ -200,5 +205,3 @@
 
 // ---------------------------------------------------------------------------
 } // namespace android
-
-#endif // ANDROID_TEXTOUTPUT_H
diff --git a/libs/binder/include/private/binder/binder_module.h b/libs/binder/include/private/binder/binder_module.h
index 7be8f7b..5a719b8 100644
--- a/libs/binder/include/private/binder/binder_module.h
+++ b/libs/binder/include/private/binder/binder_module.h
@@ -17,10 +17,6 @@
 #ifndef _BINDER_MODULE_H_
 #define _BINDER_MODULE_H_
 
-#ifdef __cplusplus
-namespace android {
-#endif
-
 /* obtain structures and constants from the kernel header */
 
 // TODO(b/31559095): bionic on host
@@ -36,6 +32,10 @@
 #include <sys/ioctl.h>
 #include <linux/android/binder.h>
 
+#ifdef __cplusplus
+namespace android {
+#endif
+
 #ifndef BR_FROZEN_REPLY
 // Temporary definition of BR_FROZEN_REPLY. For production
 // this will come from UAPI binder.h
@@ -88,7 +88,9 @@
 };
 #endif //BINDER_GET_FROZEN_INFO
 
-
+enum transaction_flags_ext {
+    TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */
+};
 
 #ifdef __cplusplus
 }   // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index b37db43..82f3882 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -26,6 +26,9 @@
                 "-D__ANDROID_API__=10000",
             ],
         },
+        darwin: {
+            enabled: false,
+        },
     },
 }
 
@@ -35,7 +38,10 @@
     defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
 
+    llndk_stubs: "libbinder_ndk.llndk",
+
     export_include_dirs: [
+        "include_cpp",
         "include_ndk",
         "include_platform",
     ],
@@ -81,6 +87,9 @@
         linux: {
             version_script: "libbinder_ndk.map.txt",
         },
+        darwin: {
+            enabled: false,
+        },
     },
     stubs: {
         symbol_file: "libbinder_ndk.map.txt",
@@ -89,6 +98,35 @@
             "30",
         ],
     },
+    tidy: true,
+    tidy_flags: [
+        // Only check our headers
+        "--header-filter=^.*frameworks/native/libs/binder/.*.h$",
+    ],
+    tidy_checks_as_errors: [
+        // Explicitly list the checks that should not occur in this module.
+        "abseil-*",
+        "android-*",
+        "bugprone-*",
+        "cert-*",
+        "clang-analyzer-*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "google-*",
+        "-google-readability-*",
+        "-google-runtime-references",
+        "misc-*",
+        "-misc-no-recursion",
+        "-misc-non-private-member-variables-in-classes",
+        "-misc-redundant-expression",
+        "-misc-unused-parameters",
+        "-misc-unused-using-decls",
+        "performance*",
+        "portability*",
+    ],
 }
 
 ndk_headers {
@@ -101,6 +139,17 @@
     license: "NOTICE",
 }
 
+// TODO(b/160624671): package with the aidl compiler
+ndk_headers {
+    name: "libbinder_ndk_helper_headers",
+    from: "include_cpp/android",
+    to: "android",
+    srcs: [
+        "include_cpp/android/*.h",
+    ],
+    license: "NOTICE",
+}
+
 ndk_library {
     name: "libbinder_ndk",
     symbol_file: "libbinder_ndk.map.txt",
@@ -108,9 +157,10 @@
 }
 
 llndk_library {
-    name: "libbinder_ndk",
+    name: "libbinder_ndk.llndk",
     symbol_file: "libbinder_ndk.map.txt",
     export_include_dirs: [
+        "include_cpp",
         "include_ndk",
         "include_platform",
     ],
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 919150d..3c90681 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -15,6 +15,8 @@
  */
 
 #include <android/binder_ibinder.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_libbinder.h>
 #include "ibinder_internal.h"
 
 #include <android/binder_stability.h>
@@ -71,14 +73,13 @@
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
 
-bool AIBinder::associateClass(const AIBinder_Class* clazz) {
-    if (clazz == nullptr) return false;
+std::optional<bool> AIBinder::associateClassInternal(const AIBinder_Class* clazz,
+                                                     const String16& newDescriptor, bool set) {
+    std::lock_guard<std::mutex> lock(mClazzMutex);
     if (mClazz == clazz) return true;
 
-    String8 newDescriptor(clazz->getInterfaceDescriptor());
-
     if (mClazz != nullptr) {
-        String8 currentDescriptor(mClazz->getInterfaceDescriptor());
+        const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
         if (newDescriptor == currentDescriptor) {
             LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
                        << "' match during associateClass, but they are different class objects. "
@@ -87,27 +88,46 @@
             LOG(ERROR) << __func__
                        << ": Class cannot be associated on object which already has a class. "
                           "Trying to associate to '"
-                       << newDescriptor.c_str() << "' but already set to '"
-                       << currentDescriptor.c_str() << "'.";
+                       << newDescriptor << "' but already set to '" << currentDescriptor << "'.";
         }
 
         // always a failure because we know mClazz != clazz
         return false;
     }
 
+    if (set) {
+        // if this is a local object, it's not one known to libbinder_ndk
+        mClazz = clazz;
+        return true;
+    }
+
+    return {};
+}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+    if (clazz == nullptr) return false;
+
+    const String16& newDescriptor = clazz->getInterfaceDescriptor();
+
+    auto result = associateClassInternal(clazz, newDescriptor, false);
+    if (result.has_value()) return *result;
+
     CHECK(asABpBinder() != nullptr);  // ABBinder always has a descriptor
 
-    String8 descriptor(getBinder()->getInterfaceDescriptor());
+    const String16& descriptor = getBinder()->getInterfaceDescriptor();
     if (descriptor != newDescriptor) {
-        LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str()
-                   << "' but descriptor is actually '" << descriptor.c_str() << "'.";
+        if (getBinder()->isBinderAlive()) {
+            LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
+                       << "' but descriptor is actually '" << descriptor << "'.";
+        } else {
+            // b/155793159
+            LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
+                       << "' to dead binder.";
+        }
         return false;
     }
 
-    // if this is a local object, it's not one known to libbinder_ndk
-    mClazz = clazz;
-
-    return true;
+    return associateClassInternal(clazz, newDescriptor, true).value();
 }
 
 ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
@@ -281,13 +301,34 @@
     return binder.get();
 }
 
+AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak) {
+    if (weak == nullptr) {
+        return nullptr;
+    }
+
+    return new AIBinder_Weak{weak->binder};
+}
+
+bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs) {
+    if (lhs == nullptr || rhs == nullptr) return lhs < rhs;
+
+    return const_cast<AIBinder*>(lhs)->getBinder() < const_cast<AIBinder*>(rhs)->getBinder();
+}
+
+bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs) {
+    if (lhs == nullptr || rhs == nullptr) return lhs < rhs;
+
+    return lhs->binder < rhs->binder;
+}
+
 AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                                AIBinder_Class_onDestroy onDestroy,
                                AIBinder_Class_onTransact onTransact)
     : onCreate(onCreate),
       onDestroy(onDestroy),
       onTransact(onTransact),
-      mInterfaceDescriptor(interfaceDescriptor) {}
+      mInterfaceDescriptor(interfaceDescriptor),
+      mWideInterfaceDescriptor(interfaceDescriptor) {}
 
 AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
                                       AIBinder_Class_onCreate onCreate,
@@ -315,6 +356,12 @@
     clazz->handleShellCommand = handleShellCommand;
 }
 
+const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) {
+    CHECK(clazz != nullptr) << "getDescriptor requires non-null clazz";
+
+    return clazz->getInterfaceDescriptorUtf8();
+}
+
 void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
     CHECK(who == mWho);
 
@@ -347,7 +394,7 @@
                            mDeathRecipients.end());
 }
 
-binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* cookie) {
+binder_status_t AIBinder_DeathRecipient::linkToDeath(const sp<IBinder>& binder, void* cookie) {
     CHECK(binder != nullptr);
 
     std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
@@ -366,7 +413,7 @@
     return STATUS_OK;
 }
 
-binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp<IBinder> binder, void* cookie) {
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(const sp<IBinder>& binder, void* cookie) {
     CHECK(binder != nullptr);
 
     std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
@@ -550,13 +597,6 @@
         return STATUS_INVALID_OPERATION;
     }
 
-    if (!binder->isRemote()) {
-        LOG(WARNING) << "A binder object at " << binder
-                     << " is being transacted on, however, this object is in the same process as "
-                        "its proxy. Transacting with this binder is expensive compared to just "
-                        "calling the corresponding functionality in the same process.";
-    }
-
     *in = new AParcel(binder);
     status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
     binder_status_t ret = PruneStatusT(status);
@@ -591,7 +631,7 @@
         return STATUS_UNKNOWN_TRANSACTION;
     }
 
-    constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY;
+    constexpr binder_flags_t kAllFlags = FLAG_PRIVATE_VENDOR | FLAG_ONEWAY | FLAG_CLEAR_BUF;
     if ((flags & ~kAllFlags) != 0) {
         LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
         return STATUS_BAD_VALUE;
@@ -676,3 +716,29 @@
     rawBinder->setExtension(ext->getBinder());
     return STATUS_OK;
 }
+
+// platform methods follow
+
+void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid) {
+    ABBinder* localBinder = binder->asABBinder();
+    if (localBinder == nullptr) {
+        LOG(FATAL) << "AIBinder_setRequestingSid must be called on a local binder";
+    }
+
+    localBinder->setRequestingSid(requestingSid);
+}
+
+const char* AIBinder_getCallingSid() {
+    return ::android::IPCThreadState::self()->getCallingSid();
+}
+
+android::sp<android::IBinder> AIBinder_toPlatformBinder(AIBinder* binder) {
+    if (binder == nullptr) return nullptr;
+    return binder->getBinder();
+}
+
+AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder) {
+    sp<AIBinder> ndkBinder = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ndkBinder.get());
+    return ndkBinder.get();
+}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 902fe79..6824306 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -22,6 +22,7 @@
 
 #include <atomic>
 #include <mutex>
+#include <optional>
 #include <vector>
 
 #include <binder/Binder.h>
@@ -52,10 +53,14 @@
     }
 
    private:
+    std::optional<bool> associateClassInternal(const AIBinder_Class* clazz,
+                                               const ::android::String16& newDescriptor, bool set);
+
     // AIBinder instance is instance of this class for a local object. In order to transact on a
     // remote object, this also must be set for simplicity (although right now, only the
     // interfaceDescriptor from it is used).
     const AIBinder_Class* mClazz;
+    std::mutex mClazzMutex;
 };
 
 // This is a local AIBinder object with a known class.
@@ -107,7 +112,8 @@
     AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                    AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
 
-    const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }
+    const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
+    const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
 
     // required to be non-null, implemented for every class
     const AIBinder_Class_onCreate onCreate = nullptr;
@@ -119,9 +125,11 @@
     AIBinder_handleShellCommand handleShellCommand = nullptr;
 
    private:
+    // Copy of the raw char string for when we don't have to return UTF-16
+    const std::string mInterfaceDescriptor;
     // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
     // one.
-    const ::android::String16 mInterfaceDescriptor;
+    const ::android::String16 mWideInterfaceDescriptor;
 };
 
 // Ownership is like this (when linked to death):
@@ -156,8 +164,8 @@
     };
 
     explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
-    binder_status_t linkToDeath(::android::sp<::android::IBinder>, void* cookie);
-    binder_status_t unlinkToDeath(::android::sp<::android::IBinder> binder, void* cookie);
+    binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie);
+    binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie);
 
    private:
     // When the user of this API deletes a Bp object but not the death recipient, the
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
similarity index 68%
rename from libs/binder/ndk/include_ndk/android/binder_auto_utils.h
rename to libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2b61cf1..0ad400b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -27,6 +27,7 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
+#include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 #include <android/binder_status.h>
 
@@ -44,9 +45,14 @@
 class SpAIBinder {
    public:
     /**
+     * Default constructor.
+     */
+    SpAIBinder() : mBinder(nullptr) {}
+
+    /**
      * Takes ownership of one strong refcount of binder.
      */
-    explicit SpAIBinder(AIBinder* binder = nullptr) : mBinder(binder) {}
+    explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {}
 
     /**
      * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
@@ -69,6 +75,9 @@
      * ownership of that other object.
      */
     SpAIBinder& operator=(const SpAIBinder& other) {
+        if (this == &other) {
+            return *this;
+        }
         AIBinder_incStrong(other.mBinder);
         set(other.mBinder);
         return *this;
@@ -106,6 +115,13 @@
      */
     AIBinder** getR() { return &mBinder; }
 
+    bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
+    bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
+    bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
+
    private:
     AIBinder* mBinder = nullptr;
 };
@@ -115,7 +131,7 @@
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
-template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
+template <typename T, void (*Destroy)(T), T DEFAULT>
 class ScopedAResource {
    public:
     /**
@@ -165,8 +181,10 @@
     ScopedAResource& operator=(const ScopedAResource&) = delete;
 
     // move-constructing/assignment is okay
-    ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; }
-    ScopedAResource& operator=(ScopedAResource&& other) {
+    ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) {
+        other.mT = DEFAULT;
+    }
+    ScopedAResource& operator=(ScopedAResource&& other) noexcept {
         set(other.mT);
         other.mT = DEFAULT;
         return *this;
@@ -181,7 +199,7 @@
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public impl::ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -189,15 +207,26 @@
     explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
     ~ScopedAParcel() {}
     ScopedAParcel(ScopedAParcel&&) = default;
+    ScopedAParcel& operator=(ScopedAParcel&&) = default;
+
+    bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
 };
 
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
+     *
+     * WARNING: this constructor is only expected to be used when reading a
+     *     status value. Use `ScopedAStatus::ok()` instead.
      */
     explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
     ~ScopedAStatus() {}
@@ -230,10 +259,24 @@
     const char* getMessage() const { return AStatus_getMessage(get()); }
 
     std::string getDescription() const {
-        const char* cStr = AStatus_getDescription(get());
-        std::string ret = cStr;
-        AStatus_deleteDescription(cStr);
-        return ret;
+        if (__builtin_available(android 30, *)) {
+            const char* cStr = AStatus_getDescription(get());
+            std::string ret = cStr;
+            AStatus_deleteDescription(cStr);
+            return ret;
+        }
+        binder_exception_t exception = getExceptionCode();
+        std::string desc = std::to_string(exception);
+        if (exception == EX_SERVICE_SPECIFIC) {
+            desc += " (" + std::to_string(getServiceSpecificError()) + ")";
+        } else if (exception == EX_TRANSACTION_FAILED) {
+            desc += " (" + std::to_string(getStatus()) + ")";
+        }
+        if (const char* msg = getMessage(); msg != nullptr) {
+            desc += ": ";
+            desc += msg;
+        }
+        return desc;
     }
 
     /**
@@ -263,7 +306,7 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-    : public impl::ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+    : public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
                                    nullptr> {
    public:
     /**
@@ -273,13 +316,14 @@
         : ScopedAResource(a) {}
     ~ScopedAIBinder_DeathRecipient() {}
     ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
+    ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default;
 };
 
 /**
  * Convenience wrapper. See AIBinder_Weak.
  */
 class ScopedAIBinder_Weak
-    : public impl::ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+    : public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -287,6 +331,7 @@
     explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
     ~ScopedAIBinder_Weak() {}
     ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
+    ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default;
 
     /**
      * See AIBinder_Weak_promote.
@@ -294,17 +339,38 @@
     SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
 };
 
+namespace internal {
+
+static void closeWithError(int fd) {
+    if (fd == -1) return;
+    int ret = close(fd);
+    if (ret != 0) {
+        syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
+    }
+}
+
+}  // namespace internal
+
 /**
  * Convenience wrapper for a file descriptor.
  */
-class ScopedFileDescriptor : public impl::ScopedAResource<int, int, close, -1> {
+class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
    public:
     /**
      * Takes ownership of a.
      */
-    explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {}
+    ScopedFileDescriptor() : ScopedFileDescriptor(-1) {}
+    explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {}
     ~ScopedFileDescriptor() {}
     ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
+    ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
+
+    bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
 };
 
 }  // namespace ndk
diff --git a/libs/binder/ndk/include_ndk/android/binder_enums.h b/libs/binder/ndk/include_cpp/android/binder_enums.h
similarity index 100%
rename from libs/binder/ndk/include_ndk/android/binder_enums.h
rename to libs/binder/ndk/include_cpp/android/binder_enums.h
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
similarity index 94%
rename from libs/binder/ndk/include_ndk/android/binder_interface_utils.h
rename to libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 33e4586..05eb64b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -83,18 +83,27 @@
     template <class T, class... Args>
     static std::shared_ptr<T> make(Args&&... args) {
         T* t = new T(std::forward<Args>(args)...);
-        return t->template ref<T>();
+        // warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]
+        return t->template ref<T>();  // NOLINT(clang-analyzer-unix.Malloc)
     }
 
     static void operator delete(void* p) { std::free(p); }
 
+    // Once minSdkVersion is 30, we are guaranteed to be building with the
+    // Android 11 AIDL compiler which supports the SharedRefBase::make API.
+    //
+    // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
+    // ownership. Making this operator private to avoid double-ownership.
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
+   private:
+#else
+    [[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
+#endif
+    static void* operator new(size_t s) { return std::malloc(s); }
+
    private:
     std::once_flag mFlagThis;
     std::weak_ptr<SharedRefBase> mThis;
-
-    // Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
-    // ownership. Making this operator private to avoid double-ownership.
-    static void* operator new(size_t s) { return std::malloc(s); }
 };
 
 /**
@@ -238,7 +247,7 @@
     // ourselves. The defaults are harmless.
     AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
 #ifdef HAS_BINDER_SHELL_COMMAND
-    if (AIBinder_Class_setHandleShellCommand != nullptr) {
+    if (__builtin_available(android 30, *)) {
         AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
     }
 #endif
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/include_cpp/android/binder_internal_logging.h
similarity index 61%
copy from libs/binder/ndk/test/IBinderNdkUnitTest.aidl
copy to libs/binder/ndk/include_cpp/android/binder_internal_logging.h
index 6e8e463..88c6443 100644
--- a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/include_cpp/android/binder_internal_logging.h
@@ -14,14 +14,25 @@
  * limitations under the License.
  */
 
-// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
-// because it requires libbinder_ndk implementation details or APIs not
-// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
-// over here.
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
 
-import IEmpty;
+/**
+ * @file binder_internal_logging.h
+ * @brief This provides the ability to use syslog from binder headers, since
+ * other logging functionality might be inaccessable.
+ */
 
-interface IBinderNdkUnitTest {
-    void takeInterface(IEmpty test);
-    void forceFlushCommands();
-}
+#pragma once
+
+// defined differently by liblog
+#pragma push_macro("LOG_PRI")
+#ifdef LOG_PRI
+#undef LOG_PRI
+#endif
+#include <syslog.h>
+#pragma pop_macro("LOG_PRI")
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
similarity index 92%
rename from libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
rename to libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index df5df13..83190aa 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,6 +27,7 @@
 #pragma once
 
 #include <android/binder_auto_utils.h>
+#include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 
 #include <optional>
@@ -45,7 +46,7 @@
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
     if (static_cast<size_t>(length) > vec->max_size()) return false;
 
-    vec->resize(length);
+    vec->resize(static_cast<size_t>(length));
     *outBuffer = vec->data();
     return true;
 }
@@ -66,7 +67,7 @@
     *vec = std::optional<std::vector<T>>(std::vector<T>{});
 
     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
-    (*vec)->resize(length);
+    (*vec)->resize(static_cast<size_t>(length));
 
     *outBuffer = (*vec)->data();
     return true;
@@ -90,7 +91,7 @@
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
     if (static_cast<size_t>(length) > vec->max_size()) return false;
 
-    vec->resize(length);
+    vec->resize(static_cast<size_t>(length));
     return true;
 }
 
@@ -117,7 +118,7 @@
     *vec = std::optional<std::vector<T>>(std::vector<T>{});
 
     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
-    (*vec)->resize(length);
+    (*vec)->resize(static_cast<size_t>(length));
 
     return true;
 }
@@ -179,6 +180,7 @@
 static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel,
                                                                 const SpAIBinder& binder) {
     if (binder.get() == nullptr) {
+        syslog(LOG_ERR, "Passing null binder object as non-@nullable AIDL IBinder");
         return STATUS_UNEXPECTED_NULL;
     }
     return AParcel_writeStrongBinder(parcel, binder.get());
@@ -228,6 +230,7 @@
 static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor(
         AParcel* parcel, const ScopedFileDescriptor& fd) {
     if (fd.get() < 0) {
+        syslog(LOG_ERR, "Passing -1 file descriptor as non-@nullable AIDL ParcelFileDescriptor");
         return STATUS_UNEXPECTED_NULL;
     }
     return AParcel_writeParcelFileDescriptor(parcel, fd.get());
@@ -257,7 +260,7 @@
     if (length <= 0) return false;
 
     std::string* str = static_cast<std::string*>(stringData);
-    str->resize(length - 1);
+    str->resize(static_cast<size_t>(length) - 1);
     *buffer = &(*str)[0];
     return true;
 }
@@ -279,7 +282,7 @@
     }
 
     *str = std::optional<std::string>(std::string{});
-    (*str)->resize(length - 1);
+    (*str)->resize(static_cast<size_t>(length) - 1);
     *buffer = &(**str)[0];
     return true;
 }
@@ -303,7 +306,7 @@
     const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
     const std::string& element = vec->at(index);
 
-    *outLength = element.size();
+    *outLength = static_cast<int32_t>(element.size());
     return element.c_str();
 }
 
@@ -337,7 +340,7 @@
         return nullptr;
     }
 
-    *outLength = element->size();
+    *outLength = static_cast<int32_t>(element->size());
     return element->c_str();
 }
 
@@ -345,7 +348,7 @@
  * Convenience API for writing a std::string.
  */
 static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
-    return AParcel_writeString(parcel, str.c_str(), str.size());
+    return AParcel_writeString(parcel, str.c_str(), static_cast<int32_t>(str.size()));
 }
 
 /**
@@ -365,7 +368,7 @@
         return AParcel_writeString(parcel, nullptr, -1);
     }
 
-    return AParcel_writeString(parcel, str->c_str(), str->size());
+    return AParcel_writeString(parcel, str->c_str(), static_cast<int32_t>(str->size()));
 }
 
 /**
@@ -383,7 +386,7 @@
 static inline binder_status_t AParcel_writeVector(AParcel* parcel,
                                                   const std::vector<std::string>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+    return AParcel_writeStringArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
                                     AParcel_stdVectorStringElementGetter);
 }
 
@@ -404,7 +407,8 @@
 static inline binder_status_t AParcel_writeVector(
         AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+    return AParcel_writeStringArray(parcel, vectorData,
+                                    (vec ? static_cast<int32_t>(vec->size()) : -1),
                                     AParcel_nullableStdVectorStringElementGetter);
 }
 
@@ -545,7 +549,7 @@
 template <typename P>
 static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+    return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
                                         AParcel_writeStdVectorParcelableElement<P>);
 }
 
@@ -564,7 +568,7 @@
  * Writes a vector of int32_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
-    return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+    return AParcel_writeInt32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -597,7 +601,7 @@
  * Writes a vector of uint32_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
-    return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+    return AParcel_writeUint32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -631,7 +635,7 @@
  * Writes a vector of int64_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
-    return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+    return AParcel_writeInt64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -664,7 +668,7 @@
  * Writes a vector of uint64_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
-    return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+    return AParcel_writeUint64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -698,7 +702,7 @@
  * Writes a vector of float to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
-    return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+    return AParcel_writeFloatArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -731,7 +735,7 @@
  * Writes a vector of double to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
-    return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+    return AParcel_writeDoubleArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -764,8 +768,8 @@
  * Writes a vector of bool to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
-    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
-                                  AParcel_stdVectorGetter<bool>);
+    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
+                                  static_cast<int32_t>(vec.size()), AParcel_stdVectorGetter<bool>);
 }
 
 /**
@@ -801,7 +805,7 @@
  * Writes a vector of char16_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
-    return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+    return AParcel_writeCharArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -831,34 +835,35 @@
 }
 
 /**
- * Writes a vector of int8_t to the next location in a non-null parcel.
+ * Writes a vector of uint8_t to the next location in a non-null parcel.
  */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
-    return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint8_t>& vec) {
+    return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
+                                  static_cast<int32_t>(vec.size()));
 }
 
 /**
- * Writes an optional vector of int8_t to the next location in a non-null parcel.
+ * Writes an optional vector of uint8_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel,
-                                           const std::optional<std::vector<int8_t>>& vec) {
+                                           const std::optional<std::vector<uint8_t>>& vec) {
     if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1);
     return AParcel_writeVector(parcel, *vec);
 }
 
 /**
- * Reads a vector of int8_t from the next location in a non-null parcel.
+ * Reads a vector of uint8_t from the next location in a non-null parcel.
  */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint8_t>* vec) {
     void* vectorData = static_cast<void*>(vec);
     return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
 }
 
 /**
- * Reads an optional vector of int8_t from the next location in a non-null parcel.
+ * Reads an optional vector of uint8_t from the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_readVector(const AParcel* parcel,
-                                          std::optional<std::vector<int8_t>>* vec) {
+                                          std::optional<std::vector<uint8_t>>* vec) {
     void* vectorData = static_cast<void*>(vec);
     return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>);
 }
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
new file mode 100644
index 0000000..2277148
--- /dev/null
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcelable_utils.h
+ * @brief Helper for parcelable.
+ */
+
+#pragma once
+#include <android/binder_parcel_utils.h>
+#include <optional>
+
+namespace ndk {
+// Also see Parcelable.h in libbinder.
+typedef int32_t parcelable_stability_t;
+enum {
+    STABILITY_LOCAL,
+    STABILITY_VINTF,  // corresponds to @VintfStability
+};
+#define RETURN_ON_FAILURE(expr)                   \
+    do {                                          \
+        binder_status_t _status = (expr);         \
+        if (_status != STATUS_OK) return _status; \
+    } while (false)
+
+class AParcelableHolder {
+   public:
+    AParcelableHolder() = delete;
+    explicit AParcelableHolder(parcelable_stability_t stability)
+        : mParcel(AParcel_create()), mStability(stability) {}
+
+    virtual ~AParcelableHolder() = default;
+
+    binder_status_t writeToParcel(AParcel* parcel) const {
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+        if (__builtin_available(android 31, *)) {
+            int32_t size = AParcel_getDataSize(this->mParcel.get());
+            RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+        if (__builtin_available(android 31, *)) {
+            int32_t size = AParcel_getDataSize(this->mParcel.get());
+            RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+        return STATUS_OK;
+    }
+
+    binder_status_t readFromParcel(const AParcel* parcel) {
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+
+        RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+        int32_t dataSize;
+        binder_status_t status = AParcel_readInt32(parcel, &dataSize);
+
+        if (status != STATUS_OK || dataSize < 0) {
+            return status != STATUS_OK ? status : STATUS_BAD_VALUE;
+        }
+
+        int32_t dataStartPos = AParcel_getDataPosition(parcel);
+
+        if (dataStartPos > INT32_MAX - dataSize) {
+            return STATUS_BAD_VALUE;
+        }
+
+        if (__builtin_available(android 31, *)) {
+            status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+        } else {
+            status = STATUS_INVALID_OPERATION;
+        }
+        if (status != STATUS_OK) {
+            return status;
+        }
+        return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
+    }
+
+    template <typename T>
+    binder_status_t setParcelable(const T& p) {
+        if (this->mStability > T::_aidl_stability) {
+            return STATUS_BAD_VALUE;
+        }
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+        AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
+        p.writeToParcel(mParcel.get());
+        return STATUS_OK;
+    }
+
+    template <typename T>
+    binder_status_t getParcelable(std::optional<T>* ret) const {
+        const std::string parcelableDesc(T::descriptor);
+        AParcel_setDataPosition(mParcel.get(), 0);
+        if (__builtin_available(android 31, *)) {
+            if (AParcel_getDataSize(mParcel.get()) == 0) {
+                *ret = std::nullopt;
+                return STATUS_OK;
+            }
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+        std::string parcelableDescInParcel;
+        binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
+        if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
+            *ret = std::nullopt;
+            return status;
+        }
+        *ret = std::make_optional<T>();
+        status = (*ret)->readFromParcel(this->mParcel.get());
+        if (status != STATUS_OK) {
+            *ret = std::nullopt;
+            return status;
+        }
+        return STATUS_OK;
+    }
+
+    void reset() {
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        }
+    }
+
+    inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
+    inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
+    inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; }
+    inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
+    inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
+    inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
+
+   private:
+    mutable ndk::ScopedAParcel mParcel;
+    parcelable_stability_t mStability;
+};
+
+#undef RETURN_ON_FAILURE
+}  // namespace ndk
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 4560f22..bb70588 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
@@ -42,7 +43,6 @@
 
 #if __ANDROID_API__ >= 29
 
-// Also see TF_* in kernel's binder.h
 typedef uint32_t binder_flags_t;
 enum {
     /**
@@ -407,6 +407,8 @@
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
  *
+ * Warning: this may fail if the binder is dead.
+ *
  * Available since API level 29.
  *
  * \param binder the object to attach the class to.
@@ -640,6 +642,94 @@
 
 #endif  //__ANDROID_API__ >= 30
 
+#if __ANDROID_API__ >= 31
+
+/**
+ * Retrieve the class descriptor for the class.
+ *
+ * Available since API level 31.
+ *
+ * \param clazz the class to fetch the descriptor from
+ *
+ * \return the class descriptor string. This pointer will never be null; a
+ * descriptor is required to define a class. The pointer is owned by the class
+ * and will remain valid as long as the class does.
+ */
+const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUCED_IN(31);
+
+/**
+ * Whether AIBinder is less than another.
+ *
+ * This provides a per-process-unique total ordering of binders where a null
+ * AIBinder* object is considered to be before all other binder objects.
+ * For instance, two binders refer to the same object in a local or remote
+ * process when both AIBinder_lt(a, b) and AIBinder(b, a) are false. This API
+ * might be used to insert and lookup binders in binary search trees.
+ *
+ * AIBinder* pointers themselves actually also create a per-process-unique total
+ * ordering. However, this ordering is inconsistent with AIBinder_Weak_lt for
+ * remote binders. So, in general, this function should be preferred.
+ *
+ * Available since API level 31.
+ *
+ * \param lhs comparison object
+ * \param rhs comparison object
+ *
+ * \return whether "lhs < rhs" is true
+ */
+bool AIBinder_lt(const AIBinder* lhs, const AIBinder* rhs);
+
+/**
+ * Clone an AIBinder_Weak. Useful because even if a weak binder promotes to a
+ * null value, after further binder transactions, it may no longer promote to a
+ * null value.
+ *
+ * Available since API level 31.
+ *
+ * \param weak Object to clone
+ *
+ * \return clone of the input parameter. This must be deleted with
+ * AIBinder_Weak_delete. Null if weak input parameter is also null.
+ */
+AIBinder_Weak* AIBinder_Weak_clone(const AIBinder_Weak* weak);
+
+/**
+ * Whether AIBinder_Weak is less than another.
+ *
+ * This provides a per-process-unique total ordering of binders which is exactly
+ * the same as AIBinder_lt. Similarly, a null AIBinder_Weak* is considered to be
+ * ordered before all other weak references.
+ *
+ * This function correctly distinguishes binders even if one is deallocated. So,
+ * for instance, an AIBinder_Weak* entry representing a deleted binder will
+ * never compare as equal to an AIBinder_Weak* entry which represents a
+ * different allocation of a binder, even if the two binders were originally
+ * allocated at the same address. That is:
+ *
+ *     AIBinder* a = ...; // imagine this has address 0x8
+ *     AIBinder_Weak* bWeak = AIBinder_Weak_new(a);
+ *     AIBinder_decStrong(a); // a may be deleted, if this is the last reference
+ *     AIBinder* b = ...; // imagine this has address 0x8 (same address as b)
+ *     AIBinder_Weak* bWeak = AIBinder_Weak_new(b);
+ *
+ * Then when a/b are compared with other binders, their order will be preserved,
+ * and it will either be the case that AIBinder_Weak_lt(aWeak, bWeak) OR
+ * AIBinder_Weak_lt(bWeak, aWeak), but not both.
+ *
+ * Unlike AIBinder*, the AIBinder_Weak* addresses themselves have nothing to do
+ * with the underlying binder.
+ *
+ * Available since API level 31.
+ *
+ * \param lhs comparison object
+ * \param rhs comparison object
+ *
+ * \return whether "lhs < rhs" is true
+ */
+bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs);
+
+#endif  //__ANDROID_API__ >= 31
+
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 86b75b8..ab67017 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -26,6 +26,7 @@
 
 #pragma once
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <sys/cdefs.h>
 
@@ -1119,6 +1120,51 @@
 // @END-PRIMITIVE-READ-WRITE
 
 #endif  //__ANDROID_API__ >= 29
+/**
+ * Reset the parcel to the initial status.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to be reset.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_reset(AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Gets the size of the parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to get the size.
+ *
+ * \return The size of the parcel.
+ */
+int32_t AParcel_getDataSize(const AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Copy the data of a parcel to other parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param from The source
+ * \param to The detination
+ * \param start The position where the copied data starts.
+ * \param size The amount of data which will be copied.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size)
+        __INTRODUCED_IN(31);
+
+/**
+ * Creates a parcel.
+ *
+ * Available since API level 31.
+ *
+ * \return A parcel which is not related to any IBinder objects.
+ */
+AParcel* AParcel_create() __INTRODUCED_IN(31);
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index ab9a144..3a55f94 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -26,6 +26,7 @@
 #pragma once
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <sys/cdefs.h>
 
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
new file mode 100644
index 0000000..e315c79
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+// platform values for binder_flags_t
+enum {
+    /**
+     * The transaction and reply will be cleared by the kernel in read-only
+     * binder buffers storing transactions.
+     *
+     * Introduced in API level 31.
+     */
+    FLAG_CLEAR_BUF = 0x20,
+};
+
+/**
+ * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This
+ * must be called on a local binder server before it is sent out to any othe
+ * process. If this is a remote binder, it will abort. If the kernel doesn't
+ * support this feature, you'll always get null from AIBinder_getCallingSid.
+ *
+ * \param binder local server binder to request security contexts on
+ */
+__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid)
+        __INTRODUCED_IN(31);
+
+/**
+ * Returns the selinux context of the callee.
+ *
+ * In order for this to work, the following conditions must be met:
+ * - The kernel must be new enough to support this feature.
+ * - The server must have called AIBinder_setRequestingSid.
+ * - The callee must be a remote process.
+ *
+ * \return security context or null if unavailable. The lifetime of this context
+ * is the lifetime of the transaction.
+ */
+__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h
new file mode 100644
index 0000000..f0c00e8
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
+
+#include <android/binder_ibinder.h>
+#include <binder/IBinder.h>
+
+/**
+ * Get libbinder version of binder from AIBinder.
+ *
+ * WARNING: function calls to a local object on the other side of this function
+ * will parcel. When converting between binders, keep in mind it is not as
+ * efficient as a direct function call.
+ *
+ * \param binder binder with ownership retained by the client
+ * \return platform binder object
+ */
+android::sp<android::IBinder> AIBinder_toPlatformBinder(AIBinder* binder);
+
+/**
+ * Get libbinder_ndk version of binder from platform binder.
+ *
+ * WARNING: function calls to a local object on the other side of this function
+ * will parcel. When converting between binders, keep in mind it is not as
+ * efficient as a direct function call.
+ *
+ * \param binder platform binder which may be from anywhere (doesn't have to be
+ * created with libbinder_ndK)
+ * \return binder with one reference count of ownership given to the client. See
+ * AIBinder_decStrong
+ */
+AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder);
+
+#endif
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 055c79b..2784aa8 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,6 +18,7 @@
 
 #include <android/binder_ibinder.h>
 #include <android/binder_status.h>
+#include <sys/cdefs.h>
 
 __BEGIN_DECLS
 
@@ -28,9 +29,9 @@
  * \param binder object to register globally with the service manager.
  * \param instance identifier of the service. This will be used to lookup the service.
  *
- * \return STATUS_OK on success.
+ * \return EX_NONE on success.
  */
-binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
+binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance);
 
 /**
  * Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -50,4 +51,47 @@
  */
 __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
 
+/**
+ * Registers a lazy service with the default service manager under the 'instance' name.
+ * Does not take ownership of binder.
+ * The service must be configured statically with init so it can be restarted with
+ * ctl.interface.* messages from servicemanager.
+ * AServiceManager_registerLazyService cannot safely be used with AServiceManager_addService
+ * in the same process. If one service is registered with AServiceManager_registerLazyService,
+ * the entire process will have its lifetime controlled by servicemanager.
+ * Instead, all services in the process should be registered using
+ * AServiceManager_registerLazyService.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance)
+        __INTRODUCED_IN(31);
+
+/**
+ * Gets a binder object with this specific instance name. Efficiently waits for the service.
+ * If the service is not declared, it will wait indefinitely. Requires the threadpool
+ * to be started in the service.
+ * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
+ * for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ *
+ * \return service if registered, null if not.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_waitForService(const char* instance)
+        __INTRODUCED_IN(31);
+
+/**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * \param instance identifier of the service.
+ *
+ * \return true on success, meaning AServiceManager_waitForService should always
+ *    be able to return the service.
+ */
+bool AServiceManager_isDeclared(const char* instance) __INTRODUCED_IN(31);
+
 __END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
index ac46cb8..d54c1a1 100644
--- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -20,6 +20,10 @@
 
 __BEGIN_DECLS
 
+#if defined(__ANDROID_APEX__) || defined(__ANDROID_VNDK__)
+#error this is only for platform code
+#endif
+
 /**
  * Gets whether or not FDs are allowed by this AParcel
  *
@@ -29,4 +33,15 @@
  */
 bool AParcel_getAllowFds(const AParcel*);
 
-__END_DECLS
\ No newline at end of file
+/**
+ * Data written to the parcel will be zero'd before being deleted or realloced.
+ *
+ * The main use of this is marking a parcel that will be used in a transaction
+ * with FLAG_CLEAR_BUF. When FLAG_CLEAR_BUF is used, the reply parcel will
+ * automatically be marked as sensitive when it is created.
+ *
+ * \param parcel The parcel to clear associated data from.
+ */
+void AParcel_markSensitive(const AParcel* parcel);
+
+__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index fdefbb4..f408fad 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -19,10 +19,15 @@
 #include <stdint.h>
 #include <sys/cdefs.h>
 
+#include <android/binder_status.h>
+
 __BEGIN_DECLS
 
 /**
  * This creates a threadpool for incoming binder transactions if it has not already been created.
+ *
+ * When using this, it is expected that ABinderProcess_setupPolling and
+ * ABinderProcess_handlePolledCommands are not used.
  */
 void ABinderProcess_startThreadPool();
 /**
@@ -37,4 +42,27 @@
  */
 void ABinderProcess_joinThreadPool();
 
+/**
+ * This gives you an fd to wait on. Whenever data is available on the fd,
+ * ABinderProcess_handlePolledCommands can be called to handle binder queries.
+ * This is expected to be used in a single threaded process which waits on
+ * events from multiple different fds.
+ *
+ * When using this, it is expected ABinderProcess_startThreadPool and
+ * ABinderProcess_joinThreadPool are not used.
+ *
+ * \param fd out param corresponding to the binder domain opened in this
+ * process.
+ * \return STATUS_OK on success
+ */
+__attribute__((weak)) binder_status_t ABinderProcess_setupPolling(int* fd) __INTRODUCED_IN(31);
+
+/**
+ * This will handle all queued binder commands in this process and then return.
+ * It is expected to be called whenever there is data on the fd.
+ *
+ * \return STATUS_OK on success
+ */
+__attribute__((weak)) binder_status_t ABinderProcess_handlePolledCommands() __INTRODUCED_IN(31);
+
 __END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index a9eba47..9a93bf3 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -95,8 +95,6 @@
     AServiceManager_addService; # apex llndk
     AServiceManager_checkService; # apex llndk
     AServiceManager_getService; # apex llndk
-  local:
-    *;
 };
 
 LIBBINDER_NDK30 { # introduced=30
@@ -111,11 +109,36 @@
     AIBinder_markVendorStability; # llndk
     AIBinder_markVintfStability; # apex llndk
     AIBinder_Class_setHandleShellCommand; # apex llndk
-  local:
-    *;
+};
+
+LIBBINDER_NDK31 { # introduced=31
+  global:
+    ABinderProcess_handlePolledCommands; # apex
+    ABinderProcess_setupPolling; # apex
+    AIBinder_getCallingSid; # apex
+    AIBinder_setRequestingSid; # apex
+    AServiceManager_isDeclared; # apex llndk
+    AServiceManager_registerLazyService; # llndk
+    AServiceManager_waitForService; # apex llndk
+
+    AIBinder_Class_getDescriptor;
+    AIBinder_Weak_clone;
+    AIBinder_Weak_lt;
+    AIBinder_lt;
+    AParcel_appendFrom;
+    AParcel_create;
+    AParcel_getDataSize;
+    AParcel_reset;
 };
 
 LIBBINDER_NDK_PLATFORM {
   global:
     AParcel_getAllowFds;
+    AParcel_markSensitive;
+    extern "C++" {
+        AIBinder_fromPlatformBinder*;
+        AIBinder_toPlatformBinder*;
+    };
+  local:
+    *;
 };
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c33c44f..ec7c7d8 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -226,6 +226,10 @@
     return parcel->get()->dataPosition();
 }
 
+void AParcel_markSensitive(const AParcel* parcel) {
+    return parcel->get()->markSensitive();
+}
+
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
     sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr;
     return parcel->get()->writeStrongBinder(writeBinder);
@@ -257,7 +261,7 @@
 }
 
 binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
-    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+    std::optional<ParcelFileDescriptor> parcelFd;
 
     status_t status = parcel->get()->readParcelable(&parcelFd);
     if (status != STATUS_OK) return PruneStatusT(status);
@@ -272,7 +276,7 @@
 }
 
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
-    return PruneStatusT(status->get()->writeToParcel(parcel->get()));
+    return PruneStatusT(status->get().writeToParcel(parcel->get()));
 }
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
     ::android::binder::Status bstatus;
@@ -647,4 +651,22 @@
     return parcel->get()->allowFds();
 }
 
+binder_status_t AParcel_reset(AParcel* parcel) {
+    parcel->get()->freeData();
+    return STATUS_OK;
+}
+
+int32_t AParcel_getDataSize(const AParcel* parcel) {
+    return parcel->get()->dataSize();
+}
+
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size) {
+    status_t status = to->get()->appendFrom(from->get(), start, size);
+    return PruneStatusT(status);
+}
+
+AParcel* AParcel_create() {
+    return new AParcel(nullptr);
+}
+
 // @END
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index c89caaf..ac582a4 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -34,3 +34,11 @@
 void ABinderProcess_joinThreadPool() {
     IPCThreadState::self()->joinThreadPool();
 }
+
+binder_status_t ABinderProcess_setupPolling(int* fd) {
+    return IPCThreadState::self()->setupPolling(fd);
+}
+
+binder_status_t ABinderProcess_handlePolledCommands() {
+    return IPCThreadState::self()->handlePolledCommands();
+}
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index d0b166d..c782d47 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -20,6 +20,7 @@
 #include "status_internal.h"
 
 #include <binder/IServiceManager.h>
+#include <binder/LazyServiceRegistrar.h>
 
 using ::android::defaultServiceManager;
 using ::android::IBinder;
@@ -28,14 +29,14 @@
 using ::android::status_t;
 using ::android::String16;
 
-binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance) {
+binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance) {
     if (binder == nullptr || instance == nullptr) {
-        return STATUS_UNEXPECTED_NULL;
+        return EX_ILLEGAL_ARGUMENT;
     }
 
     sp<IServiceManager> sm = defaultServiceManager();
-    status_t status = sm->addService(String16(instance), binder->getBinder());
-    return PruneStatusT(status);
+    status_t exception = sm->addService(String16(instance), binder->getBinder());
+    return PruneException(exception);
 }
 AIBinder* AServiceManager_checkService(const char* instance) {
     if (instance == nullptr) {
@@ -61,3 +62,33 @@
     AIBinder_incStrong(ret.get());
     return ret.get();
 }
+binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char* instance) {
+    if (binder == nullptr || instance == nullptr) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+
+    auto serviceRegistrar = android::binder::LazyServiceRegistrar::getInstance();
+    status_t status = serviceRegistrar.registerService(binder->getBinder(), instance);
+
+    return PruneStatusT(status);
+}
+AIBinder* AServiceManager_waitForService(const char* instance) {
+    if (instance == nullptr) {
+        return nullptr;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->waitForService(String16(instance));
+
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
+bool AServiceManager_isDeclared(const char* instance) {
+    if (instance == nullptr) {
+        return false;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    return sm->isDeclared(String16(instance));
+}
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index 87e1341..a8ae441 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -23,7 +23,8 @@
 using ::android::binder::Status;
 
 AStatus* AStatus_newOk() {
-    return new AStatus();
+    static AStatus status = AStatus();
+    return &status;
 }
 
 AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
@@ -47,27 +48,27 @@
 }
 
 bool AStatus_isOk(const AStatus* status) {
-    return status->get()->isOk();
+    return status->get().isOk();
 }
 
 binder_exception_t AStatus_getExceptionCode(const AStatus* status) {
-    return PruneException(status->get()->exceptionCode());
+    return PruneException(status->get().exceptionCode());
 }
 
 int32_t AStatus_getServiceSpecificError(const AStatus* status) {
-    return status->get()->serviceSpecificErrorCode();
+    return status->get().serviceSpecificErrorCode();
 }
 
 binder_status_t AStatus_getStatus(const AStatus* status) {
-    return PruneStatusT(status->get()->transactionError());
+    return PruneStatusT(status->get().transactionError());
 }
 
 const char* AStatus_getMessage(const AStatus* status) {
-    return status->get()->exceptionMessage().c_str();
+    return status->get().exceptionMessage().c_str();
 }
 
 const char* AStatus_getDescription(const AStatus* status) {
-    android::String8 description = status->get()->toString8();
+    android::String8 description = status->get().toString8();
     char* cStr = new char[description.size() + 1];
     memcpy(cStr, description.c_str(), description.size() + 1);
     return cStr;
@@ -78,7 +79,9 @@
 }
 
 void AStatus_delete(AStatus* status) {
-    delete status;
+    if (status != AStatus_newOk()) {
+        delete status;
+    }
 }
 
 binder_status_t PruneStatusT(status_t status) {
@@ -123,8 +126,8 @@
             return STATUS_UNKNOWN_ERROR;
 
         default:
-            LOG(WARNING) << __func__
-                         << ": Unknown status_t pruned into STATUS_UNKNOWN_ERROR: " << status;
+            LOG(WARNING) << __func__ << ": Unknown status_t (" << status
+                         << ") pruned into STATUS_UNKNOWN_ERROR";
             return STATUS_UNKNOWN_ERROR;
     }
 }
@@ -155,8 +158,8 @@
             return EX_TRANSACTION_FAILED;
 
         default:
-            LOG(WARNING) << __func__
-                         << ": Unknown status_t pruned into EX_TRANSACTION_FAILED: " << exception;
+            LOG(WARNING) << __func__ << ": Unknown binder exception (" << exception
+                         << ") pruned into EX_TRANSACTION_FAILED";
             return EX_TRANSACTION_FAILED;
     }
 }
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index f6227f7..cb96e48 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -25,8 +25,7 @@
     AStatus() {}  // ok
     explicit AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
 
-    ::android::binder::Status* get() { return &mStatus; }
-    const ::android::binder::Status* get() const { return &mStatus; }
+    const ::android::binder::Status& get() const { return mStatus; }
 
    private:
     ::android::binder::Status mStatus;
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/tests/Android.bp
similarity index 91%
rename from libs/binder/ndk/test/Android.bp
rename to libs/binder/ndk/tests/Android.bp
index 5f5265c..46e6270 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -40,6 +40,7 @@
 cc_defaults {
     name: "test_libbinder_ndk_test_defaults",
     defaults: ["test_libbinder_ndk_defaults"],
+    // critical that libbinder/libbinder_ndk are shared for VTS
     shared_libs: [
         "libandroid_runtime_lazy",
         "libbase",
@@ -63,11 +64,8 @@
         "IBinderNdkUnitTest-cpp",
         "IBinderNdkUnitTest-ndk_platform",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts"],
     require_root: true,
-
-    // force since binderVendorDoubleLoadTest has its own
-    auto_gen_config: true,
 }
 
 cc_test {
@@ -81,13 +79,15 @@
         "IBinderVendorDoubleLoadTest-ndk_platform",
         "libbinder_aidl_test_stub-ndk_platform",
     ],
+    // critical that libbinder/libbinder_ndk are shared for VTS
     shared_libs: [
         "libbase",
         "libbinder",
         "libbinder_ndk",
         "libutils",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts"],
+    require_root: true,
 }
 
 aidl_interface {
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
similarity index 93%
rename from libs/binder/ndk/test/IBinderNdkUnitTest.aidl
rename to libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
index 6e8e463..dc77467d 100644
--- a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
+++ b/libs/binder/ndk/tests/IBinderNdkUnitTest.aidl
@@ -22,6 +22,10 @@
 import IEmpty;
 
 interface IBinderNdkUnitTest {
+    int repeatInt(int a);
+
     void takeInterface(IEmpty test);
     void forceFlushCommands();
+
+    boolean getsRequestedSid();
 }
diff --git a/libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl b/libs/binder/ndk/tests/IBinderVendorDoubleLoadTest.aidl
similarity index 100%
rename from libs/binder/ndk/test/IBinderVendorDoubleLoadTest.aidl
rename to libs/binder/ndk/tests/IBinderVendorDoubleLoadTest.aidl
diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/tests/IEmpty.aidl
similarity index 100%
rename from libs/binder/ndk/test/IEmpty.aidl
rename to libs/binder/ndk/tests/IEmpty.aidl
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
similarity index 100%
rename from libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
rename to libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/tests/iface.cpp
similarity index 98%
rename from libs/binder/ndk/test/iface.cpp
rename to libs/binder/ndk/tests/iface.cpp
index a588985..2afe5d2 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -25,7 +25,7 @@
 
 const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
 const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
-const char* kIFooDescriptor = "my-special-IFoo-class";
+const char* IFoo::kIFooDescriptor = "my-special-IFoo-class";
 
 struct IFoo_Class_Data {
     sp<IFoo> foo;
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
similarity index 97%
rename from libs/binder/ndk/test/include/iface/iface.h
rename to libs/binder/ndk/tests/include/iface/iface.h
index d9dd64b..7408d0c 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -27,6 +27,7 @@
    public:
     static const char* kSomeInstanceName;
     static const char* kInstanceNameToDieFor;
+    static const char* kIFooDescriptor;
 
     static AIBinder_Class* kClass;
 
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
similarity index 68%
rename from libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
rename to libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index aaf36b9..0d1989e 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -19,10 +19,13 @@
 #include <aidl/BnEmpty.h>
 #include <android-base/logging.h>
 #include <android/binder_ibinder_jni.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_libbinder.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <iface/iface.h>
+#include <utils/Looper.h>
 
 // warning: this is assuming that libbinder_ndk is using the same copy
 // of libbinder that we are.
@@ -34,14 +37,21 @@
 #include <sys/prctl.h>
 #include <chrono>
 #include <condition_variable>
+#include <iostream>
 #include <mutex>
+#include "android/binder_ibinder.h"
 
 using namespace android;
 
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
 constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
+constexpr char kLazyBinderNdkUnitTestService[] = "LazyBinderNdkUnitTest";
 
 class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
+    ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) {
+        *out = in;
+        return ndk::ScopedAStatus::ok();
+    }
     ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) {
         (void)empty;
         return ndk::ScopedAStatus::ok();
@@ -52,6 +62,12 @@
         android::IPCThreadState::self()->flushCommands();
         return ndk::ScopedAStatus::ok();
     }
+    ndk::ScopedAStatus getsRequestedSid(bool* out) {
+        const char* sid = AIBinder_getCallingSid();
+        std::cout << "Got security context: " << (sid ?: "null") << std::endl;
+        *out = sid != nullptr;
+        return ndk::ScopedAStatus::ok();
+    }
     binder_status_t handleShellCommand(int /*in*/, int out, int /*err*/, const char** args,
                                        uint32_t numArgs) override {
         for (uint32_t i = 0; i < numArgs; i++) {
@@ -66,11 +82,15 @@
     ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
-    binder_status_t status =
-            AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService);
+    auto binder = service->asBinder();
 
-    if (status != STATUS_OK) {
-        LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService;
+    AIBinder_setRequestingSid(binder.get(), true);
+
+    binder_exception_t exception =
+            AServiceManager_addService(binder.get(), kBinderNdkUnitTestService);
+
+    if (exception != EX_NONE) {
+        LOG(FATAL) << "Could not register: " << exception << " " << kBinderNdkUnitTestService;
     }
 
     ABinderProcess_joinThreadPool();
@@ -92,12 +112,53 @@
     }
 };
 
-int manualService(const char* instance) {
-    ABinderProcess_setThreadPoolMaxThreadCount(0);
-
+void manualService(const char* instance) {
     // Strong reference to MyFoo kept by service manager.
-    binder_status_t status = (new MyFoo)->addService(instance);
+    binder_exception_t exception = (new MyFoo)->addService(instance);
 
+    if (exception != EX_NONE) {
+        LOG(FATAL) << "Could not register: " << exception << " " << instance;
+    }
+}
+int manualPollingService(const char* instance) {
+    int fd;
+    CHECK(STATUS_OK == ABinderProcess_setupPolling(&fd));
+    manualService(instance);
+
+    class Handler : public LooperCallback {
+        int handleEvent(int /*fd*/, int /*events*/, void* /*data*/) override {
+            ABinderProcess_handlePolledCommands();
+            return 1;  // Continue receiving callbacks.
+        }
+    };
+
+    sp<Looper> looper = Looper::prepare(0 /* opts */);
+    looper->addFd(fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, new Handler(), nullptr /*data*/);
+    // normally, would add additional fds
+    while (true) {
+        looper->pollAll(-1 /* timeoutMillis */);
+    }
+    return 1;  // should not reach
+}
+int manualThreadPoolService(const char* instance) {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    manualService(instance);
+    ABinderProcess_joinThreadPool();
+    return 1;
+}
+
+int lazyService(const char* instance) {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    // Wait to register this service to make sure the main test process will
+    // actually wait for the service to be available. Tested with sleep(60),
+    // and reduced for sake of time.
+    sleep(1);
+    // Strong reference to MyBinderNdkUnitTest kept by service manager.
+    // This is just for testing, it has no corresponding init behavior.
+    auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+    auto binder = service->asBinder();
+
+    binder_status_t status = AServiceManager_registerLazyService(binder.get(), instance);
     if (status != STATUS_OK) {
         LOG(FATAL) << "Could not register: " << status << " " << instance;
     }
@@ -107,11 +168,10 @@
     return 1;  // should not return
 }
 
-// This is too slow
-// TEST(NdkBinder, GetServiceThatDoesntExist) {
-//     sp<IFoo> foo = IFoo::getService("asdfghkl;");
-//     EXPECT_EQ(nullptr, foo.get());
-// }
+TEST(NdkBinder, GetServiceThatDoesntExist) {
+    sp<IFoo> foo = IFoo::getService("asdfghkl;");
+    EXPECT_EQ(nullptr, foo.get());
+}
 
 TEST(NdkBinder, CheckServiceThatDoesntExist) {
     AIBinder* binder = AServiceManager_checkService("asdfghkl;");
@@ -155,6 +215,33 @@
     EXPECT_EQ(2, out);
 }
 
+TEST(NdkBinder, GetLazyService) {
+    // Not declared in the vintf manifest
+    ASSERT_FALSE(AServiceManager_isDeclared(kLazyBinderNdkUnitTestService));
+    ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
+    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+            aidl::IBinderNdkUnitTest::fromBinder(binder);
+    ASSERT_NE(service, nullptr);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+}
+
+// This is too slow
+TEST(NdkBinder, CheckLazyServiceShutDown) {
+    ndk::SpAIBinder binder(AServiceManager_waitForService(kLazyBinderNdkUnitTestService));
+    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+            aidl::IBinderNdkUnitTest::fromBinder(binder);
+    ASSERT_NE(service, nullptr);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+    binder = nullptr;
+    service = nullptr;
+    IPCThreadState::self()->flushCommands();
+    // Make sure the service is dead after some time of no use
+    sleep(10);
+    ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
+}
+
 void LambdaOnDeath(void* cookie) {
     auto onDeath = static_cast<std::function<void(void)>*>(cookie);
     (*onDeath)();
@@ -238,11 +325,20 @@
     }
 };
 
+TEST(NdkBinder, AddNullService) {
+    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, AServiceManager_addService(nullptr, "any-service-name"));
+}
+
+TEST(NdkBinder, AddInvalidServiceName) {
+    sp<IFoo> foo = new MyTestFoo;
+    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, foo->addService("!@#$%^&"));
+}
+
 TEST(NdkBinder, GetServiceInProcess) {
     static const char* kInstanceName = "test-get-service-in-process";
 
     sp<IFoo> foo = new MyTestFoo;
-    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName));
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName));
 
     sp<IFoo> getFoo = IFoo::getService(kInstanceName);
     EXPECT_EQ(foo.get(), getFoo.get());
@@ -279,8 +375,7 @@
 
     AIBinder_decStrong(binder);
 
-    // assert because would need to decStrong if non-null and we shouldn't need to add a no-op here
-    ASSERT_NE(nullptr, AIBinder_Weak_promote(wBinder));
+    ASSERT_EQ(nullptr, AIBinder_Weak_promote(wBinder));
 
     AIBinder_Weak_delete(wBinder);
 }
@@ -289,11 +384,21 @@
     static const char* kInstanceName1 = "test-multi-1";
     static const char* kInstanceName2 = "test-multi-2";
     sp<IFoo> foo = new MyTestFoo;
-    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName1));
-    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2));
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName1));
+    EXPECT_EQ(EX_NONE, foo->addService(kInstanceName2));
     EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
 }
 
+TEST(NdkBinder, RequestedSidWorks) {
+    ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService));
+    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+            aidl::IBinderNdkUnitTest::fromBinder(binder);
+
+    bool gotSid = false;
+    EXPECT_TRUE(service->getsRequestedSid(&gotSid).isOk());
+    EXPECT_TRUE(gotSid);
+}
+
 TEST(NdkBinder, SentAidlBinderCanBeDestroyed) {
     static volatile bool destroyed = false;
     static std::mutex dMutex;
@@ -328,6 +433,30 @@
     EXPECT_TRUE(destroyed);
 }
 
+TEST(NdkBinder, ConvertToPlatformBinder) {
+    for (const ndk::SpAIBinder& binder :
+         {// remote
+          ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)),
+          // local
+          ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
+        // convert to platform binder
+        EXPECT_NE(binder.get(), nullptr);
+        sp<IBinder> platformBinder = AIBinder_toPlatformBinder(binder.get());
+        EXPECT_NE(platformBinder.get(), nullptr);
+        auto proxy = interface_cast<IBinderNdkUnitTest>(platformBinder);
+        EXPECT_NE(proxy, nullptr);
+
+        // use platform binder
+        int out;
+        EXPECT_TRUE(proxy->repeatInt(4, &out).isOk());
+        EXPECT_EQ(out, 4);
+
+        // convert back
+        ndk::SpAIBinder backBinder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(platformBinder));
+        EXPECT_EQ(backBinder.get(), binder.get());
+    }
+}
+
 class MyResultReceiver : public BnResultReceiver {
    public:
     Mutex mMutex;
@@ -414,16 +543,24 @@
     EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"}));
 }
 
+TEST(NdkBinder, GetClassInterfaceDescriptor) {
+    ASSERT_STREQ(IFoo::kIFooDescriptor, AIBinder_Class_getDescriptor(IFoo::kClass));
+}
+
 int main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
 
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
-        return manualService(IFoo::kInstanceNameToDieFor);
+        return manualThreadPoolService(IFoo::kInstanceNameToDieFor);
     }
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
-        return manualService(IFoo::kSomeInstanceName);
+        return manualPollingService(IFoo::kSomeInstanceName);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return lazyService(kLazyBinderNdkUnitTestService);
     }
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
similarity index 67%
rename from libs/binder/fuzzer/Android.bp
rename to libs/binder/parcel_fuzzer/Android.bp
index d2b4d52..3e6fe99 100644
--- a/libs/binder/fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -12,10 +12,13 @@
         "binder_ndk.cpp",
         "hwbinder.cpp",
         "main.cpp",
+        "random_fd.cpp",
+        "random_parcel.cpp",
         "util.cpp",
     ],
     static_libs: [
         "libbase",
+        "libbinder_random_parcel",
         "libcgrouprc",
         "libcgrouprc_format",
         "libcutils",
@@ -45,3 +48,25 @@
     // produced, you may find uncommenting the below line very useful.
     // cflags: ["-DENABLE_LOG_FUZZ"],
 }
+
+cc_library_static {
+    name: "libbinder_random_parcel",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
+    srcs: [
+        "random_fd.cpp",
+        "random_parcel.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+    local_include_dirs: ["include_random_parcel"],
+    export_include_dirs: ["include_random_parcel"],
+}
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/parcel_fuzzer/binder.cpp
similarity index 80%
rename from libs/binder/fuzzer/binder.cpp
rename to libs/binder/parcel_fuzzer/binder.cpp
index 52c730c..394d222 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/parcel_fuzzer/binder.cpp
@@ -19,6 +19,8 @@
 #include "util.h"
 
 #include <android/os/IServiceManager.h>
+#include <binder/ParcelableHolder.h>
+#include <binder/PersistableBundle.h>
 
 using ::android::status_t;
 
@@ -84,6 +86,8 @@
     PARCEL_READ_WITH_STATUS(T, FUN), \
     PARCEL_READ_NO_STATUS(T, FUN)
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 // clang-format off
 std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
     PARCEL_READ_NO_STATUS(size_t, dataSize),
@@ -128,13 +132,13 @@
     PARCEL_READ_OPT_STATUS(uint64_t, readUint64),
     PARCEL_READ_OPT_STATUS(float, readFloat),
     PARCEL_READ_OPT_STATUS(double, readDouble),
-    PARCEL_READ_OPT_STATUS(intptr_t, readIntPtr),
     PARCEL_READ_OPT_STATUS(bool, readBool),
     PARCEL_READ_OPT_STATUS(char16_t, readChar),
     PARCEL_READ_OPT_STATUS(int8_t, readByte),
 
     PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
+    PARCEL_READ_WITH_STATUS(std::optional<std::string>, readUtf8FromUtf16),
     [] (const ::android::Parcel& p, uint8_t /*data*/) {
         FUZZ_LOG() << "about to read c-str";
         const char* str = p.readCString();
@@ -143,6 +147,7 @@
     PARCEL_READ_OPT_STATUS(android::String8, readString8),
     PARCEL_READ_OPT_STATUS(android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
+    PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
     [] (const ::android::Parcel& p, uint8_t /*data*/) {
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outLen = 0;
@@ -156,17 +161,22 @@
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(std::vector<ByteEnum>, readEnumVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<ByteEnum>>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<ByteEnum>>, readEnumVector),
     // PARCEL_READ_WITH_STATUS(std::vector<IntEnum>, readEnumVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<IntEnum>>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<IntEnum>>, readEnumVector),
     // PARCEL_READ_WITH_STATUS(std::vector<LongEnum>, readEnumVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<LongEnum>>, readEnumVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<LongEnum>>, readEnumVector),
 
     // only reading one parcelable type for now
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<ExampleParcelable>>>, readParcelableVector),
     // PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
     PARCEL_READ_WITH_STATUS(ExampleParcelable, readParcelable),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<ExampleParcelable>, readParcelable),
+    PARCEL_READ_WITH_STATUS(std::optional<ExampleParcelable>, readParcelable),
 
     // only reading one binder type for now
     PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
@@ -174,30 +184,42 @@
 
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
+    // PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
     // PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::IBinder>>, readStrongBinderVector),
 
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int8_t>>, readByteVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int8_t>>, readByteVector),
     // PARCEL_READ_WITH_STATUS(std::vector<int8_t>, readByteVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, readByteVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, readByteVector),
     // PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, readByteVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int32_t>>, readInt32Vector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int32_t>>, readInt32Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<int32_t>, readInt32Vector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int64_t>>, readInt64Vector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int64_t>>, readInt64Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<int64_t>, readInt64Vector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint64_t>>, readUint64Vector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint64_t>>, readUint64Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<uint64_t>, readUint64Vector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<float>>, readFloatVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<float>>, readFloatVector),
     // PARCEL_READ_WITH_STATUS(std::vector<float>, readFloatVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<double>>, readDoubleVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<double>>, readDoubleVector),
     // PARCEL_READ_WITH_STATUS(std::vector<double>, readDoubleVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<bool>>, readBoolVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<bool>>, readBoolVector),
     // PARCEL_READ_WITH_STATUS(std::vector<bool>, readBoolVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<char16_t>>, readCharVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<char16_t>>, readCharVector),
     // PARCEL_READ_WITH_STATUS(std::vector<char16_t>, readCharVector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<android::String16>>>, readString16Vector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<android::String16>>>, readString16Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<android::String16>, readString16Vector),
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<std::string>>>, readUtf8VectorFromUtf16Vector),
     // PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
 
     [] (const android::Parcel& p, uint8_t /*len*/) {
@@ -234,6 +256,7 @@
 
     // TODO(b/131868573): can force read of arbitrarily sized vector
     // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
+    // PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
     // PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
 
     [] (const android::Parcel& p, uint8_t len) {
@@ -251,5 +274,21 @@
     PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
     PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
+
+    // additional parcelable objects defined in libbinder
+    [] (const ::android::Parcel& p, uint8_t data) {
+        using ::android::os::ParcelableHolder;
+        using ::android::Parcelable;
+        FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
+        Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
+        if ( (data & 1) == 1 ) {
+            stability = Parcelable::Stability::STABILITY_VINTF;
+        }
+        ParcelableHolder t = ParcelableHolder(stability);
+        status_t status = p.readParcelable(&t);
+        FUZZ_LOG() << "ParcelableHolder status: " << status;
+    },
+    PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
 };
 // clang-format on
+#pragma clang diagnostic pop
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/parcel_fuzzer/binder.h
similarity index 98%
rename from libs/binder/fuzzer/binder.h
rename to libs/binder/parcel_fuzzer/binder.h
index b224ef4..0c51d68 100644
--- a/libs/binder/fuzzer/binder.h
+++ b/libs/binder/parcel_fuzzer/binder.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <binder/Parcel.h>
 #include <vector>
diff --git a/libs/binder/fuzzer/binder_ndk.cpp b/libs/binder/parcel_fuzzer/binder_ndk.cpp
similarity index 83%
rename from libs/binder/fuzzer/binder_ndk.cpp
rename to libs/binder/parcel_fuzzer/binder_ndk.cpp
index 29da8f7..008780c 100644
--- a/libs/binder/fuzzer/binder_ndk.cpp
+++ b/libs/binder/parcel_fuzzer/binder_ndk.cpp
@@ -18,6 +18,7 @@
 #include "binder_ndk.h"
 
 #include <android/binder_parcel_utils.h>
+#include <android/binder_parcelable_utils.h>
 
 #include "util.h"
 
@@ -54,6 +55,25 @@
             binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
             FUZZ_LOG() << "read status header: " << status;
         },
+        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+            FUZZ_LOG() << "about to getDataSize the parcel";
+            AParcel_getDataSize(p.aParcel());
+            FUZZ_LOG() << "getDataSize done";
+        },
+        [](const NdkParcelAdapter& p, uint8_t data) {
+            FUZZ_LOG() << "about to read a ParcelableHolder";
+            ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+            binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
+            FUZZ_LOG() << "read the ParcelableHolder: " << status;
+        },
+        [](const NdkParcelAdapter& p, uint8_t data) {
+            FUZZ_LOG() << "about to appendFrom";
+            AParcel* parcel = AParcel_create();
+            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+            AParcel_delete(parcel);
+            FUZZ_LOG() << "appendFrom: " << status;
+        },
+
         PARCEL_READ(int32_t, AParcel_readInt32),
         PARCEL_READ(uint32_t, AParcel_readUint32),
         PARCEL_READ(int64_t, AParcel_readInt64),
diff --git a/libs/binder/fuzzer/binder_ndk.h b/libs/binder/parcel_fuzzer/binder_ndk.h
similarity index 91%
rename from libs/binder/fuzzer/binder_ndk.h
rename to libs/binder/parcel_fuzzer/binder_ndk.h
index 622cafc..e69d9c1 100644
--- a/libs/binder/fuzzer/binder_ndk.h
+++ b/libs/binder/parcel_fuzzer/binder_ndk.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <android/binder_auto_utils.h>
 #include <vector>
@@ -31,6 +32,9 @@
     const AParcel* aParcel() const { return mParcel.get(); }
     AParcel* aParcel() { return mParcel.get(); }
 
+    android::Parcel* parcel() { return aParcel()->get(); }
+
+    const uint8_t* data() const { return aParcel()->get()->data(); }
     size_t dataSize() const { return aParcel()->get()->dataSize(); }
     size_t dataAvail() const { return aParcel()->get()->dataAvail(); }
     size_t dataPosition() const { return aParcel()->get()->dataPosition(); }
diff --git a/libs/binder/fuzzer/hwbinder.cpp b/libs/binder/parcel_fuzzer/hwbinder.cpp
similarity index 100%
rename from libs/binder/fuzzer/hwbinder.cpp
rename to libs/binder/parcel_fuzzer/hwbinder.cpp
diff --git a/libs/binder/fuzzer/hwbinder.h b/libs/binder/parcel_fuzzer/hwbinder.h
similarity index 98%
rename from libs/binder/fuzzer/hwbinder.h
rename to libs/binder/parcel_fuzzer/hwbinder.h
index a6c66be..1fa56d4 100644
--- a/libs/binder/fuzzer/hwbinder.h
+++ b/libs/binder/parcel_fuzzer/hwbinder.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <hwbinder/Parcel.h>
 #include <vector>
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 66%
copy from libs/gui/tests/DummyConsumer.h
copy to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 502bdf9..0a083d7 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#include <gui/IConsumerListener.h>
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
 
 namespace android {
 
-struct DummyConsumer : public BnConsumerListener {
-    void onFrameAvailable(const BufferItem& /* item */) override {}
-    void onBuffersReleased() override {}
-    void onSidebandStreamChanged() override {}
-};
+// ownership to callee, always valid or aborts
+// get a random FD for use in fuzzing, of a few different specific types
+int getRandomFd(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 72%
copy from libs/binder/fuzzer/binder.h
copy to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index b224ef4..b92a6a9 100644
--- a/libs/binder/fuzzer/binder.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+#pragma once
+
 #include <binder/Parcel.h>
-#include <vector>
+#include <fuzzer/FuzzedDataProvider.h>
 
-#include "parcel_fuzzer.h"
-
-extern std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS;
+namespace android {
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
+} // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
new file mode 100644
index 0000000..78606cc
--- /dev/null
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 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 FUZZ_LOG_TAG "main"
+
+#include "binder.h"
+#include "binder_ndk.h"
+#include "hwbinder.h"
+#include "util.h"
+
+#include <iostream>
+
+#include <android-base/logging.h>
+#include <fuzzbinder/random_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <cstdlib>
+#include <ctime>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+using android::fillRandomParcel;
+
+void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+    // TODO: functionality to create random parcels for libhwbinder parcels
+    std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
+    p->setData(input.data(), input.size());
+}
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+    // fill underlying parcel using functions to fill random libbinder parcel
+    fillRandomParcel(p->parcel(), std::move(provider));
+}
+
+template <typename P>
+void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
+            FuzzedDataProvider&& provider) {
+    // Allow some majority of the bytes to be dedicated to telling us what to
+    // do. The fixed value added here represents that we want to test doing a
+    // lot of 'instructions' even on really short parcels.
+    size_t maxInstructions = 20 + (provider.remaining_bytes() * 2 / 3);
+    // but don't always use that many instructions. We want to allow the fuzzer
+    // to explore large parcels with few instructions if it wants to.
+    std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>(
+            provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
+
+    P p;
+    fillRandomParcel(&p, std::move(provider));
+
+    // since we are only using a byte to index
+    CHECK(reads.size() <= 255) << reads.size();
+
+    FUZZ_LOG() << "backend: " << backend;
+    FUZZ_LOG() << "input: " << hexString(p.data(), p.dataSize());
+    FUZZ_LOG() << "instructions: " << hexString(instructions);
+
+    for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
+        uint8_t a = instructions[i];
+        uint8_t readIdx = a % reads.size();
+
+        uint8_t b = instructions[i + 1];
+
+        FUZZ_LOG() << "Instruction: " << (i / 2) + 1 << "/" << instructions.size() / 2
+                   << " cmd: " << static_cast<size_t>(a) << " (" << static_cast<size_t>(readIdx)
+                   << ") arg: " << static_cast<size_t>(b) << " size: " << p.dataSize()
+                   << " avail: " << p.dataAvail() << " pos: " << p.dataPosition()
+                   << " cap: " << p.dataCapacity();
+
+        reads[readIdx](p, b);
+    }
+}
+
+size_t getHardMemoryLimit() {
+    struct rlimit limit;
+    CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+    return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+    const struct rlimit kLimit = {
+       .rlim_cur = cur,
+       .rlim_max = max,
+    };
+    CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    static constexpr size_t kMemLimit = 1 * 1024 * 1024;
+    size_t hardLimit = getHardMemoryLimit();
+    setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
+    if (size <= 1) return 0;  // no use
+
+    // avoid timeouts, see b/142617274, b/142473153
+    if (size > 50000) return 0;
+
+    FuzzedDataProvider provider = FuzzedDataProvider(data, size);
+
+    const std::function<void(FuzzedDataProvider &&)> fuzzBackend[3] = {
+            [](FuzzedDataProvider&& provider) {
+                doFuzz<::android::hardware::Parcel>("hwbinder", HWBINDER_PARCEL_READ_FUNCTIONS,
+                                                    std::move(provider));
+            },
+            [](FuzzedDataProvider&& provider) {
+                doFuzz<::android::Parcel>("binder", BINDER_PARCEL_READ_FUNCTIONS,
+                                          std::move(provider));
+            },
+            [](FuzzedDataProvider&& provider) {
+                doFuzz<NdkParcelAdapter>("binder_ndk", BINDER_NDK_PARCEL_READ_FUNCTIONS,
+                                         std::move(provider));
+            },
+    };
+
+    provider.PickValueInArray(fuzzBackend)(std::move(provider));
+
+    setMemoryLimit(hardLimit, hardLimit);
+
+    return 0;
+}
diff --git a/libs/binder/fuzzer/parcel_fuzzer.h b/libs/binder/parcel_fuzzer/parcel_fuzzer.h
similarity index 97%
rename from libs/binder/fuzzer/parcel_fuzzer.h
rename to libs/binder/parcel_fuzzer/parcel_fuzzer.h
index 10cf17c..b68a8a9 100644
--- a/libs/binder/fuzzer/parcel_fuzzer.h
+++ b/libs/binder/parcel_fuzzer/parcel_fuzzer.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 template <typename P>
 using ParcelRead = std::function<void(const P& p, uint8_t data)>;
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/parcel_fuzzer/random_fd.cpp
new file mode 100644
index 0000000..cef6adb
--- /dev/null
+++ b/libs/binder/parcel_fuzzer/random_fd.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/random_fd.h>
+
+#include <fcntl.h>
+
+#include <android-base/logging.h>
+#include <cutils/ashmem.h>
+
+namespace android {
+
+int getRandomFd(FuzzedDataProvider* provider) {
+    int fd = provider->PickValueInArray<std::function<int()>>({
+            []() { return ashmem_create_region("binder test region", 1024); },
+            []() { return open("/dev/null", O_RDWR); },
+    })();
+    CHECK(fd >= 0);
+    return fd;
+}
+
+} // namespace android
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp
new file mode 100644
index 0000000..9ca4c8a
--- /dev/null
+++ b/libs/binder/parcel_fuzzer/random_parcel.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/random_parcel.h>
+
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <fuzzbinder/random_fd.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class NamedBinder : public BBinder {
+public:
+    NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
+    const String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+    String16 mDescriptor;
+};
+
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
+    while (provider.remaining_bytes() > 0) {
+        auto fillFunc = provider.PickValueInArray<const std::function<void()>>({
+                // write data
+                [&]() {
+                    size_t toWrite =
+                            provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes());
+                    std::vector<uint8_t> data = provider.ConsumeBytes<uint8_t>(toWrite);
+                    CHECK(OK == p->write(data.data(), data.size()));
+                },
+                // write FD
+                [&]() {
+                    int fd = getRandomFd(&provider);
+                    CHECK(OK == p->writeFileDescriptor(fd, true /*takeOwnership*/));
+                },
+                // write binder
+                [&]() {
+                    auto makeFunc = provider.PickValueInArray<const std::function<sp<IBinder>()>>({
+                            [&]() {
+                                // descriptor is the length of a class name, e.g.
+                                // "some.package.Foo"
+                                std::string str =
+                                        provider.ConsumeRandomLengthString(100 /*max length*/);
+                                return new NamedBinder(String16(str.c_str()));
+                            },
+                            []() {
+                                // this is the easiest remote binder to get ahold of, and it
+                                // should be able to handle anything thrown at it, and
+                                // essentially every process can talk to it, so it's a good
+                                // candidate for checking usage of an actual BpBinder
+                                return IInterface::asBinder(defaultServiceManager());
+                            },
+                            []() { return nullptr; },
+                    });
+                    sp<IBinder> binder = makeFunc();
+                    CHECK(OK == p->writeStrongBinder(binder));
+                },
+        });
+
+        fillFunc();
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/fuzzer/util.cpp b/libs/binder/parcel_fuzzer/util.cpp
similarity index 100%
rename from libs/binder/fuzzer/util.cpp
rename to libs/binder/parcel_fuzzer/util.cpp
diff --git a/libs/binder/fuzzer/util.h b/libs/binder/parcel_fuzzer/util.h
similarity index 98%
rename from libs/binder/fuzzer/util.h
rename to libs/binder/parcel_fuzzer/util.h
index aa504d2..45e8c57 100644
--- a/libs/binder/fuzzer/util.h
+++ b/libs/binder/parcel_fuzzer/util.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <iostream>
 #include <sstream>
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
new file mode 100644
index 0000000..fd5f2f5
--- /dev/null
+++ b/libs/binder/rust/Android.bp
@@ -0,0 +1,96 @@
+rust_library {
+    name: "libbinder_rs",
+    crate_name: "binder",
+    srcs: ["src/lib.rs"],
+    shared_libs: [
+        "libutils",
+    ],
+    rustlibs: [
+        "liblibc",
+        "libbinder_ndk_sys",
+    ],
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    }
+}
+
+rust_library {
+    name: "libbinder_ndk_sys",
+    crate_name: "binder_ndk_sys",
+    srcs: [
+        "sys/lib.rs",
+        ":libbinder_ndk_bindgen",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    }
+}
+
+rust_bindgen {
+    name: "libbinder_ndk_bindgen",
+    crate_name: "binder_ndk_bindgen",
+    wrapper_src: "sys/BinderBindings.hpp",
+    source_stem: "bindings",
+    bindgen_flags: [
+        // Unfortunately the only way to specify the rust_non_exhaustive enum
+        // style for a type is to make it the default
+        "--default-enum-style", "rust_non_exhaustive",
+        // and then specify constified enums for the enums we don't want
+        // rustified
+        "--constified-enum", "android::c_interface::consts::.*",
+
+        "--whitelist-type", "android::c_interface::.*",
+        "--whitelist-type", "AStatus",
+        "--whitelist-type", "AIBinder_Class",
+        "--whitelist-type", "AIBinder",
+        "--whitelist-type", "AIBinder_Weak",
+        "--whitelist-type", "AIBinder_DeathRecipient",
+        "--whitelist-type", "AParcel",
+        "--whitelist-type", "binder_status_t",
+        "--whitelist-function", ".*",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    host_supported: true,
+
+    // Currently necessary for host builds
+    // TODO(b/31559095): bionic on host should define this
+    target: {
+        host: {
+            cflags: [
+                "-D__INTRODUCED_IN(n)=",
+                "-D__assert(a,b,c)=",
+                // We want all the APIs to be available on the host.
+                "-D__ANDROID_API__=10000",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+rust_test {
+    name: "libbinder_rs-internal_test",
+    crate_name: "binder",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    rustlibs: [
+        "liblibc",
+        "libbinder_ndk_sys",
+    ],
+}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
new file mode 100644
index 0000000..42c1e0a
--- /dev/null
+++ b/libs/binder/rust/src/binder.rs
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Trait definitions for binder objects
+
+use crate::error::{status_t, Result};
+use crate::parcel::Parcel;
+use crate::proxy::{DeathRecipient, SpIBinder};
+use crate::sys;
+
+use std::ffi::{c_void, CStr, CString};
+use std::os::raw::c_char;
+use std::os::unix::io::AsRawFd;
+use std::ptr;
+
+/// Binder action to perform.
+///
+/// This must be a number between [`IBinder::FIRST_CALL_TRANSACTION`] and
+/// [`IBinder::LAST_CALL_TRANSACTION`].
+pub type TransactionCode = u32;
+
+/// Additional operation flags.
+///
+/// `IBinder::FLAG_*` values.
+pub type TransactionFlags = u32;
+
+/// Super-trait for Binder interfaces.
+///
+/// This trait allows conversion of a Binder interface trait object into an
+/// IBinder object for IPC calls. All Binder remotable interface (i.e. AIDL
+/// interfaces) must implement this trait.
+///
+/// This is equivalent `IInterface` in C++.
+pub trait Interface {
+    /// Convert this binder object into a generic [`SpIBinder`] reference.
+    fn as_binder(&self) -> SpIBinder {
+        panic!("This object was not a Binder object and cannot be converted into an SpIBinder.")
+    }
+}
+
+/// A local service that can be remotable via Binder.
+///
+/// An object that implement this interface made be made into a Binder service
+/// via `Binder::new(object)`.
+///
+/// This is a low-level interface that should normally be automatically
+/// generated from AIDL via the [`declare_binder_interface!`] macro. When using
+/// the AIDL backend, users need only implement the high-level AIDL-defined
+/// interface. The AIDL compiler then generates a container struct that wraps
+/// the user-defined service and implements `Remotable`.
+pub trait Remotable: Send + Sync {
+    /// The Binder interface descriptor string.
+    ///
+    /// This string is a unique identifier for a Binder interface, and should be
+    /// the same between all implementations of that interface.
+    fn get_descriptor() -> &'static str;
+
+    /// Handle and reply to a request to invoke a transaction on this object.
+    ///
+    /// `reply` may be [`None`] if the sender does not expect a reply.
+    fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>;
+
+    /// Retrieve the class of this remote object.
+    ///
+    /// This method should always return the same InterfaceClass for the same
+    /// type.
+    fn get_class() -> InterfaceClass;
+}
+
+/// Interface of binder local or remote objects.
+///
+/// This trait corresponds to the interface of the C++ `IBinder` class.
+pub trait IBinder {
+    /// First transaction code available for user commands (inclusive)
+    const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
+    /// Last transaction code available for user commands (inclusive)
+    const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
+
+    /// Corresponds to TF_ONE_WAY -- an asynchronous call.
+    const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
+    /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
+    const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
+
+    /// Is this object still alive?
+    fn is_binder_alive(&self) -> bool;
+
+    /// Send a ping transaction to this object
+    fn ping_binder(&mut self) -> Result<()>;
+
+    /// Indicate that the service intends to receive caller security contexts.
+    fn set_requesting_sid(&mut self, enable: bool);
+
+    /// Dump this object to the given file handle
+    fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()>;
+
+    /// Get a new interface that exposes additional extension functionality, if
+    /// available.
+    fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
+
+    /// Perform a generic operation with the object.
+    ///
+    /// # Arguments
+    /// * `code` - Transaction code for the operation
+    /// * `data` - [`Parcel`] with input data
+    /// * `reply` - Optional [`Parcel`] for reply data
+    /// * `flags` - Transaction flags, e.g. marking the transaction as
+    /// asynchronous ([`FLAG_ONEWAY`](IBinder::FLAG_ONEWAY))
+    fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+        &self,
+        code: TransactionCode,
+        flags: TransactionFlags,
+        input_callback: F,
+    ) -> Result<Parcel>;
+
+    /// Register the recipient for a notification if this binder
+    /// goes away. If this binder object unexpectedly goes away
+    /// (typically because its hosting process has been killed),
+    /// then DeathRecipient::binder_died() will be called with a reference
+    /// to this.
+    ///
+    /// You will only receive death notifications for remote binders,
+    /// as local binders by definition can't die without you dying as well.
+    /// Trying to use this function on a local binder will result in an
+    /// INVALID_OPERATION code being returned and nothing happening.
+    ///
+    /// This link always holds a weak reference to its recipient.
+    ///
+    /// You will only receive a weak reference to the dead
+    /// binder. You should not try to promote this to a strong reference.
+    /// (Nor should you need to, as there is nothing useful you can
+    /// directly do with it now that it has passed on.)
+    fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
+
+    /// Remove a previously registered death notification.
+    /// The recipient will no longer be called if this object
+    /// dies.
+    fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
+}
+
+/// Opaque reference to the type of a Binder interface.
+///
+/// This object encapsulates the Binder interface descriptor string, along with
+/// the binder transaction callback, if the class describes a local service.
+///
+/// A Binder remotable object may only have a single interface class, and any
+/// given object can only be associated with one class. Two objects with
+/// different classes are incompatible, even if both classes have the same
+/// interface descriptor.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct InterfaceClass(*const sys::AIBinder_Class);
+
+impl InterfaceClass {
+    /// Get a Binder NDK `AIBinder_Class` pointer for this object type.
+    ///
+    /// Note: the returned pointer will not be constant. Calling this method
+    /// multiple times for the same type will result in distinct class
+    /// pointers. A static getter for this value is implemented in
+    /// [`declare_binder_interface!`].
+    pub fn new<I: InterfaceClassMethods>() -> InterfaceClass {
+        let descriptor = CString::new(I::get_descriptor()).unwrap();
+        let ptr = unsafe {
+            // Safety: `AIBinder_Class_define` expects a valid C string, and
+            // three valid callback functions, all non-null pointers. The C
+            // string is copied and need not be valid for longer than the call,
+            // so we can drop it after the call. We can safely assign null to
+            // the onDump and handleShellCommand callbacks as long as the class
+            // pointer was non-null. Rust None for a Option<fn> is guaranteed to
+            // be a NULL pointer. Rust retains ownership of the pointer after it
+            // is defined.
+            let class = sys::AIBinder_Class_define(
+                descriptor.as_ptr(),
+                Some(I::on_create),
+                Some(I::on_destroy),
+                Some(I::on_transact),
+            );
+            if class.is_null() {
+                panic!("Expected non-null class pointer from AIBinder_Class_define!");
+            }
+            sys::AIBinder_Class_setOnDump(class, None);
+            sys::AIBinder_Class_setHandleShellCommand(class, None);
+            class
+        };
+        InterfaceClass(ptr)
+    }
+
+    /// Construct an `InterfaceClass` out of a raw, non-null `AIBinder_Class`
+    /// pointer.
+    ///
+    /// # Safety
+    ///
+    /// This function is safe iff `ptr` is a valid, non-null pointer to an
+    /// `AIBinder_Class`.
+    pub(crate) unsafe fn from_ptr(ptr: *const sys::AIBinder_Class) -> InterfaceClass {
+        InterfaceClass(ptr)
+    }
+
+    /// Get the interface descriptor string of this class.
+    pub fn get_descriptor(&self) -> String {
+        unsafe {
+            // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
+            // is always a two-byte null terminated sequence of u16s. Thus, we
+            // can continue reading from the pointer until we hit a null value,
+            // and this pointer can be a valid slice if the slice length is <=
+            // the number of u16 elements before the null terminator.
+
+            let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
+            CStr::from_ptr(raw_descriptor).to_str()
+                .expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
+                .into()
+        }
+    }
+}
+
+impl From<InterfaceClass> for *const sys::AIBinder_Class {
+    fn from(class: InterfaceClass) -> *const sys::AIBinder_Class {
+        class.0
+    }
+}
+
+/// Create a function implementing a static getter for an interface class.
+///
+/// Each binder interface (i.e. local [`Remotable`] service or remote proxy
+/// [`Interface`]) must have global, static class that uniquely identifies
+/// it. This macro implements an [`InterfaceClass`] getter to simplify these
+/// implementations.
+///
+/// The type of a structure that implements [`InterfaceClassMethods`] must be
+/// passed to this macro. For local services, this should be `Binder<Self>`
+/// since [`Binder`] implements [`InterfaceClassMethods`].
+///
+/// # Examples
+///
+/// When implementing a local [`Remotable`] service `ExampleService`, the
+/// `get_class` method is required in the [`Remotable`] impl block. This macro
+/// should be used as follows to implement this functionality:
+///
+/// ```rust
+/// impl Remotable for ExampleService {
+///     fn get_descriptor() -> &'static str {
+///         "android.os.IExampleInterface"
+///     }
+///
+///     fn on_transact(
+///         &self,
+///         code: TransactionCode,
+///         data: &Parcel,
+///         reply: &mut Parcel,
+///     ) -> Result<()> {
+///         // ...
+///     }
+///
+///     binder_fn_get_class!(Binder<Self>);
+/// }
+/// ```
+macro_rules! binder_fn_get_class {
+    ($class:ty) => {
+        binder_fn_get_class!($crate::InterfaceClass::new::<$class>());
+    };
+
+    ($constructor:expr) => {
+        fn get_class() -> $crate::InterfaceClass {
+            static CLASS_INIT: std::sync::Once = std::sync::Once::new();
+            static mut CLASS: Option<$crate::InterfaceClass> = None;
+
+            CLASS_INIT.call_once(|| unsafe {
+                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+                // variable, and therefore is thread-safe, as it can only occur
+                // once.
+                CLASS = Some($constructor);
+            });
+            unsafe {
+                // Safety: The `CLASS` variable can only be mutated once, above,
+                // and is subsequently safe to read from any thread.
+                CLASS.unwrap()
+            }
+        }
+    };
+}
+
+pub trait InterfaceClassMethods {
+    /// Get the interface descriptor string for this object type.
+    fn get_descriptor() -> &'static str
+    where
+        Self: Sized;
+
+    /// Called during construction of a new `AIBinder` object of this interface
+    /// class.
+    ///
+    /// The opaque pointer parameter will be the parameter provided to
+    /// `AIBinder_new`. Returns an opaque userdata to be associated with the new
+    /// `AIBinder` object.
+    ///
+    /// # Safety
+    ///
+    /// Callback called from C++. The parameter argument provided to
+    /// `AIBinder_new` must match the type expected here. The `AIBinder` object
+    /// will take ownership of the returned pointer, which it will free via
+    /// `on_destroy`.
+    unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void;
+
+    /// Called when a transaction needs to be processed by the local service
+    /// implementation.
+    ///
+    /// # Safety
+    ///
+    /// Callback called from C++. The `binder` parameter must be a valid pointer
+    /// to a binder object of this class with userdata initialized via this
+    /// class's `on_create`. The parcel parameters must be valid pointers to
+    /// parcel objects.
+    unsafe extern "C" fn on_transact(
+        binder: *mut sys::AIBinder,
+        code: u32,
+        data: *const sys::AParcel,
+        reply: *mut sys::AParcel,
+    ) -> status_t;
+
+    /// Called whenever an `AIBinder` object is no longer referenced and needs
+    /// to be destroyed.
+    ///
+    /// # Safety
+    ///
+    /// Callback called from C++. The opaque pointer parameter must be the value
+    /// returned by `on_create` for this class. This function takes ownership of
+    /// the provided pointer and destroys it.
+    unsafe extern "C" fn on_destroy(object: *mut c_void);
+}
+
+/// Interface for transforming a generic SpIBinder into a specific remote
+/// interface trait.
+///
+/// # Example
+///
+/// For Binder interface `IFoo`, the following implementation should be made:
+/// ```no_run
+/// # use binder::{FromIBinder, SpIBinder, Result};
+/// # trait IFoo {}
+/// impl FromIBinder for dyn IFoo {
+///     fn try_from(ibinder: SpIBinder) -> Result<Box<Self>> {
+///         // ...
+///         # Err(binder::StatusCode::OK)
+///     }
+/// }
+/// ```
+pub trait FromIBinder {
+    /// Try to interpret a generic Binder object as this interface.
+    ///
+    /// Returns a trait object for the `Self` interface if this object
+    /// implements that interface.
+    fn try_from(ibinder: SpIBinder) -> Result<Box<Self>>;
+}
+
+/// Trait for transparent Rust wrappers around android C++ native types.
+///
+/// The pointer return by this trait's methods should be immediately passed to
+/// C++ and not stored by Rust. The pointer is valid only as long as the
+/// underlying C++ object is alive, so users must be careful to take this into
+/// account, as Rust cannot enforce this.
+///
+/// # Safety
+///
+/// For this trait to be a correct implementation, `T` must be a valid android
+/// C++ type. Since we cannot constrain this via the type system, this trait is
+/// marked as unsafe.
+pub unsafe trait AsNative<T> {
+    /// Return a pointer to the native version of `self`
+    fn as_native(&self) -> *const T;
+
+    /// Return a mutable pointer to the native version of `self`
+    fn as_native_mut(&mut self) -> *mut T;
+}
+
+unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
+    fn as_native(&self) -> *const T {
+        self.as_ref().map_or(ptr::null(), |v| v.as_native())
+    }
+
+    fn as_native_mut(&mut self) -> *mut T {
+        self.as_mut().map_or(ptr::null_mut(), |v| v.as_native_mut())
+    }
+}
+
+/// Declare typed interfaces for a binder object.
+///
+/// Given an interface trait and descriptor string, create a native and remote
+/// proxy wrapper for this interface. The native service object (`$native`)
+/// implements `Remotable` and will dispatch to the function `$on_transact` to
+/// handle transactions. The typed proxy object (`$proxy`) wraps remote binder
+/// objects for this interface and can optionally contain additional fields.
+///
+/// Assuming the interface trait is `Interface`, `$on_transact` function must
+/// have the following type:
+///
+/// ```
+/// # use binder::{Interface, TransactionCode, Parcel};
+/// # trait Placeholder {
+/// fn on_transact(
+///     service: &dyn Interface,
+///     code: TransactionCode,
+///     data: &Parcel,
+///     reply: &mut Parcel,
+/// ) -> binder::Result<()>;
+/// # }
+/// ```
+///
+/// # Examples
+///
+/// The following example declares the local service type `BnServiceManager` and
+/// a remote proxy type `BpServiceManager` (the `n` and `p` stand for native and
+/// proxy respectively) for the `IServiceManager` Binder interface. The
+/// interfaces will be identified by the descriptor string
+/// "android.os.IServiceManager". The local service will dispatch transactions
+/// using the provided function, `on_transact`.
+///
+/// ```
+/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel};
+///
+/// pub trait IServiceManager: Interface {
+///     // remote methods...
+/// }
+///
+/// declare_binder_interface! {
+///     IServiceManager["android.os.IServiceManager"] {
+///         native: BnServiceManager(on_transact),
+///         proxy: BpServiceManager,
+///     }
+/// }
+///
+/// fn on_transact(
+///     service: &dyn IServiceManager,
+///     code: TransactionCode,
+///     data: &Parcel,
+///     reply: &mut Parcel,
+/// ) -> binder::Result<()> {
+///     // ...
+///     Ok(())
+/// }
+///
+/// impl IServiceManager for BpServiceManager {
+///     // parceling/unparceling code for the IServiceManager emitted here
+/// }
+///
+/// impl IServiceManager for Binder<BnServiceManager> {
+///     // Forward calls to local implementation
+/// }
+/// ```
+#[macro_export]
+macro_rules! declare_binder_interface {
+    {
+        $interface:path[$descriptor:expr] {
+            native: $native:ident($on_transact:path),
+            proxy: $proxy:ident,
+        }
+    } => {
+        $crate::declare_binder_interface! {
+            $interface[$descriptor] {
+                native: $native($on_transact),
+                proxy: $proxy {},
+            }
+        }
+    };
+
+    {
+        $interface:path[$descriptor:expr] {
+            native: $native:ident($on_transact:path),
+            proxy: $proxy:ident {
+                $($fname:ident: $fty:ty = $finit:expr),*
+            },
+        }
+    } => {
+        $crate::declare_binder_interface! {
+            $interface[$descriptor] {
+                @doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
+                native: $native($on_transact),
+                @doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
+                proxy: $proxy {
+                    $($fname: $fty = $finit),*
+                },
+            }
+        }
+    };
+
+    {
+        $interface:path[$descriptor:expr] {
+            @doc[$native_doc:expr]
+            native: $native:ident($on_transact:path),
+
+            @doc[$proxy_doc:expr]
+            proxy: $proxy:ident {
+                $($fname:ident: $fty:ty = $finit:expr),*
+            },
+        }
+    } => {
+        #[doc = $proxy_doc]
+        pub struct $proxy {
+            binder: $crate::SpIBinder,
+            $($fname: $fty,)*
+        }
+
+        impl $crate::Interface for $proxy {
+            fn as_binder(&self) -> $crate::SpIBinder {
+                self.binder.clone()
+            }
+        }
+
+        impl $crate::Proxy for $proxy
+        where
+            $proxy: $interface,
+        {
+            fn get_descriptor() -> &'static str {
+                $descriptor
+            }
+
+            fn from_binder(mut binder: $crate::SpIBinder) -> $crate::Result<Self> {
+                Ok(Self { binder, $($fname: $finit),* })
+            }
+        }
+
+        #[doc = $native_doc]
+        #[repr(transparent)]
+        pub struct $native(Box<dyn $interface + Sync + Send + 'static>);
+
+        impl $native {
+            /// Create a new binder service.
+            pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> impl $interface {
+                $crate::Binder::new($native(Box::new(inner)))
+            }
+        }
+
+        impl $crate::Remotable for $native {
+            fn get_descriptor() -> &'static str {
+                $descriptor
+            }
+
+            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
+                match $on_transact(&*self.0, code, data, reply) {
+                    // The C++ backend converts UNEXPECTED_NULL into an exception
+                    Err($crate::StatusCode::UNEXPECTED_NULL) => {
+                        let status = $crate::Status::new_exception(
+                            $crate::ExceptionCode::NULL_POINTER,
+                            None,
+                        );
+                        reply.write(&status)
+                    },
+                    result => result
+                }
+            }
+
+            fn get_class() -> $crate::InterfaceClass {
+                static CLASS_INIT: std::sync::Once = std::sync::Once::new();
+                static mut CLASS: Option<$crate::InterfaceClass> = None;
+
+                CLASS_INIT.call_once(|| unsafe {
+                    // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+                    // variable, and therefore is thread-safe, as it can only occur
+                    // once.
+                    CLASS = Some($crate::InterfaceClass::new::<$crate::Binder<$native>>());
+                });
+                unsafe {
+                    // Safety: The `CLASS` variable can only be mutated once, above,
+                    // and is subsequently safe to read from any thread.
+                    CLASS.unwrap()
+                }
+            }
+        }
+
+        impl $crate::FromIBinder for dyn $interface {
+            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
+                use $crate::AssociateClass;
+
+                let existing_class = ibinder.get_class();
+                if let Some(class) = existing_class {
+                    if class != <$native as $crate::Remotable>::get_class() &&
+                        class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+                    {
+                        // The binder object's descriptor string matches what we
+                        // expect. We still need to treat this local or already
+                        // associated object as remote, because we can't cast it
+                        // into a Rust service object without a matching class
+                        // pointer.
+                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+                    }
+                }
+
+                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+                    let service: $crate::Result<$crate::Binder<$native>> =
+                        std::convert::TryFrom::try_from(ibinder.clone());
+                    if let Ok(service) = service {
+                        // We were able to associate with our expected class and
+                        // the service is local.
+                        return Ok(Box::new(service));
+                    } else {
+                        // Service is remote
+                        return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+                    }
+                }
+
+                Err($crate::StatusCode::BAD_TYPE.into())
+            }
+        }
+
+        impl $crate::parcel::Serialize for dyn $interface + '_
+        where
+            dyn $interface: $crate::Interface
+        {
+            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+                let binder = $crate::Interface::as_binder(self);
+                parcel.write(&binder)
+            }
+        }
+
+        impl $crate::parcel::SerializeOption for dyn $interface + '_ {
+            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+                parcel.write(&this.map($crate::Interface::as_binder))
+            }
+        }
+
+        impl std::fmt::Debug for dyn $interface {
+            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                f.pad(stringify!($interface))
+            }
+        }
+
+        // Convert a &dyn $interface to Box<dyn $interface>
+        impl std::borrow::ToOwned for dyn $interface {
+            type Owned = Box<dyn $interface>;
+            fn to_owned(&self) -> Self::Owned {
+                self.as_binder().into_interface()
+                    .expect(concat!("Error cloning interface ", stringify!($interface)))
+            }
+        }
+    };
+}
+
+/// Declare an AIDL enumeration.
+///
+/// This is mainly used internally by the AIDL compiler.
+#[macro_export]
+macro_rules! declare_binder_enum {
+    {
+        $enum:ident : $backing:ty {
+            $( $name:ident = $value:expr, )*
+        }
+    } => {
+        #[derive(Debug, Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
+        pub struct $enum(pub $backing);
+        impl $enum {
+            $( pub const $name: Self = Self($value); )*
+        }
+
+        impl $crate::parcel::Serialize for $enum {
+            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+                parcel.write(&self.0)
+            }
+        }
+
+        impl $crate::parcel::SerializeArray for $enum {
+            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+                let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
+                <$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
+            }
+        }
+
+        impl $crate::parcel::Deserialize for $enum {
+            fn deserialize(parcel: &$crate::parcel::Parcel) -> $crate::Result<Self> {
+                parcel.read().map(Self)
+            }
+        }
+
+        impl $crate::parcel::DeserializeArray for $enum {
+            fn deserialize_array(parcel: &$crate::parcel::Parcel) -> $crate::Result<Option<Vec<Self>>> {
+                let v: Option<Vec<$backing>> =
+                    <$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
+                Ok(v.map(|v| v.into_iter().map(Self).collect()))
+            }
+        }
+    };
+}
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
new file mode 100644
index 0000000..4492cf7
--- /dev/null
+++ b/libs/binder/rust/src/error.rs
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::binder::AsNative;
+use crate::sys;
+
+use std::error;
+use std::ffi::CStr;
+use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
+use std::result;
+
+pub use sys::binder_status_t as status_t;
+
+/// Low-level status codes from Android `libutils`.
+// All error codes are negative integer values. Derived from the anonymous enum
+// in utils/Errors.h
+pub use sys::android_c_interface_StatusCode as StatusCode;
+
+/// A specialized [`Result`](result::Result) for binder operations.
+pub type Result<T> = result::Result<T, StatusCode>;
+
+/// Convert a low-level status code into an empty result.
+///
+/// An OK status is converted into an `Ok` result, any other status is converted
+/// into an `Err` result holding the status code.
+pub fn status_result(status: status_t) -> Result<()> {
+    match parse_status_code(status) {
+        StatusCode::OK => Ok(()),
+        e => Err(e),
+    }
+}
+
+fn parse_status_code(code: i32) -> StatusCode {
+    match code {
+        e if e == StatusCode::OK as i32 => StatusCode::OK,
+        e if e == StatusCode::NO_MEMORY as i32 => StatusCode::NO_MEMORY,
+        e if e == StatusCode::INVALID_OPERATION as i32 => StatusCode::INVALID_OPERATION,
+        e if e == StatusCode::BAD_VALUE as i32 => StatusCode::BAD_VALUE,
+        e if e == StatusCode::BAD_TYPE as i32 => StatusCode::BAD_TYPE,
+        e if e == StatusCode::NAME_NOT_FOUND as i32 => StatusCode::NAME_NOT_FOUND,
+        e if e == StatusCode::PERMISSION_DENIED as i32 => StatusCode::PERMISSION_DENIED,
+        e if e == StatusCode::NO_INIT as i32 => StatusCode::NO_INIT,
+        e if e == StatusCode::ALREADY_EXISTS as i32 => StatusCode::ALREADY_EXISTS,
+        e if e == StatusCode::DEAD_OBJECT as i32 => StatusCode::DEAD_OBJECT,
+        e if e == StatusCode::FAILED_TRANSACTION as i32 => StatusCode::FAILED_TRANSACTION,
+        e if e == StatusCode::BAD_INDEX as i32 => StatusCode::BAD_INDEX,
+        e if e == StatusCode::NOT_ENOUGH_DATA as i32 => StatusCode::NOT_ENOUGH_DATA,
+        e if e == StatusCode::WOULD_BLOCK as i32 => StatusCode::WOULD_BLOCK,
+        e if e == StatusCode::TIMED_OUT as i32 => StatusCode::TIMED_OUT,
+        e if e == StatusCode::UNKNOWN_TRANSACTION as i32 => StatusCode::UNKNOWN_TRANSACTION,
+        e if e == StatusCode::FDS_NOT_ALLOWED as i32 => StatusCode::FDS_NOT_ALLOWED,
+        e if e == StatusCode::UNEXPECTED_NULL as i32 => StatusCode::UNEXPECTED_NULL,
+        _ => StatusCode::UNKNOWN_ERROR,
+    }
+}
+
+pub use sys::android_c_interface_ExceptionCode as ExceptionCode;
+
+fn parse_exception_code(code: i32) -> ExceptionCode {
+    match code {
+        e if e == ExceptionCode::NONE as i32 => ExceptionCode::NONE,
+        e if e == ExceptionCode::SECURITY as i32 => ExceptionCode::SECURITY,
+        e if e == ExceptionCode::BAD_PARCELABLE as i32 => ExceptionCode::BAD_PARCELABLE,
+        e if e == ExceptionCode::ILLEGAL_ARGUMENT as i32 => ExceptionCode::ILLEGAL_ARGUMENT,
+        e if e == ExceptionCode::NULL_POINTER as i32 => ExceptionCode::NULL_POINTER,
+        e if e == ExceptionCode::ILLEGAL_STATE as i32 => ExceptionCode::ILLEGAL_STATE,
+        e if e == ExceptionCode::NETWORK_MAIN_THREAD as i32 => {
+            ExceptionCode::NETWORK_MAIN_THREAD
+        }
+        e if e == ExceptionCode::UNSUPPORTED_OPERATION as i32 => {
+            ExceptionCode::UNSUPPORTED_OPERATION
+        }
+        e if e == ExceptionCode::SERVICE_SPECIFIC as i32 => ExceptionCode::SERVICE_SPECIFIC,
+        _ => ExceptionCode::TRANSACTION_FAILED,
+    }
+}
+
+// Safety: `Status` always contains a owning pointer to a valid `AStatus`. The
+// lifetime of the contained pointer is the same as the `Status` object.
+/// High-level binder status object that encapsulates a standard way to keep
+/// track of and chain binder errors along with service specific errors.
+///
+/// Used in AIDL transactions to represent failed transactions.
+pub struct Status(*mut sys::AStatus);
+
+impl Status {
+    /// Create a status object representing a successful transaction.
+    pub fn ok() -> Self {
+        let ptr = unsafe {
+            // Safety: `AStatus_newOk` always returns a new, heap allocated
+            // pointer to an `ASTatus` object, so we know this pointer will be
+            // valid.
+            //
+            // Rust takes ownership of the returned pointer.
+            sys::AStatus_newOk()
+        };
+        Self(ptr)
+    }
+
+    /// Create a status object from a service specific error
+    pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
+        let ptr = if let Some(message) = message {
+            unsafe {
+                // Safety: Any i32 is a valid service specific error for the
+                // error code parameter. We construct a valid, null-terminated
+                // `CString` from the message, which must be a valid C-style
+                // string to pass as the message. This function always returns a
+                // new, heap allocated pointer to an `AStatus` object, so we
+                // know the returned pointer will be valid.
+                //
+                // Rust takes ownership of the returned pointer.
+                sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr())
+            }
+        } else {
+            unsafe {
+                // Safety: Any i32 is a valid service specific error for the
+                // error code parameter. This function always returns a new,
+                // heap allocated pointer to an `AStatus` object, so we know the
+                // returned pointer will be valid.
+                //
+                // Rust takes ownership of the returned pointer.
+                sys::AStatus_fromServiceSpecificError(err)
+            }
+        };
+        Self(ptr)
+    }
+
+    /// Create a status object from an exception code
+    pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
+        if let Some(message) = message {
+            let ptr = unsafe {
+                sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
+            };
+            Self(ptr)
+        } else {
+            exception.into()
+        }
+    }
+
+    /// Create a status object from a raw `AStatus` pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe iff `ptr` is a valid pointer to an `AStatus`.
+    pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self {
+        Self(ptr)
+    }
+
+    /// Returns `true` if this status represents a successful transaction.
+    pub fn is_ok(&self) -> bool {
+        unsafe {
+            // Safety: `Status` always contains a valid `AStatus` pointer, so we
+            // are always passing a valid pointer to `AStatus_isOk` here.
+            sys::AStatus_isOk(self.as_native())
+        }
+    }
+
+    /// Returns a description of the status.
+    pub fn get_description(&self) -> String {
+        let description_ptr = unsafe {
+            // Safety: `Status` always contains a valid `AStatus` pointer, so we
+            // are always passing a valid pointer to `AStatus_getDescription`
+            // here.
+            //
+            // `AStatus_getDescription` always returns a valid pointer to a null
+            // terminated C string. Rust is responsible for freeing this pointer
+            // via `AStatus_deleteDescription`.
+            sys::AStatus_getDescription(self.as_native())
+        };
+        let description = unsafe {
+            // Safety: `AStatus_getDescription` always returns a valid C string,
+            // which can be safely converted to a `CStr`.
+            CStr::from_ptr(description_ptr)
+        };
+        let description = description.to_string_lossy().to_string();
+        unsafe {
+            // Safety: `description_ptr` was returned from
+            // `AStatus_getDescription` above, and must be freed via
+            // `AStatus_deleteDescription`. We must not access the pointer after
+            // this call, so we copy it into an owned string above and return
+            // that string.
+            sys::AStatus_deleteDescription(description_ptr);
+        }
+        description
+    }
+
+    /// Returns the exception code of the status.
+    pub fn exception_code(&self) -> ExceptionCode {
+        let code = unsafe {
+            // Safety: `Status` always contains a valid `AStatus` pointer, so we
+            // are always passing a valid pointer to `AStatus_getExceptionCode`
+            // here.
+            sys::AStatus_getExceptionCode(self.as_native())
+        };
+        parse_exception_code(code)
+    }
+
+    /// Return a status code representing a transaction failure, or
+    /// `StatusCode::OK` if there was no transaction failure.
+    ///
+    /// If this method returns `OK`, the status may still represent a different
+    /// exception or a service specific error. To find out if this transaction
+    /// as a whole is okay, use [`is_ok`](Self::is_ok) instead.
+    pub fn transaction_error(&self) -> StatusCode {
+        let code = unsafe {
+            // Safety: `Status` always contains a valid `AStatus` pointer, so we
+            // are always passing a valid pointer to `AStatus_getStatus` here.
+            sys::AStatus_getStatus(self.as_native())
+        };
+        parse_status_code(code)
+    }
+
+    /// Return a service specific error if this status represents one.
+    ///
+    /// This function will only ever return a non-zero result if
+    /// [`exception_code`](Self::exception_code) returns
+    /// `ExceptionCode::SERVICE_SPECIFIC`. If this function returns 0, the
+    /// status object may still represent a different exception or status. To
+    /// find out if this transaction as a whole is okay, use
+    /// [`is_ok`](Self::is_ok) instead.
+    pub fn service_specific_error(&self) -> i32 {
+        unsafe {
+            // Safety: `Status` always contains a valid `AStatus` pointer, so we
+            // are always passing a valid pointer to
+            // `AStatus_getServiceSpecificError` here.
+            sys::AStatus_getServiceSpecificError(self.as_native())
+        }
+    }
+
+    /// Calls `op` if the status was ok, otherwise returns an `Err` value of
+    /// `self`.
+    pub fn and_then<T, F>(self, op: F) -> result::Result<T, Status>
+    where
+        F: FnOnce() -> result::Result<T, Status>,
+    {
+        <result::Result<(), Status>>::from(self)?;
+        op()
+    }
+}
+
+impl error::Error for Status {}
+
+impl Display for Status {
+    fn fmt(&self, f: &mut Formatter) -> FmtResult {
+        f.write_str(&self.get_description())
+    }
+}
+
+impl Debug for Status {
+    fn fmt(&self, f: &mut Formatter) -> FmtResult {
+        f.write_str(&self.get_description())
+    }
+}
+
+impl PartialEq for Status {
+    fn eq(&self, other: &Status) -> bool {
+        let self_code = self.exception_code();
+        let other_code = other.exception_code();
+
+        match (self_code, other_code) {
+            (ExceptionCode::NONE, ExceptionCode::NONE) => true,
+            (ExceptionCode::TRANSACTION_FAILED, ExceptionCode::TRANSACTION_FAILED) => {
+                self.transaction_error() == other.transaction_error()
+                    && self.get_description() == other.get_description()
+            }
+            (ExceptionCode::SERVICE_SPECIFIC, ExceptionCode::SERVICE_SPECIFIC) => {
+                self.service_specific_error() == other.service_specific_error()
+                    && self.get_description() == other.get_description()
+            }
+            (e1, e2) => e1 == e2 && self.get_description() == other.get_description(),
+        }
+    }
+}
+
+impl Eq for Status {}
+
+impl From<StatusCode> for Status {
+    fn from(status: StatusCode) -> Status {
+        (status as status_t).into()
+    }
+}
+
+impl From<status_t> for Status {
+    fn from(status: status_t) -> Status {
+        let ptr = unsafe {
+            // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
+            // this is a safe FFI call. Unknown values will be coerced into
+            // UNKNOWN_ERROR.
+            sys::AStatus_fromStatus(status)
+        };
+        Self(ptr)
+    }
+}
+
+impl From<ExceptionCode> for Status {
+    fn from(code: ExceptionCode) -> Status {
+        let ptr = unsafe {
+            // Safety: `AStatus_fromExceptionCode` expects any
+            // `binder_exception_t` (i32) integer, so this is a safe FFI call.
+            // Unknown values will be coerced into EX_TRANSACTION_FAILED.
+            sys::AStatus_fromExceptionCode(code as i32)
+        };
+        Self(ptr)
+    }
+}
+
+// TODO: impl Try for Status when try_trait is stabilized
+// https://github.com/rust-lang/rust/issues/42327
+impl From<Status> for result::Result<(), Status> {
+    fn from(status: Status) -> result::Result<(), Status> {
+        if status.is_ok() {
+            Ok(())
+        } else {
+            Err(status)
+        }
+    }
+}
+
+impl From<Status> for status_t {
+    fn from(status: Status) -> status_t {
+        status.transaction_error() as status_t
+    }
+}
+
+impl Drop for Status {
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: `Status` manages the lifetime of its inner `AStatus`
+            // pointee, so we need to delete it here. We know that the pointer
+            // will be valid here since `Status` always contains a valid pointer
+            // while it is alive.
+            sys::AStatus_delete(self.0);
+        }
+    }
+}
+
+/// # Safety
+///
+/// `Status` always contains a valid pointer to an `AStatus` object, so we can
+/// trivially convert it to a correctly-typed raw pointer.
+///
+/// Care must be taken that the returned pointer is only dereferenced while the
+/// `Status` object is still alive.
+unsafe impl AsNative<sys::AStatus> for Status {
+    fn as_native(&self) -> *const sys::AStatus {
+        self.0
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AStatus {
+        self.0
+    }
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
new file mode 100644
index 0000000..edfb56a
--- /dev/null
+++ b/libs/binder/rust/src/lib.rs
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Safe Rust interface to Android `libbinder`.
+//!
+//! This crate is primarily designed as an target for a Rust AIDL compiler
+//! backend, and should generally not be used directly by users. It is built on
+//! top of the binder NDK library to be usable by APEX modules, and therefore
+//! only exposes functionality available in the NDK interface.
+//!
+//! # Example
+//!
+//! The following example illustrates how the AIDL backend will use this crate.
+//!
+//! ```
+//! use binder::{
+//!     declare_binder_interface, Binder, IBinder, Interface, Remotable, Parcel, SpIBinder,
+//!     StatusCode, TransactionCode,
+//! };
+//!
+//! // Generated by AIDL compiler
+//! pub trait ITest: Interface {
+//!     fn test(&self) -> binder::Result<String>;
+//! }
+//!
+//! // Creates a new local (native) service object, BnTest, and a remote proxy
+//! // object, BpTest, that are the typed interfaces for their respective ends
+//! // of the binder transaction. Generated by AIDL compiler.
+//! declare_binder_interface! {
+//!     ITest["android.os.ITest"] {
+//!         native: BnTest(on_transact),
+//!         proxy: BpTest,
+//!     }
+//! }
+//!
+//! // Generated by AIDL compiler
+//! fn on_transact(
+//!     service: &dyn ITest,
+//!     code: TransactionCode,
+//!     _data: &Parcel,
+//!     reply: &mut Parcel,
+//! ) -> binder::Result<()> {
+//!     match code {
+//!         SpIBinder::FIRST_CALL_TRANSACTION => {
+//!             reply.write(&service.test()?)?;
+//!             Ok(())
+//!         }
+//!         _ => Err(StatusCode::UNKNOWN_TRANSACTION),
+//!     }
+//! }
+//!
+//! // Generated by AIDL compiler
+//! impl ITest for Binder<BnTest> {
+//!     fn test(&self) -> binder::Result<String> {
+//!         self.0.test()
+//!     }
+//! }
+//!
+//! // Generated by AIDL compiler
+//! impl ITest for BpTest {
+//!     fn test(&self) -> binder::Result<String> {
+//!        let reply = self
+//!            .as_binder()
+//!            .transact(SpIBinder::FIRST_CALL_TRANSACTION, 0, |_| Ok(()))?;
+//!        reply.read()
+//!     }
+//! }
+//!
+//! // User implemented:
+//!
+//! // Local implementation of the ITest remotable interface.
+//! struct TestService;
+//!
+//! impl Interface for TestService {}
+//!
+//! impl ITest for TestService {
+//!     fn test(&self) -> binder::Result<String> {
+//!        Ok("testing service".to_string())
+//!     }
+//! }
+//! ```
+
+#[macro_use]
+mod proxy;
+
+#[macro_use]
+mod binder;
+mod error;
+mod native;
+mod state;
+
+use binder_ndk_sys as sys;
+
+pub mod parcel;
+
+pub use crate::binder::{
+    FromIBinder, IBinder, Interface, InterfaceClass, Remotable, TransactionCode, TransactionFlags,
+};
+pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
+pub use native::add_service;
+pub use native::Binder;
+pub use parcel::Parcel;
+pub use proxy::{get_interface, get_service};
+pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
+pub use state::{ProcessState, ThreadState};
+
+/// The public API usable outside AIDL-generated interface crates.
+pub mod public_api {
+    pub use super::parcel::ParcelFileDescriptor;
+    pub use super::{add_service, get_interface};
+    pub use super::{
+        ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, WpIBinder,
+    };
+
+    /// Binder result containing a [`Status`] on error.
+    pub type Result<T> = std::result::Result<T, Status>;
+}
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
new file mode 100644
index 0000000..185645e
--- /dev/null
+++ b/libs/binder/rust/src/native.rs
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode};
+use crate::error::{status_result, status_t, Result, StatusCode};
+use crate::parcel::{Parcel, Serialize};
+use crate::proxy::SpIBinder;
+use crate::sys;
+
+use std::convert::TryFrom;
+use std::ffi::{c_void, CString};
+use std::mem::ManuallyDrop;
+use std::ops::Deref;
+use std::ptr;
+
+/// Rust wrapper around Binder remotable objects.
+///
+/// Implements the C++ `BBinder` class, and therefore implements the C++
+/// `IBinder` interface.
+#[repr(C)]
+pub struct Binder<T: Remotable> {
+    ibinder: *mut sys::AIBinder,
+    rust_object: *mut T,
+}
+
+/// # Safety
+///
+/// A `Binder<T>` is a pair of unique owning pointers to two values:
+///   * a C++ ABBinder which the C++ API guarantees can be passed between threads
+///   * a Rust object which implements `Remotable`; this trait requires `Send + Sync`
+///
+/// Both pointers are unique (never escape the `Binder<T>` object and are not copied)
+/// so we can essentially treat `Binder<T>` as a box-like containing the two objects;
+/// the box-like object inherits `Send` from the two inner values, similarly
+/// to how `Box<T>` is `Send` if `T` is `Send`.
+unsafe impl<T: Remotable> Send for Binder<T> {}
+
+impl<T: Remotable> Binder<T> {
+    /// Create a new Binder remotable object.
+    ///
+    /// This moves the `rust_object` into an owned [`Box`] and Binder will
+    /// manage its lifetime.
+    pub fn new(rust_object: T) -> Binder<T> {
+        let class = T::get_class();
+        let rust_object = Box::into_raw(Box::new(rust_object));
+        let ibinder = unsafe {
+            // Safety: `AIBinder_new` expects a valid class pointer (which we
+            // initialize via `get_class`), and an arbitrary pointer
+            // argument. The caller owns the returned `AIBinder` pointer, which
+            // is a strong reference to a `BBinder`. This reference should be
+            // decremented via `AIBinder_decStrong` when the reference lifetime
+            // ends.
+            sys::AIBinder_new(class.into(), rust_object as *mut c_void)
+        };
+        Binder {
+            ibinder,
+            rust_object,
+        }
+    }
+
+    /// Set the extension of a binder interface. This allows a downstream
+    /// developer to add an extension to an interface without modifying its
+    /// interface file. This should be called immediately when the object is
+    /// created before it is passed to another thread.
+    ///
+    /// # Examples
+    ///
+    /// For instance, imagine if we have this Binder AIDL interface definition:
+    ///     interface IFoo { void doFoo(); }
+    ///
+    /// If an unrelated owner (perhaps in a downstream codebase) wants to make a
+    /// change to the interface, they have two options:
+    ///
+    /// 1) Historical option that has proven to be BAD! Only the original
+    ///    author of an interface should change an interface. If someone
+    ///    downstream wants additional functionality, they should not ever
+    ///    change the interface or use this method.
+    ///    ```AIDL
+    ///    BAD TO DO:  interface IFoo {                       BAD TO DO
+    ///    BAD TO DO:      void doFoo();                      BAD TO DO
+    ///    BAD TO DO: +    void doBar(); // adding a method   BAD TO DO
+    ///    BAD TO DO:  }                                      BAD TO DO
+    ///    ```
+    ///
+    /// 2) Option that this method enables!
+    ///    Leave the original interface unchanged (do not change IFoo!).
+    ///    Instead, create a new AIDL interface in a downstream package:
+    ///    ```AIDL
+    ///    package com.<name>; // new functionality in a new package
+    ///    interface IBar { void doBar(); }
+    ///    ```
+    ///
+    ///    When registering the interface, add:
+    ///
+    ///        # use binder::{Binder, Interface};
+    ///        # type MyFoo = ();
+    ///        # type MyBar = ();
+    ///        # let my_foo = ();
+    ///        # let my_bar = ();
+    ///        let mut foo: Binder<MyFoo> = Binder::new(my_foo); // class in AOSP codebase
+    ///        let bar: Binder<MyBar> = Binder::new(my_bar);     // custom extension class
+    ///        foo.set_extension(&mut bar.as_binder());          // use method in Binder
+    ///
+    ///    Then, clients of `IFoo` can get this extension:
+    ///
+    ///        # use binder::{declare_binder_interface, Binder, TransactionCode, Parcel};
+    ///        # trait IBar {}
+    ///        # declare_binder_interface! {
+    ///        #     IBar["test"] {
+    ///        #         native: BnBar(on_transact),
+    ///        #         proxy: BpBar,
+    ///        #     }
+    ///        # }
+    ///        # fn on_transact(
+    ///        #     service: &dyn IBar,
+    ///        #     code: TransactionCode,
+    ///        #     data: &Parcel,
+    ///        #     reply: &mut Parcel,
+    ///        # ) -> binder::Result<()> {
+    ///        #     Ok(())
+    ///        # }
+    ///        # impl IBar for BpBar {}
+    ///        # impl IBar for Binder<BnBar> {}
+    ///        # fn main() -> binder::Result<()> {
+    ///        # let binder = Binder::new(());
+    ///        if let Some(barBinder) = binder.get_extension()? {
+    ///            let bar = BpBar::new(barBinder)
+    ///                .expect("Extension was not of type IBar");
+    ///        } else {
+    ///            // There was no extension
+    ///        }
+    ///        # }
+    pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> {
+        let status = unsafe {
+            // Safety: `AIBinder_setExtension` expects two valid, mutable
+            // `AIBinder` pointers. We are guaranteed that both `self` and
+            // `extension` contain valid `AIBinder` pointers, because they
+            // cannot be initialized without a valid
+            // pointer. `AIBinder_setExtension` does not take ownership of
+            // either parameter.
+            sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut())
+        };
+        status_result(status)
+    }
+
+    /// Retrieve the interface descriptor string for this object's Binder
+    /// interface.
+    pub fn get_descriptor() -> &'static str {
+        T::get_descriptor()
+    }
+}
+
+impl<T: Remotable> Interface for Binder<T> {
+    /// Converts the local remotable object into a generic `SpIBinder`
+    /// reference.
+    ///
+    /// The resulting `SpIBinder` will hold its own strong reference to this
+    /// remotable object, which will prevent the object from being dropped while
+    /// the `SpIBinder` is alive.
+    fn as_binder(&self) -> SpIBinder {
+        unsafe {
+            // Safety: `self.ibinder` is guaranteed to always be a valid pointer
+            // to an `AIBinder` by the `Binder` constructor. We are creating a
+            // copy of the `self.ibinder` strong reference, but
+            // `SpIBinder::from_raw` assumes it receives an owned pointer with
+            // its own strong reference. We first increment the reference count,
+            // so that the new `SpIBinder` will be tracked as a new reference.
+            sys::AIBinder_incStrong(self.ibinder);
+            SpIBinder::from_raw(self.ibinder).unwrap()
+        }
+    }
+}
+
+impl<T: Remotable> InterfaceClassMethods for Binder<T> {
+    fn get_descriptor() -> &'static str {
+        <T as Remotable>::get_descriptor()
+    }
+
+    /// Called whenever a transaction needs to be processed by a local
+    /// implementation.
+    ///
+    /// # Safety
+    ///
+    /// Must be called with a non-null, valid pointer to a local `AIBinder` that
+    /// contains a `T` pointer in its user data. The `data` and `reply` parcel
+    /// parameters must be valid pointers to `AParcel` objects. This method does
+    /// not take ownership of any of its parameters.
+    ///
+    /// These conditions hold when invoked by `ABBinder::onTransact`.
+    unsafe extern "C" fn on_transact(
+        binder: *mut sys::AIBinder,
+        code: u32,
+        data: *const sys::AParcel,
+        reply: *mut sys::AParcel,
+    ) -> status_t {
+        let res = {
+            let mut reply = Parcel::borrowed(reply).unwrap();
+            let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap();
+            let object = sys::AIBinder_getUserData(binder);
+            let binder: &T = &*(object as *const T);
+            binder.on_transact(code, &data, &mut reply)
+        };
+        match res {
+            Ok(()) => 0i32,
+            Err(e) => e as i32,
+        }
+    }
+
+    /// Called whenever an `AIBinder` object is no longer referenced and needs
+    /// destroyed.
+    ///
+    /// # Safety
+    ///
+    /// Must be called with a valid pointer to a `T` object. After this call,
+    /// the pointer will be invalid and should not be dereferenced.
+    unsafe extern "C" fn on_destroy(object: *mut c_void) {
+        ptr::drop_in_place(object as *mut T)
+    }
+
+    /// Called whenever a new, local `AIBinder` object is needed of a specific
+    /// class.
+    ///
+    /// Constructs the user data pointer that will be stored in the object,
+    /// which will be a heap-allocated `T` object.
+    ///
+    /// # Safety
+    ///
+    /// Must be called with a valid pointer to a `T` object allocated via `Box`.
+    unsafe extern "C" fn on_create(args: *mut c_void) -> *mut c_void {
+        // We just return the argument, as it is already a pointer to the rust
+        // object created by Box.
+        args
+    }
+}
+
+impl<T: Remotable> Drop for Binder<T> {
+    // This causes C++ to decrease the strong ref count of the `AIBinder`
+    // object. We specifically do not drop the `rust_object` here. When C++
+    // actually destroys the object, it calls `on_destroy` and we can drop the
+    // `rust_object` then.
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: When `self` is dropped, we can no longer access the
+            // reference, so can decrement the reference count. `self.ibinder`
+            // is always a valid `AIBinder` pointer, so is valid to pass to
+            // `AIBinder_decStrong`.
+            sys::AIBinder_decStrong(self.ibinder);
+        }
+    }
+}
+
+impl<T: Remotable> Deref for Binder<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            // Safety: While `self` is alive, the reference count of the
+            // underlying object is > 0 and therefore `on_destroy` cannot be
+            // called. Therefore while `self` is alive, we know that
+            // `rust_object` is still a valid pointer to a heap allocated object
+            // of type `T`.
+            &*self.rust_object
+        }
+    }
+}
+
+impl<B: Remotable> Serialize for Binder<B> {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        parcel.write_binder(Some(&self.as_binder()))
+    }
+}
+
+// This implementation is an idiomatic implementation of the C++
+// `IBinder::localBinder` interface if the binder object is a Rust binder
+// service.
+impl<B: Remotable> TryFrom<SpIBinder> for Binder<B> {
+    type Error = StatusCode;
+
+    fn try_from(mut ibinder: SpIBinder) -> Result<Self> {
+        let class = B::get_class();
+        if Some(class) != ibinder.get_class() {
+            return Err(StatusCode::BAD_TYPE);
+        }
+        let userdata = unsafe {
+            // Safety: `SpIBinder` always holds a valid pointer pointer to an
+            // `AIBinder`, which we can safely pass to
+            // `AIBinder_getUserData`. `ibinder` retains ownership of the
+            // returned pointer.
+            sys::AIBinder_getUserData(ibinder.as_native_mut())
+        };
+        if userdata.is_null() {
+            return Err(StatusCode::UNEXPECTED_NULL);
+        }
+        // We are transferring the ownership of the AIBinder into the new Binder
+        // object.
+        let mut ibinder = ManuallyDrop::new(ibinder);
+        Ok(Binder {
+            ibinder: ibinder.as_native_mut(),
+            rust_object: userdata as *mut B,
+        })
+    }
+}
+
+/// # Safety
+///
+/// The constructor for `Binder` guarantees that `self.ibinder` will contain a
+/// valid, non-null pointer to an `AIBinder`, so this implementation is type
+/// safe. `self.ibinder` will remain valid for the entire lifetime of `self`
+/// because we hold a strong reference to the `AIBinder` until `self` is
+/// dropped.
+unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
+    fn as_native(&self) -> *const sys::AIBinder {
+        self.ibinder
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AIBinder {
+        self.ibinder
+    }
+}
+
+/// Register a new service with the default service manager.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier.
+pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
+    let instance = CString::new(identifier).unwrap();
+    let status = unsafe {
+        // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+        // string pointers. Caller retains ownership of both
+        // pointers. `AServiceManager_addService` creates a new strong reference
+        // and copies the string, so both pointers need only be valid until the
+        // call returns.
+        sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr())
+    };
+    status_result(status)
+}
+
+/// Tests often create a base BBinder instance; so allowing the unit
+/// type to be remotable translates nicely to Binder::new(()).
+impl Remotable for () {
+    fn get_descriptor() -> &'static str {
+        ""
+    }
+
+    fn on_transact(
+        &self,
+        _code: TransactionCode,
+        _data: &Parcel,
+        _reply: &mut Parcel,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    binder_fn_get_class!(Binder::<Self>);
+}
+
+impl Interface for () {}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
new file mode 100644
index 0000000..6c34824
--- /dev/null
+++ b/libs/binder/rust/src/parcel.rs
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Container for messages that are sent via binder.
+
+use crate::binder::AsNative;
+use crate::error::{status_result, Result, StatusCode};
+use crate::proxy::SpIBinder;
+use crate::sys;
+
+use std::cell::RefCell;
+use std::convert::TryInto;
+use std::mem::ManuallyDrop;
+use std::ptr;
+
+mod file_descriptor;
+mod parcelable;
+
+pub use self::file_descriptor::ParcelFileDescriptor;
+pub use self::parcelable::{
+    Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+};
+
+/// Container for a message (data and object references) that can be sent
+/// through Binder.
+///
+/// A Parcel can contain both serialized data that will be deserialized on the
+/// other side of the IPC, and references to live Binder objects that will
+/// result in the other side receiving a proxy Binder connected with the
+/// original Binder in the Parcel.
+pub enum Parcel {
+    /// Owned parcel pointer
+    Owned(*mut sys::AParcel),
+    /// Borrowed parcel pointer (will not be destroyed on drop)
+    Borrowed(*mut sys::AParcel),
+}
+
+/// # Safety
+///
+/// The `Parcel` constructors guarantee that a `Parcel` object will always
+/// contain a valid pointer to an `AParcel`.
+unsafe impl AsNative<sys::AParcel> for Parcel {
+    fn as_native(&self) -> *const sys::AParcel {
+        match *self {
+            Self::Owned(x) | Self::Borrowed(x) => x,
+        }
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AParcel {
+        match *self {
+            Self::Owned(x) | Self::Borrowed(x) => x,
+        }
+    }
+}
+
+impl Parcel {
+    /// Create a borrowed reference to a parcel object from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe if the raw pointer parameter is either null
+    /// (resulting in `None`), or a valid pointer to an `AParcel` object.
+    pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
+        ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
+    }
+
+    /// Create an owned reference to a parcel object from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe if the raw pointer parameter is either null
+    /// (resulting in `None`), or a valid pointer to an `AParcel` object. The
+    /// parcel object must be owned by the caller prior to this call, as this
+    /// constructor takes ownership of the parcel and will destroy it on drop.
+    pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> {
+        ptr.as_mut().map(|ptr| Self::Owned(ptr))
+    }
+
+    /// Consume the parcel, transferring ownership to the caller if the parcel
+    /// was owned.
+    pub(crate) fn into_raw(mut self) -> *mut sys::AParcel {
+        let ptr = self.as_native_mut();
+        let _ = ManuallyDrop::new(self);
+        ptr
+    }
+}
+
+// Data serialization methods
+impl Parcel {
+    /// Data written to parcelable is zero'd before being deleted or reallocated.
+    pub fn mark_sensitive(&mut self) {
+        unsafe {
+            // Safety: guaranteed to have a parcel object, and this method never fails
+            sys::AParcel_markSensitive(self.as_native())
+        }
+    }
+
+    /// Write a type that implements [`Serialize`] to the `Parcel`.
+    pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+        parcelable.serialize(self)
+    }
+
+    /// Writes the length of a slice to the `Parcel`.
+    ///
+    /// This is used in AIDL-generated client side code to indicate the
+    /// allocated space for an output array parameter.
+    pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> {
+        if let Some(slice) = slice {
+            let len: i32 = slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?;
+            self.write(&len)
+        } else {
+            self.write(&-1i32)
+        }
+    }
+
+    /// Perform a series of writes to the `Parcel`, prepended with the length
+    /// (in bytes) of the written data.
+    ///
+    /// The length `0i32` will be written to the parcel first, followed by the
+    /// writes performed by the callback. The initial length will then be
+    /// updated to the length of all data written by the callback, plus the
+    /// size of the length elemement itself (4 bytes).
+    ///
+    /// # Examples
+    ///
+    /// After the following call:
+    ///
+    /// ```
+    /// # use binder::{Binder, Interface, Parcel};
+    /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+    /// parcel.sized_write(|subparcel| {
+    ///     subparcel.write(&1u32)?;
+    ///     subparcel.write(&2u32)?;
+    ///     subparcel.write(&3u32)
+    /// });
+    /// ```
+    ///
+    /// `parcel` will contain the following:
+    ///
+    /// ```ignore
+    /// [16i32, 1u32, 2u32, 3u32]
+    /// ```
+    pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+    where for<'a>
+        F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+    {
+        let start = self.get_data_position();
+        self.write(&0i32)?;
+        {
+            let subparcel = WritableSubParcel(RefCell::new(self));
+            f(&subparcel)?;
+        }
+        let end = self.get_data_position();
+        unsafe {
+            self.set_data_position(start)?;
+        }
+        assert!(end >= start);
+        self.write(&(end - start))?;
+        unsafe {
+            self.set_data_position(end)?;
+        }
+        Ok(())
+    }
+
+    /// Returns the current position in the parcel data.
+    pub fn get_data_position(&self) -> i32 {
+        unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
+            // and this call is otherwise safe.
+            sys::AParcel_getDataPosition(self.as_native())
+        }
+    }
+
+    /// Move the current read/write position in the parcel.
+    ///
+    /// The new position must be a position previously returned by
+    /// `self.get_data_position()`.
+    ///
+    /// # Safety
+    ///
+    /// This method is safe if `pos` is less than the current size of the parcel
+    /// data buffer. Otherwise, we are relying on correct bounds checking in the
+    /// Parcel C++ code on every subsequent read or write to this parcel. If all
+    /// accesses are bounds checked, this call is still safe, but we can't rely
+    /// on that.
+    pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
+        status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
+    }
+}
+
+/// A segment of a writable parcel, used for [`Parcel::sized_write`].
+pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+
+impl<'a> WritableSubParcel<'a> {
+    /// Write a type that implements [`Serialize`] to the sub-parcel.
+    pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
+        parcelable.serialize(&mut *self.0.borrow_mut())
+    }
+}
+
+// Data deserialization methods
+impl Parcel {
+    /// Attempt to read a type that implements [`Deserialize`] from this
+    /// `Parcel`.
+    pub fn read<D: Deserialize>(&self) -> Result<D> {
+        D::deserialize(self)
+    }
+
+    /// Read a vector size from the `Parcel` and resize the given output vector
+    /// to be correctly sized for that amount of data.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> {
+        let len: i32 = self.read()?;
+
+        if len < 0 {
+            return Err(StatusCode::UNEXPECTED_NULL);
+        }
+
+        // usize in Rust may be 16-bit, so i32 may not fit
+        let len = len.try_into().unwrap();
+        out_vec.resize_with(len, Default::default);
+
+        Ok(())
+    }
+
+    /// Read a vector size from the `Parcel` and either create a correctly sized
+    /// vector for that amount of data or set the output parameter to None if
+    /// the vector should be null.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_nullable_out_vec<D: Default + Deserialize>(
+        &self,
+        out_vec: &mut Option<Vec<D>>,
+    ) -> Result<()> {
+        let len: i32 = self.read()?;
+
+        if len < 0 {
+            *out_vec = None;
+        } else {
+            // usize in Rust may be 16-bit, so i32 may not fit
+            let len = len.try_into().unwrap();
+            let mut vec = Vec::with_capacity(len);
+            vec.resize_with(len, Default::default);
+            *out_vec = Some(vec);
+        }
+
+        Ok(())
+    }
+}
+
+// Internal APIs
+impl Parcel {
+    pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
+        unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
+            // null or a valid pointer to an `AIBinder`, both of which are
+            // valid, safe inputs to `AParcel_writeStrongBinder`.
+            //
+            // This call does not take ownership of the binder. However, it does
+            // require a mutable pointer, which we cannot extract from an
+            // immutable reference, so we clone the binder, incrementing the
+            // refcount before the call. The refcount will be immediately
+            // decremented when this temporary is dropped.
+            status_result(sys::AParcel_writeStrongBinder(
+                self.as_native_mut(),
+                binder.cloned().as_native_mut(),
+            ))
+        }
+    }
+
+    pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
+        let mut binder = ptr::null_mut();
+        let status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. We pass a valid, mutable out pointer to the `binder`
+            // parameter. After this call, `binder` will be either null or a
+            // valid pointer to an `AIBinder` owned by the caller.
+            sys::AParcel_readStrongBinder(self.as_native(), &mut binder)
+        };
+
+        status_result(status)?;
+
+        Ok(unsafe {
+            // Safety: `binder` is either null or a valid, owned pointer at this
+            // point, so can be safely passed to `SpIBinder::from_raw`.
+            SpIBinder::from_raw(binder)
+        })
+    }
+}
+
+impl Drop for Parcel {
+    fn drop(&mut self) {
+        // Run the C++ Parcel complete object destructor
+        if let Self::Owned(ptr) = *self {
+            unsafe {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. If we own the parcel, we can safely delete it
+                // here.
+                sys::AParcel_delete(ptr)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+impl Parcel {
+    /// Create a new parcel tied to a bogus binder. TESTING ONLY!
+    ///
+    /// This can only be used for testing! All real parcel operations must be
+    /// done in the callback to [`IBinder::transact`] or in
+    /// [`Remotable::on_transact`] using the parcels provided to these methods.
+    pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> {
+        let mut input = ptr::null_mut();
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `binder` always contains a
+            // valid pointer to an `AIBinder`. We pass a valid, mutable out
+            // pointer to receive a newly constructed parcel. When successful
+            // this function assigns a new pointer to an `AParcel` to `input`
+            // and transfers ownership of this pointer to the caller. Thus,
+            // after this call, `input` will either be null or point to a valid,
+            // owned `AParcel`.
+            sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input)
+        };
+        status_result(status)?;
+        unsafe {
+            // Safety: `input` is either null or a valid, owned pointer to an
+            // `AParcel`, so is valid to safe to
+            // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel
+            // pointer.
+            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
+        }
+    }
+}
+
+#[test]
+fn test_read_write() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+
+    let mut service = Binder::new(()).as_binder();
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<i8>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<u16>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<i32>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<u32>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<i64>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<u64>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<f32>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<f64>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    assert_eq!(parcel.read::<Option<String>>(), Ok(None));
+    assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
+
+    assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
+
+    parcel.write(&1i32).unwrap();
+
+    unsafe {
+        parcel.set_data_position(start).unwrap();
+    }
+
+    let i: i32 = parcel.read().unwrap();
+    assert_eq!(i, 1i32);
+}
+
+#[test]
+#[allow(clippy::float_cmp)]
+fn test_read_data() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+
+    let mut service = Binder::new(()).as_binder();
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let str_start = parcel.get_data_position();
+
+    parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
+    // Skip over string length
+    unsafe {
+        assert!(parcel.set_data_position(str_start).is_ok());
+    }
+    assert_eq!(parcel.read::<i32>().unwrap(), 15);
+    let start = parcel.get_data_position();
+
+    assert_eq!(parcel.read::<bool>().unwrap(), true);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<i8>().unwrap(), 72i8);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u16>().unwrap(), 25928);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<i32>().unwrap(), 1819043144);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 1819043144);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<i64>().unwrap(), 4764857262830019912);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u64>().unwrap(), 4764857262830019912);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(
+        parcel.read::<f32>().unwrap(),
+        1143139100000000000000000000.0
+    );
+    assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<f64>().unwrap(), 34732488246.197815);
+
+    // Skip back to before the string length
+    unsafe {
+        assert!(parcel.set_data_position(str_start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<Vec<u8>>().unwrap(), b"Hello, Binder!\0");
+}
+
+#[test]
+fn test_utf8_utf16_conversions() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+
+    let mut service = Binder::new(()).as_binder();
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    assert!(parcel.write("Hello, Binder!").is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert_eq!(
+        parcel.read::<Option<String>>().unwrap().unwrap(),
+        "Hello, Binder!",
+    );
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert!(parcel.write("Embedded null \0 inside a string").is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert_eq!(
+        parcel.read::<Option<String>>().unwrap().unwrap(),
+        "Embedded null \0 inside a string",
+    );
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
+    assert!(parcel
+        .write(
+            &[
+                String::from("str4"),
+                String::from("str5"),
+                String::from("str6"),
+            ][..]
+        )
+        .is_ok());
+
+    let s1 = "Hello, Binder!";
+    let s2 = "This is a utf8 string.";
+    let s3 = "Some more text here.";
+
+    assert!(parcel.write(&[s1, s2, s3][..]).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(
+        parcel.read::<Vec<String>>().unwrap(),
+        ["str1", "str2", "str3"]
+    );
+    assert_eq!(
+        parcel.read::<Vec<String>>().unwrap(),
+        ["str4", "str5", "str6"]
+    );
+    assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
+}
+
+#[test]
+fn test_sized_write() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+
+    let mut service = Binder::new(()).as_binder();
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    let arr = [1i32, 2i32, 3i32];
+
+    parcel.sized_write(|subparcel| {
+        subparcel.write(&arr[..])
+    }).expect("Could not perform sized write");
+
+    // i32 sub-parcel length + i32 array length + 3 i32 elements
+    let expected_len = 20i32;
+
+    assert_eq!(parcel.get_data_position(), start + expected_len);
+
+    unsafe {
+        parcel.set_data_position(start).unwrap();
+    }
+
+    assert_eq!(
+        expected_len,
+        parcel.read().unwrap(),
+    );
+
+    assert_eq!(
+        parcel.read::<Vec<i32>>().unwrap(),
+        &arr,
+    );
+}
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
new file mode 100644
index 0000000..20e9178
--- /dev/null
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use super::{
+    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+    SerializeOption,
+};
+use crate::binder::AsNative;
+use crate::error::{status_result, Result, StatusCode};
+use crate::sys;
+
+use std::fs::File;
+use std::os::unix::io::{AsRawFd, FromRawFd};
+
+/// Rust version of the Java class android.os.ParcelFileDescriptor
+#[derive(Debug)]
+pub struct ParcelFileDescriptor(File);
+
+impl ParcelFileDescriptor {
+    /// Create a new `ParcelFileDescriptor`
+    pub fn new(file: File) -> Self {
+        Self(file)
+    }
+}
+
+impl AsRef<File> for ParcelFileDescriptor {
+    fn as_ref(&self) -> &File {
+        &self.0
+    }
+}
+
+impl From<ParcelFileDescriptor> for File {
+    fn from(file: ParcelFileDescriptor) -> File {
+        file.0
+    }
+}
+
+impl Serialize for ParcelFileDescriptor {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        let fd = self.0.as_raw_fd();
+        let status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
+            // valid file, so we can borrow a valid file
+            // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
+            // ownership of the fd, so we need not duplicate it first.
+            sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd)
+        };
+        status_result(status)
+    }
+}
+
+impl SerializeArray for ParcelFileDescriptor {}
+
+impl SerializeOption for ParcelFileDescriptor {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        if let Some(f) = this {
+            f.serialize(parcel)
+        } else {
+            let status = unsafe {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
+                // value `-1` as the file descriptor to signify serializing a
+                // null file descriptor.
+                sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32)
+            };
+            status_result(status)
+        }
+    }
+}
+
+impl SerializeArray for Option<ParcelFileDescriptor> {}
+
+impl DeserializeOption for ParcelFileDescriptor {
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+        let mut fd = -1i32;
+        unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. We pass a valid mutable pointer to an i32, which
+            // `AParcel_readParcelFileDescriptor` assigns the valid file
+            // descriptor into, or `-1` if deserializing a null file
+            // descriptor. The read function passes ownership of the file
+            // descriptor to its caller if it was non-null, so we must take
+            // ownership of the file and ensure that it is eventually closed.
+            status_result(sys::AParcel_readParcelFileDescriptor(
+                parcel.as_native(),
+                &mut fd,
+            ))?;
+        }
+        if fd < 0 {
+            Ok(None)
+        } else {
+            let file = unsafe {
+                // Safety: At this point, we know that the file descriptor was
+                // not -1, so must be a valid, owned file descriptor which we
+                // can safely turn into a `File`.
+                File::from_raw_fd(fd)
+            };
+            Ok(Some(ParcelFileDescriptor::new(file)))
+        }
+    }
+}
+
+impl DeserializeArray for Option<ParcelFileDescriptor> {}
+
+impl Deserialize for ParcelFileDescriptor {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        Deserialize::deserialize(parcel)
+            .transpose()
+            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+    }
+}
+
+impl DeserializeArray for ParcelFileDescriptor {}
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
new file mode 100644
index 0000000..8d18fb4
--- /dev/null
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -0,0 +1,989 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::binder::{AsNative, FromIBinder};
+use crate::error::{status_result, status_t, Result, Status, StatusCode};
+use crate::parcel::Parcel;
+use crate::proxy::SpIBinder;
+use crate::sys;
+
+use std::convert::TryInto;
+use std::ffi::c_void;
+use std::os::raw::{c_char, c_ulong};
+use std::mem::{self, MaybeUninit};
+use std::ptr;
+use std::slice;
+
+/// A struct whose instances can be written to a [`Parcel`].
+// Might be able to hook this up as a serde backend in the future?
+pub trait Serialize {
+    /// Serialize this instance into the given [`Parcel`].
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()>;
+}
+
+/// A struct whose instances can be restored from a [`Parcel`].
+// Might be able to hook this up as a serde backend in the future?
+pub trait Deserialize: Sized {
+    /// Deserialize an instance from the given [`Parcel`].
+    fn deserialize(parcel: &Parcel) -> Result<Self>;
+}
+
+/// Helper trait for types that can be serialized as arrays.
+/// Defaults to calling Serialize::serialize() manually for every element,
+/// but can be overridden for custom implementations like `writeByteArray`.
+// Until specialization is stabilized in Rust, we need this to be a separate
+// trait because it's the only way to have a default implementation for a method.
+// We want the default implementation for most types, but an override for
+// a few special ones like `readByteArray` for `u8`.
+pub trait SerializeArray: Serialize + Sized {
+    /// Serialize an array of this type into the given [`Parcel`].
+    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+        let res = unsafe {
+            // Safety: Safe FFI, slice will always be a safe pointer to pass.
+            sys::AParcel_writeParcelableArray(
+                parcel.as_native_mut(),
+                slice.as_ptr() as *const c_void,
+                slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?,
+                Some(serialize_element::<Self>),
+            )
+        };
+        status_result(res)
+    }
+}
+
+/// Callback to serialize an element of a generic parcelable array.
+///
+/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it
+/// doesn't provide an index larger than the length of the original slice in
+/// serialize_array, this operation is safe. The index provided is zero-based.
+unsafe extern "C" fn serialize_element<T: Serialize>(
+    parcel: *mut sys::AParcel,
+    array: *const c_void,
+    index: c_ulong,
+) -> status_t {
+    // c_ulong and usize are the same, but we need the explicitly sized version
+    // so the function signature matches what bindgen generates.
+    let index = index as usize;
+
+    let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
+
+    let mut parcel = match Parcel::borrowed(parcel) {
+        None => return StatusCode::UNEXPECTED_NULL as status_t,
+        Some(p) => p,
+    };
+
+    slice[index].serialize(&mut parcel)
+                .err()
+                .unwrap_or(StatusCode::OK)
+        as status_t
+}
+
+/// Helper trait for types that can be deserialized as arrays.
+/// Defaults to calling Deserialize::deserialize() manually for every element,
+/// but can be overridden for custom implementations like `readByteArray`.
+pub trait DeserializeArray: Deserialize {
+    /// Deserialize an array of type from the given [`Parcel`].
+    fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+        let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
+        let res = unsafe {
+            // Safety: Safe FFI, vec is the correct opaque type expected by
+            // allocate_vec and deserialize_element.
+            sys::AParcel_readParcelableArray(
+                parcel.as_native(),
+                &mut vec as *mut _ as *mut c_void,
+                Some(allocate_vec::<Self>),
+                Some(deserialize_element::<Self>),
+            )
+        };
+        status_result(res)?;
+        let vec: Option<Vec<Self>> = unsafe {
+            // Safety: We are assuming that the NDK correctly initialized every
+            // element of the vector by now, so we know that all the
+            // MaybeUninits are now properly initialized. We can transmute from
+            // Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T> has the same
+            // alignment and size as T, so the pointer to the vector allocation
+            // will be compatible.
+            mem::transmute(vec)
+        };
+        Ok(vec)
+    }
+}
+
+/// Callback to deserialize a parcelable element.
+///
+/// The opaque array data pointer must be a mutable pointer to an
+/// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
+/// (zero-based).
+unsafe extern "C" fn deserialize_element<T: Deserialize>(
+    parcel: *const sys::AParcel,
+    array: *mut c_void,
+    index: c_ulong,
+) -> status_t {
+    // c_ulong and usize are the same, but we need the explicitly sized version
+    // so the function signature matches what bindgen generates.
+    let index = index as usize;
+
+    let vec = &mut *(array as *mut Option<Vec<MaybeUninit<T>>>);
+    let vec = match vec {
+        Some(v) => v,
+        None => return StatusCode::BAD_INDEX as status_t,
+    };
+
+    let parcel = match Parcel::borrowed(parcel as *mut _) {
+        None => return StatusCode::UNEXPECTED_NULL as status_t,
+        Some(p) => p,
+    };
+    let element = match parcel.read() {
+        Ok(e) => e,
+        Err(code) => return code as status_t,
+    };
+    ptr::write(vec[index].as_mut_ptr(), element);
+    StatusCode::OK as status_t
+}
+
+/// Helper trait for types that can be nullable when serialized.
+// We really need this trait instead of implementing `Serialize for Option<T>`
+// because of the Rust orphan rule which prevents us from doing
+// `impl Serialize for Option<&dyn IFoo>` for AIDL interfaces.
+// Instead we emit `impl SerializeOption for dyn IFoo` which is allowed.
+// We also use it to provide a default implementation for AIDL-generated
+// parcelables.
+pub trait SerializeOption: Serialize {
+    /// Serialize an Option of this type into the given [`Parcel`].
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        if let Some(inner) = this {
+            parcel.write(&1i32)?;
+            parcel.write(inner)
+        } else {
+            parcel.write(&0i32)
+        }
+    }
+}
+
+/// Helper trait for types that can be nullable when deserialized.
+pub trait DeserializeOption: Deserialize {
+    /// Deserialize an Option of this type from the given [`Parcel`].
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+        let null: i32 = parcel.read()?;
+        if null == 0 {
+            Ok(None)
+        } else {
+            parcel.read().map(Some)
+        }
+    }
+}
+
+/// Callback to allocate a vector for parcel array read functions.
+///
+/// This variant is for APIs which use an out buffer pointer.
+///
+/// # Safety
+///
+/// The opaque data pointer passed to the array read function must be a mutable
+/// pointer to an `Option<Vec<MaybeUninit<T>>>`. `buffer` will be assigned a mutable pointer
+/// to the allocated vector data if this function returns true.
+unsafe extern "C" fn allocate_vec_with_buffer<T>(
+    data: *mut c_void,
+    len: i32,
+    buffer: *mut *mut T,
+) -> bool {
+    let res = allocate_vec::<T>(data, len);
+    let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
+    if let Some(new_vec) = vec {
+        *buffer = new_vec.as_mut_ptr() as *mut T;
+    }
+    res
+}
+
+/// Callback to allocate a vector for parcel array read functions.
+///
+/// # Safety
+///
+/// The opaque data pointer passed to the array read function must be a mutable
+/// pointer to an `Option<Vec<MaybeUninit<T>>>`.
+unsafe extern "C" fn allocate_vec<T>(
+    data: *mut c_void,
+    len: i32,
+) -> bool {
+    let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
+    if len < 0 {
+        *vec = None;
+        return true;
+    }
+    let mut new_vec: Vec<MaybeUninit<T>> = Vec::with_capacity(len as usize);
+
+    // Safety: We are filling the vector with uninitialized data here, but this
+    // is safe because the vector contains MaybeUninit elements which can be
+    // uninitialized. We're putting off the actual unsafe bit, transmuting the
+    // vector to a Vec<T> until the contents are initialized.
+    new_vec.set_len(len as usize);
+
+    ptr::write(vec, Some(new_vec));
+    true
+}
+
+
+macro_rules! parcelable_primitives {
+    {
+        $(
+            impl $trait:ident for $ty:ty = $fn:path;
+        )*
+    } => {
+        $(impl_parcelable!{$trait, $ty, $fn})*
+    };
+}
+
+macro_rules! impl_parcelable {
+    {Serialize, $ty:ty, $write_fn:path} => {
+        impl Serialize for $ty {
+            fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+                unsafe {
+                    // Safety: `Parcel` always contains a valid pointer to an
+                    // `AParcel`, and any `$ty` literal value is safe to pass to
+                    // `$write_fn`.
+                    status_result($write_fn(parcel.as_native_mut(), *self))
+                }
+            }
+        }
+    };
+
+    {Deserialize, $ty:ty, $read_fn:path} => {
+        impl Deserialize for $ty {
+            fn deserialize(parcel: &Parcel) -> Result<Self> {
+                let mut val = Self::default();
+                unsafe {
+                    // Safety: `Parcel` always contains a valid pointer to an
+                    // `AParcel`. We pass a valid, mutable pointer to `val`, a
+                    // literal of type `$ty`, and `$read_fn` will write the
+                    // value read into `val` if successful
+                    status_result($read_fn(parcel.as_native(), &mut val))?
+                };
+                Ok(val)
+            }
+        }
+    };
+
+    {SerializeArray, $ty:ty, $write_array_fn:path} => {
+        impl SerializeArray for $ty {
+            fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+                let status = unsafe {
+                    // Safety: `Parcel` always contains a valid pointer to an
+                    // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
+                    // will be a valid pointer to an array of elements of type
+                    // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
+                    // dangling, but this is safe since the pointer is not
+                    // dereferenced if the length parameter is 0.
+                    $write_array_fn(
+                        parcel.as_native_mut(),
+                        slice.as_ptr(),
+                        slice
+                            .len()
+                            .try_into()
+                            .or(Err(StatusCode::BAD_VALUE))?,
+                    )
+                };
+                status_result(status)
+            }
+        }
+    };
+
+    {DeserializeArray, $ty:ty, $read_array_fn:path} => {
+        impl DeserializeArray for $ty {
+            fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+                let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
+                let status = unsafe {
+                    // Safety: `Parcel` always contains a valid pointer to an
+                    // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
+                    // be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
+                    // correct for it.
+                    $read_array_fn(
+                        parcel.as_native(),
+                        &mut vec as *mut _ as *mut c_void,
+                        Some(allocate_vec_with_buffer),
+                    )
+                };
+                status_result(status)?;
+                let vec: Option<Vec<Self>> = unsafe {
+                    // Safety: We are assuming that the NDK correctly
+                    // initialized every element of the vector by now, so we
+                    // know that all the MaybeUninits are now properly
+                    // initialized. We can transmute from Vec<MaybeUninit<T>> to
+                    // Vec<T> because MaybeUninit<T> has the same alignment and
+                    // size as T, so the pointer to the vector allocation will
+                    // be compatible.
+                    mem::transmute(vec)
+                };
+                Ok(vec)
+            }
+        }
+    };
+}
+
+parcelable_primitives! {
+    impl Serialize for bool = sys::AParcel_writeBool;
+    impl Deserialize for bool = sys::AParcel_readBool;
+
+    // This is only safe because `Option<Vec<u8>>` is interchangeable with
+    // `Option<Vec<i8>>` (what the allocator function actually allocates.
+    impl DeserializeArray for u8 = sys::AParcel_readByteArray;
+
+    impl Serialize for i8 = sys::AParcel_writeByte;
+    impl Deserialize for i8 = sys::AParcel_readByte;
+    impl SerializeArray for i8 = sys::AParcel_writeByteArray;
+    impl DeserializeArray for i8 = sys::AParcel_readByteArray;
+
+    impl Serialize for u16 = sys::AParcel_writeChar;
+    impl Deserialize for u16 = sys::AParcel_readChar;
+    impl SerializeArray for u16 = sys::AParcel_writeCharArray;
+    impl DeserializeArray for u16 = sys::AParcel_readCharArray;
+
+    // This is only safe because `Option<Vec<i16>>` is interchangeable with
+    // `Option<Vec<u16>>` (what the allocator function actually allocates.
+    impl DeserializeArray for i16 = sys::AParcel_readCharArray;
+
+    impl Serialize for u32 = sys::AParcel_writeUint32;
+    impl Deserialize for u32 = sys::AParcel_readUint32;
+    impl SerializeArray for u32 = sys::AParcel_writeUint32Array;
+    impl DeserializeArray for u32 = sys::AParcel_readUint32Array;
+
+    impl Serialize for i32 = sys::AParcel_writeInt32;
+    impl Deserialize for i32 = sys::AParcel_readInt32;
+    impl SerializeArray for i32 = sys::AParcel_writeInt32Array;
+    impl DeserializeArray for i32 = sys::AParcel_readInt32Array;
+
+    impl Serialize for u64 = sys::AParcel_writeUint64;
+    impl Deserialize for u64 = sys::AParcel_readUint64;
+    impl SerializeArray for u64 = sys::AParcel_writeUint64Array;
+    impl DeserializeArray for u64 = sys::AParcel_readUint64Array;
+
+    impl Serialize for i64 = sys::AParcel_writeInt64;
+    impl Deserialize for i64 = sys::AParcel_readInt64;
+    impl SerializeArray for i64 = sys::AParcel_writeInt64Array;
+    impl DeserializeArray for i64 = sys::AParcel_readInt64Array;
+
+    impl Serialize for f32 = sys::AParcel_writeFloat;
+    impl Deserialize for f32 = sys::AParcel_readFloat;
+    impl SerializeArray for f32 = sys::AParcel_writeFloatArray;
+    impl DeserializeArray for f32 = sys::AParcel_readFloatArray;
+
+    impl Serialize for f64 = sys::AParcel_writeDouble;
+    impl Deserialize for f64 = sys::AParcel_readDouble;
+    impl SerializeArray for f64 = sys::AParcel_writeDoubleArray;
+    impl DeserializeArray for f64 = sys::AParcel_readDoubleArray;
+}
+
+impl SerializeArray for bool {}
+impl DeserializeArray for bool {}
+
+impl Serialize for u8 {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        (*self as i8).serialize(parcel)
+    }
+}
+
+impl Deserialize for u8 {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        i8::deserialize(parcel).map(|v| v as u8)
+    }
+}
+
+impl SerializeArray for u8 {
+    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+        let status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+            // valid pointer to an array of elements of type `$ty`. If the slice
+            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+            // since the pointer is not dereferenced if the length parameter is
+            // 0.
+            sys::AParcel_writeByteArray(
+                parcel.as_native_mut(),
+                slice.as_ptr() as *const i8,
+                slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?,
+            )
+        };
+        status_result(status)
+    }
+}
+
+impl Serialize for i16 {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        (*self as u16).serialize(parcel)
+    }
+}
+
+impl Deserialize for i16 {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        u16::deserialize(parcel).map(|v| v as i16)
+    }
+}
+
+impl SerializeArray for i16 {
+    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+        let status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+            // valid pointer to an array of elements of type `$ty`. If the slice
+            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+            // since the pointer is not dereferenced if the length parameter is
+            // 0.
+            sys::AParcel_writeCharArray(
+                parcel.as_native_mut(),
+                slice.as_ptr() as *const u16,
+                slice.len().try_into().or(Err(StatusCode::BAD_VALUE))?,
+            )
+        };
+        status_result(status)
+    }
+}
+
+impl SerializeOption for str {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        match this {
+            None => unsafe {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. If the string pointer is null,
+                // `AParcel_writeString` requires that the length is -1 to
+                // indicate that we want to serialize a null string.
+                status_result(sys::AParcel_writeString(
+                    parcel.as_native_mut(),
+                    ptr::null(),
+                    -1,
+                ))
+            },
+            Some(s) => unsafe {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
+                // string pointer of `length` bytes, which is what str in Rust
+                // is. The docstring for `AParcel_writeString` says that the
+                // string input should be null-terminated, but it doesn't
+                // actually rely on that fact in the code. If this ever becomes
+                // necessary, we will need to null-terminate the str buffer
+                // before sending it.
+                status_result(sys::AParcel_writeString(
+                    parcel.as_native_mut(),
+                    s.as_ptr() as *const c_char,
+                    s.as_bytes()
+                        .len()
+                        .try_into()
+                        .or(Err(StatusCode::BAD_VALUE))?,
+                ))
+            },
+        }
+    }
+}
+
+impl SerializeArray for Option<&str> {}
+
+impl Serialize for str {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        Some(self).serialize(parcel)
+    }
+}
+
+impl SerializeArray for &str {}
+
+impl Serialize for String {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        Some(self.as_str()).serialize(parcel)
+    }
+}
+
+impl SerializeArray for String {}
+
+impl SerializeOption for String {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(this.map(String::as_str), parcel)
+    }
+}
+
+impl SerializeArray for Option<String> {}
+
+impl Deserialize for Option<String> {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        let mut vec: Option<Vec<u8>> = None;
+        let status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
+            // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
+            // for `allocate_vec`, so `vec` is safe to pass as the opaque data
+            // pointer on platforms where char is signed.
+            sys::AParcel_readString(
+                parcel.as_native(),
+                &mut vec as *mut _ as *mut c_void,
+                Some(allocate_vec_with_buffer),
+            )
+        };
+
+        status_result(status)?;
+        vec.map(|mut s| {
+            // The vector includes a null-terminator and we don't want the
+            // string to be null-terminated for Rust.
+            s.pop();
+            String::from_utf8(s).or(Err(StatusCode::BAD_VALUE))
+        })
+        .transpose()
+    }
+}
+
+impl DeserializeArray for Option<String> {}
+
+impl Deserialize for String {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        Deserialize::deserialize(parcel)
+            .transpose()
+            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+    }
+}
+
+impl DeserializeArray for String {}
+
+impl<T: SerializeArray> Serialize for [T] {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        SerializeArray::serialize_array(self, parcel)
+    }
+}
+
+impl<T: SerializeArray> Serialize for Vec<T> {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        SerializeArray::serialize_array(&self[..], parcel)
+    }
+}
+
+impl<T: SerializeArray> SerializeOption for [T] {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        if let Some(v) = this {
+            SerializeArray::serialize_array(v, parcel)
+        } else {
+            parcel.write(&-1i32)
+        }
+    }
+}
+
+impl<T: SerializeArray> SerializeOption for Vec<T> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(this.map(Vec::as_slice), parcel)
+    }
+}
+
+impl<T: DeserializeArray> Deserialize for Vec<T> {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        DeserializeArray::deserialize_array(parcel)
+            .transpose()
+            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+    }
+}
+
+impl<T: DeserializeArray> DeserializeOption for Vec<T> {
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+        DeserializeArray::deserialize_array(parcel)
+    }
+}
+
+impl Serialize for Status {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an `AParcel`
+            // and `Status` always contains a valid pointer to an `AStatus`, so
+            // both parameters are valid and safe. This call does not take
+            // ownership of either of its parameters.
+            status_result(sys::AParcel_writeStatusHeader(
+                parcel.as_native_mut(),
+                self.as_native(),
+            ))
+        }
+    }
+}
+
+impl Deserialize for Status {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        let mut status_ptr = ptr::null_mut();
+        let ret_status = unsafe {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. We pass a mutable out pointer which will be
+            // assigned a valid `AStatus` pointer if the function returns
+            // status OK. This function passes ownership of the status
+            // pointer to the caller, if it was assigned.
+            sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr)
+        };
+        status_result(ret_status)?;
+        Ok(unsafe {
+            // Safety: At this point, the return status of the read call was ok,
+            // so we know that `status_ptr` is a valid, owned pointer to an
+            // `AStatus`, from which we can safely construct a `Status` object.
+            Status::from_ptr(status_ptr)
+        })
+    }
+}
+
+impl<T: Serialize + ?Sized> Serialize for Box<T> {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        Serialize::serialize(&**self, parcel)
+    }
+}
+
+impl<T: SerializeOption + ?Sized> SerializeOption for Box<T> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(this.map(|b| &**b), parcel)
+    }
+}
+
+impl<T: FromIBinder + ?Sized> Deserialize for Box<T> {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        let ibinder: SpIBinder = parcel.read()?;
+        FromIBinder::try_from(ibinder)
+    }
+}
+
+impl<T: FromIBinder + ?Sized> DeserializeOption for Box<T> {
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+        let ibinder: Option<SpIBinder> = parcel.read()?;
+        ibinder.map(FromIBinder::try_from).transpose()
+    }
+}
+
+// We need these to support Option<&T> for all T
+impl<T: Serialize + ?Sized> Serialize for &T {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        Serialize::serialize(*self, parcel)
+    }
+}
+
+impl<T: SerializeOption + ?Sized> SerializeOption for &T {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(this.copied(), parcel)
+    }
+}
+
+impl<T: SerializeOption> Serialize for Option<T> {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(self.as_ref(), parcel)
+    }
+}
+
+impl<T: DeserializeOption> Deserialize for Option<T> {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        DeserializeOption::deserialize_option(parcel)
+    }
+}
+
+#[test]
+fn test_custom_parcelable() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+    let mut service = Binder::new(()).as_binder();
+
+    struct Custom(u32, bool, String, Vec<String>);
+
+    impl Serialize for Custom {
+        fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+            self.0.serialize(parcel)?;
+            self.1.serialize(parcel)?;
+            self.2.serialize(parcel)?;
+            self.3.serialize(parcel)
+        }
+    }
+
+    impl Deserialize for Custom {
+        fn deserialize(parcel: &Parcel) -> Result<Self> {
+            Ok(Custom(
+                parcel.read()?,
+                parcel.read()?,
+                parcel.read()?,
+                parcel.read::<Option<Vec<String>>>()?.unwrap(),
+            ))
+        }
+    }
+
+    let string8 = "Custom Parcelable".to_string();
+
+    let s1 = "str1".to_string();
+    let s2 = "str2".to_string();
+    let s3 = "str3".to_string();
+
+    let strs = vec![s1, s2, s3];
+
+    let custom = Custom(123_456_789, true, string8, strs);
+
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    assert!(custom.serialize(&mut parcel).is_ok());
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let custom2 = Custom::deserialize(&parcel).unwrap();
+
+    assert_eq!(custom2.0, 123_456_789);
+    assert!(custom2.1);
+    assert_eq!(custom2.2, custom.2);
+    assert_eq!(custom2.3, custom.3);
+}
+
+#[test]
+#[allow(clippy::excessive_precision)]
+fn test_slice_parcelables() {
+    use crate::binder::Interface;
+    use crate::native::Binder;
+    let mut service = Binder::new(()).as_binder();
+
+    let bools = [true, false, false, true];
+
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    assert!(bools.serialize(&mut parcel).is_ok());
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4);
+    assert_eq!(parcel.read::<u32>().unwrap(), 1);
+    assert_eq!(parcel.read::<u32>().unwrap(), 0);
+    assert_eq!(parcel.read::<u32>().unwrap(), 0);
+    assert_eq!(parcel.read::<u32>().unwrap(), 1);
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<bool>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [true, false, false, true]);
+
+    let u8s = [101u8, 255, 42, 117];
+
+    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let start = parcel.get_data_position();
+
+    assert!(parcel.write(&u8s[..]).is_ok());
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
+    assert_eq!(vec, [101, 255, 42, 117]);
+
+    let i8s = [-128i8, 127, 42, -117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert!(parcel.write(&i8s[..]).is_ok());
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
+    assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
+
+    let u16s = [u16::max_value(), 12_345, 42, 117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(u16s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+    assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<u16>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+
+    let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(i16s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+    assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<i16>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+
+    let u32s = [u32::max_value(), 12_345, 42, 117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(u32s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
+    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+    assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<u32>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+
+    let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(i32s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+    assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
+    assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<i32>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+
+    let u64s = [u64::max_value(), 12_345, 42, 117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(u64s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<u64>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+
+    let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(i64s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<i64>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+
+    let f32s = [
+        std::f32::NAN,
+        std::f32::INFINITY,
+        1.23456789,
+        std::f32::EPSILON,
+    ];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(f32s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<f32>::deserialize(&parcel).unwrap();
+
+    // NAN != NAN so we can't use it in the assert_eq:
+    assert!(vec[0].is_nan());
+    assert_eq!(vec[1..], f32s[1..]);
+
+    let f64s = [
+        std::f64::NAN,
+        std::f64::INFINITY,
+        1.234567890123456789,
+        std::f64::EPSILON,
+    ];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(f64s.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<f64>::deserialize(&parcel).unwrap();
+
+    // NAN != NAN so we can't use it in the assert_eq:
+    assert!(vec[0].is_nan());
+    assert_eq!(vec[1..], f64s[1..]);
+
+    let s1 = "Hello, Binder!";
+    let s2 = "This is a utf8 string.";
+    let s3 = "Some more text here.";
+    let s4 = "Embedded nulls \0 \0";
+
+    let strs = [s1, s2, s3, s4];
+
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+    assert!(strs.serialize(&mut parcel).is_ok());
+    unsafe {
+        assert!(parcel.set_data_position(start).is_ok());
+    }
+
+    let vec = Vec::<String>::deserialize(&parcel).unwrap();
+
+    assert_eq!(vec, strs);
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
new file mode 100644
index 0000000..e9e74c0
--- /dev/null
+++ b/libs/binder/rust/src/proxy.rs
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Rust API for interacting with a remote binder service.
+
+use crate::binder::{
+    AsNative, FromIBinder, IBinder, Interface, InterfaceClass, TransactionCode, TransactionFlags,
+};
+use crate::error::{status_result, Result, StatusCode};
+use crate::parcel::{
+    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+    SerializeOption,
+};
+use crate::sys;
+
+use std::convert::TryInto;
+use std::ffi::{c_void, CString};
+use std::fmt;
+use std::os::unix::io::AsRawFd;
+use std::ptr;
+
+/// A strong reference to a Binder remote object.
+///
+/// This struct encapsulates the generic C++ `sp<IBinder>` class. This wrapper
+/// is untyped; typed interface access is implemented by the AIDL compiler.
+pub struct SpIBinder(*mut sys::AIBinder);
+
+impl fmt::Debug for SpIBinder {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("SpIBinder")
+    }
+}
+
+/// # Safety
+///
+/// An `SpIBinder` is a handle to a C++ IBinder, which is thread-safe
+unsafe impl Send for SpIBinder {}
+
+impl SpIBinder {
+    /// Create an `SpIBinder` wrapper object from a raw `AIBinder` pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe iff `ptr` is a null pointer or a valid pointer
+    /// to an `AIBinder`.
+    ///
+    /// In the non-null case, this method conceptually takes ownership of a strong
+    /// reference to the object, so `AIBinder_incStrong` must have been called
+    /// on the pointer before passing it to this constructor. This is generally
+    /// done by Binder NDK methods that return an `AIBinder`, but care should be
+    /// taken to ensure this invariant.
+    ///
+    /// All `SpIBinder` objects that are constructed will hold a valid pointer
+    /// to an `AIBinder`, which will remain valid for the entire lifetime of the
+    /// `SpIBinder` (we keep a strong reference, and only decrement on drop).
+    pub(crate) unsafe fn from_raw(ptr: *mut sys::AIBinder) -> Option<Self> {
+        ptr.as_mut().map(|p| Self(p))
+    }
+
+    /// Extract a raw `AIBinder` pointer from this wrapper.
+    ///
+    /// This method should _only_ be used for testing. Do not try to use the NDK
+    /// interface directly for anything else.
+    ///
+    /// # Safety
+    ///
+    /// The resulting pointer is valid only as long as the SpIBinder is alive.
+    /// The SpIBinder object retains ownership of the AIBinder and the caller
+    /// should not attempt to free the returned pointer.
+    pub unsafe fn as_raw(&self) -> *mut sys::AIBinder {
+        self.0
+    }
+
+    /// Return true if this binder object is hosted in a different process than
+    /// the current one.
+    pub fn is_remote(&self) -> bool {
+        unsafe {
+            // Safety: `SpIBinder` guarantees that it always contains a valid
+            // `AIBinder` pointer.
+            sys::AIBinder_isRemote(self.as_native())
+        }
+    }
+
+    /// Try to convert this Binder object into a trait object for the given
+    /// Binder interface.
+    ///
+    /// If this object does not implement the expected interface, the error
+    /// `StatusCode::BAD_TYPE` is returned.
+    pub fn into_interface<I: FromIBinder + ?Sized>(self) -> Result<Box<I>> {
+        FromIBinder::try_from(self)
+    }
+
+    /// Return the interface class of this binder object, if associated with
+    /// one.
+    pub fn get_class(&mut self) -> Option<InterfaceClass> {
+        unsafe {
+            // Safety: `SpIBinder` guarantees that it always contains a valid
+            // `AIBinder` pointer. `AIBinder_getClass` returns either a null
+            // pointer or a valid pointer to an `AIBinder_Class`. After mapping
+            // null to None, we can safely construct an `InterfaceClass` if the
+            // pointer was non-null.
+            let class = sys::AIBinder_getClass(self.as_native_mut());
+            class.as_ref().map(|p| InterfaceClass::from_ptr(p))
+        }
+    }
+
+    /// Creates a new weak reference to this binder object.
+    pub fn downgrade(&mut self) -> WpIBinder {
+        WpIBinder::new(self)
+    }
+}
+
+/// An object that can be associate with an [`InterfaceClass`].
+pub trait AssociateClass {
+    /// Check if this object is a valid object for the given interface class
+    /// `I`.
+    ///
+    /// Returns `Some(self)` if this is a valid instance of the interface, and
+    /// `None` otherwise.
+    ///
+    /// Classes constructed by `InterfaceClass` are unique per type, so
+    /// repeatedly calling this method for the same `InterfaceClass` is allowed.
+    fn associate_class(&mut self, class: InterfaceClass) -> bool;
+}
+
+impl AssociateClass for SpIBinder {
+    fn associate_class(&mut self, class: InterfaceClass) -> bool {
+        unsafe {
+            // Safety: `SpIBinder` guarantees that it always contains a valid
+            // `AIBinder` pointer. An `InterfaceClass` can always be converted
+            // into a valid `AIBinder_Class` pointer, so these parameters are
+            // always safe.
+            sys::AIBinder_associateClass(self.as_native_mut(), class.into())
+        }
+    }
+}
+
+impl PartialEq for SpIBinder {
+    fn eq(&self, other: &Self) -> bool {
+        ptr::eq(self.0, other.0)
+    }
+}
+
+impl Eq for SpIBinder {}
+
+impl Clone for SpIBinder {
+    fn clone(&self) -> Self {
+        unsafe {
+            // Safety: Cloning a strong reference must increment the reference
+            // count. We are guaranteed by the `SpIBinder` constructor
+            // invariants that `self.0` is always a valid `AIBinder` pointer.
+            sys::AIBinder_incStrong(self.0);
+        }
+        Self(self.0)
+    }
+}
+
+impl Drop for SpIBinder {
+    // We hold a strong reference to the IBinder in SpIBinder and need to give up
+    // this reference on drop.
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
+            // know this pointer is safe to pass to `AIBinder_decStrong` here.
+            sys::AIBinder_decStrong(self.as_native_mut());
+        }
+    }
+}
+
+impl<T: AsNative<sys::AIBinder>> IBinder for T {
+    /// Perform a binder transaction
+    fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+        &self,
+        code: TransactionCode,
+        flags: TransactionFlags,
+        input_callback: F,
+    ) -> Result<Parcel> {
+        let mut input = ptr::null_mut();
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. It is safe to cast from an
+            // immutable pointer to a mutable pointer here, because
+            // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
+            // methods but the parameter is unfortunately not marked as const.
+            //
+            // After the call, input will be either a valid, owned `AParcel`
+            // pointer, or null.
+            sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
+        };
+        status_result(status)?;
+        let mut input = unsafe {
+            // Safety: At this point, `input` is either a valid, owned `AParcel`
+            // pointer, or null. `Parcel::owned` safely handles both cases,
+            // taking ownership of the parcel.
+            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)?
+        };
+        input_callback(&mut input)?;
+        let mut reply = ptr::null_mut();
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. Although `IBinder::transact` is
+            // not a const method, it is still safe to cast our immutable
+            // pointer to mutable for the call. First, `IBinder::transact` is
+            // thread-safe, so concurrency is not an issue. The only way that
+            // `transact` can affect any visible, mutable state in the current
+            // process is by calling `onTransact` for a local service. However,
+            // in order for transactions to be thread-safe, this method must
+            // dynamically lock its data before modifying it. We enforce this
+            // property in Rust by requiring `Sync` for remotable objects and
+            // only providing `on_transact` with an immutable reference to
+            // `self`.
+            //
+            // This call takes ownership of the `input` parcel pointer, and
+            // passes ownership of the `reply` out parameter to its caller. It
+            // does not affect ownership of the `binder` parameter.
+            sys::AIBinder_transact(
+                self.as_native() as *mut sys::AIBinder,
+                code,
+                &mut input.into_raw(),
+                &mut reply,
+                flags,
+            )
+        };
+        status_result(status)?;
+
+        unsafe {
+            // Safety: `reply` is either a valid `AParcel` pointer or null
+            // after the call to `AIBinder_transact` above, so we can
+            // construct a `Parcel` out of it. `AIBinder_transact` passes
+            // ownership of the `reply` parcel to Rust, so we need to
+            // construct an owned variant. `Parcel::owned` takes ownership
+            // of the parcel pointer.
+            Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+        }
+    }
+
+    fn is_binder_alive(&self) -> bool {
+        unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`.
+            //
+            // This call does not affect ownership of its pointer parameter.
+            sys::AIBinder_isAlive(self.as_native())
+        }
+    }
+
+    fn ping_binder(&mut self) -> Result<()> {
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`.
+            //
+            // This call does not affect ownership of its pointer parameter.
+            sys::AIBinder_ping(self.as_native_mut())
+        };
+        status_result(status)
+    }
+
+    fn set_requesting_sid(&mut self, enable: bool) {
+        unsafe {
+            sys::AIBinder_setRequestingSid(self.as_native_mut(), enable)
+        };
+    }
+
+    fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
+        let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
+        let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
+            // file descriptor parameter is always be a valid open file. The
+            // `args` pointer parameter is a valid pointer to an array of C
+            // strings that will outlive the call since `args` lives for the
+            // whole function scope.
+            //
+            // This call does not affect ownership of its binder pointer
+            // parameter and does not take ownership of the file or args array
+            // parameters.
+            sys::AIBinder_dump(
+                self.as_native_mut(),
+                fp.as_raw_fd(),
+                arg_ptrs.as_mut_ptr(),
+                arg_ptrs.len().try_into().unwrap(),
+            )
+        };
+        status_result(status)
+    }
+
+    fn get_extension(&mut self) -> Result<Option<SpIBinder>> {
+        let mut out = ptr::null_mut();
+        let status = unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. After this call, the `out`
+            // parameter will be either null, or a valid pointer to an
+            // `AIBinder`.
+            //
+            // This call passes ownership of the out pointer to its caller
+            // (assuming it is set to a non-null value).
+            sys::AIBinder_getExtension(self.as_native_mut(), &mut out)
+        };
+        let ibinder = unsafe {
+            // Safety: The call above guarantees that `out` is either null or a
+            // valid, owned pointer to an `AIBinder`, both of which are safe to
+            // pass to `SpIBinder::from_raw`.
+            SpIBinder::from_raw(out)
+        };
+
+        status_result(status)?;
+        Ok(ibinder)
+    }
+
+    fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        status_result(unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. `recipient` can always be
+            // converted into a valid pointer to an
+            // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+            // cookie, although we depend on this value being set by
+            // `get_cookie` when the death recipient callback is called.
+            sys::AIBinder_linkToDeath(
+                self.as_native_mut(),
+                recipient.as_native_mut(),
+                recipient.get_cookie(),
+            )
+        })
+    }
+
+    fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        status_result(unsafe {
+            // Safety: `SpIBinder` guarantees that `self` always contains a
+            // valid pointer to an `AIBinder`. `recipient` can always be
+            // converted into a valid pointer to an
+            // `AIBinder_DeatRecipient`. Any value is safe to pass as the
+            // cookie, although we depend on this value being set by
+            // `get_cookie` when the death recipient callback is called.
+            sys::AIBinder_unlinkToDeath(
+                self.as_native_mut(),
+                recipient.as_native_mut(),
+                recipient.get_cookie(),
+            )
+        })
+    }
+}
+
+impl Serialize for SpIBinder {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        parcel.write_binder(Some(self))
+    }
+}
+
+impl SerializeOption for SpIBinder {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        parcel.write_binder(this)
+    }
+}
+
+impl SerializeArray for SpIBinder {}
+impl SerializeArray for Option<&SpIBinder> {}
+
+impl Deserialize for SpIBinder {
+    fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+        parcel
+            .read_binder()
+            .transpose()
+            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+    }
+}
+
+impl DeserializeOption for SpIBinder {
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+        parcel.read_binder()
+    }
+}
+
+impl DeserializeArray for SpIBinder {}
+impl DeserializeArray for Option<SpIBinder> {}
+
+/// A weak reference to a Binder remote object.
+///
+/// This struct encapsulates the generic C++ `wp<IBinder>` class. This wrapper
+/// is untyped; typed interface access is implemented by the AIDL compiler.
+pub struct WpIBinder(*mut sys::AIBinder_Weak);
+
+impl fmt::Debug for WpIBinder {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.pad("WpIBinder")
+    }
+}
+
+/// # Safety
+///
+/// A `WpIBinder` is a handle to a C++ IBinder, which is thread-safe.
+unsafe impl Send for WpIBinder {}
+
+impl WpIBinder {
+    /// Create a new weak reference from an object that can be converted into a
+    /// raw `AIBinder` pointer.
+    fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
+        let ptr = unsafe {
+            // Safety: `SpIBinder` guarantees that `binder` always contains a
+            // valid pointer to an `AIBinder`.
+            sys::AIBinder_Weak_new(binder.as_native_mut())
+        };
+        assert!(!ptr.is_null());
+        Self(ptr)
+    }
+
+    /// Promote this weak reference to a strong reference to the binder object.
+    pub fn promote(&self) -> Option<SpIBinder> {
+        unsafe {
+            // Safety: `WpIBinder` always contains a valid weak reference, so we
+            // can pass this pointer to `AIBinder_Weak_promote`. Returns either
+            // null or an AIBinder owned by the caller, both of which are valid
+            // to pass to `SpIBinder::from_raw`.
+            let ptr = sys::AIBinder_Weak_promote(self.0);
+            SpIBinder::from_raw(ptr)
+        }
+    }
+}
+
+impl Drop for WpIBinder {
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+            // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
+            sys::AIBinder_Weak_delete(self.0);
+        }
+    }
+}
+
+/// Rust wrapper around DeathRecipient objects.
+#[repr(C)]
+pub struct DeathRecipient {
+    recipient: *mut sys::AIBinder_DeathRecipient,
+    callback: Box<dyn Fn() + Send + 'static>,
+}
+
+impl DeathRecipient {
+    /// Create a new death recipient that will call the given callback when its
+    /// associated object dies.
+    pub fn new<F>(callback: F) -> DeathRecipient
+    where
+        F: Fn() + Send + 'static,
+    {
+        let callback = Box::new(callback);
+        let recipient = unsafe {
+            // Safety: The function pointer is a valid death recipient callback.
+            //
+            // This call returns an owned `AIBinder_DeathRecipient` pointer
+            // which must be destroyed via `AIBinder_DeathRecipient_delete` when
+            // no longer needed.
+            sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
+        };
+        DeathRecipient {
+            recipient,
+            callback,
+        }
+    }
+
+    /// Get the opaque cookie that identifies this death recipient.
+    ///
+    /// This cookie will be used to link and unlink this death recipient to a
+    /// binder object and will be passed to the `binder_died` callback as an
+    /// opaque userdata pointer.
+    fn get_cookie(&self) -> *mut c_void {
+        &*self.callback as *const _ as *mut c_void
+    }
+
+    /// Callback invoked from C++ when the binder object dies.
+    ///
+    /// # Safety
+    ///
+    /// The `cookie` parameter must have been created with the `get_cookie`
+    /// method of this object.
+    unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
+    where
+        F: Fn() + Send + 'static,
+    {
+        let callback = (cookie as *mut F).as_ref().unwrap();
+        callback();
+    }
+}
+
+/// # Safety
+///
+/// A `DeathRecipient` is always constructed with a valid raw pointer to an
+/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this
+/// pointer.
+unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
+    fn as_native(&self) -> *const sys::AIBinder_DeathRecipient {
+        self.recipient
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AIBinder_DeathRecipient {
+        self.recipient
+    }
+}
+
+impl Drop for DeathRecipient {
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: `self.recipient` is always a valid, owned
+            // `AIBinder_DeathRecipient` pointer returned by
+            // `AIBinder_DeathRecipient_new` when `self` was created. This
+            // delete method can only be called once when `self` is dropped.
+            sys::AIBinder_DeathRecipient_delete(self.recipient);
+        }
+    }
+}
+
+/// Generic interface to remote binder objects.
+///
+/// Corresponds to the C++ `BpInterface` class.
+pub trait Proxy: Sized + Interface {
+    /// The Binder interface descriptor string.
+    ///
+    /// This string is a unique identifier for a Binder interface, and should be
+    /// the same between all implementations of that interface.
+    fn get_descriptor() -> &'static str;
+
+    /// Create a new interface from the given proxy, if it matches the expected
+    /// type of this interface.
+    fn from_binder(binder: SpIBinder) -> Result<Self>;
+}
+
+/// # Safety
+///
+/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow
+/// invocation of `IBinder` methods directly from `Interface` objects. It shares
+/// the same safety as the implementation for `SpIBinder`.
+unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
+    fn as_native(&self) -> *const sys::AIBinder {
+        self.as_binder().as_native()
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AIBinder {
+        self.as_binder().as_native_mut()
+    }
+}
+
+/// Retrieve an existing service, blocking for a few seconds if it doesn't yet
+/// exist.
+pub fn get_service(name: &str) -> Option<SpIBinder> {
+    let name = CString::new(name).ok()?;
+    unsafe {
+        // Safety: `AServiceManager_getService` returns either a null pointer or
+        // a valid pointer to an owned `AIBinder`. Either of these values is
+        // safe to pass to `SpIBinder::from_raw`.
+        SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr()))
+    }
+}
+
+/// Retrieve an existing service for a particular interface, blocking for a few
+/// seconds if it doesn't yet exist.
+pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Box<T>> {
+    let service = get_service(name);
+    match service {
+        Some(service) => FromIBinder::try_from(service),
+        None => Err(StatusCode::NAME_NOT_FOUND),
+    }
+}
+
+/// # Safety
+///
+/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
+/// `AIBinder`, so we can trivially extract this pointer here.
+unsafe impl AsNative<sys::AIBinder> for SpIBinder {
+    fn as_native(&self) -> *const sys::AIBinder {
+        self.0
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AIBinder {
+        self.0
+    }
+}
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
new file mode 100644
index 0000000..0e05f10
--- /dev/null
+++ b/libs/binder/rust/src/state.rs
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use crate::sys;
+
+use libc::{pid_t, uid_t};
+
+/// Static utility functions to manage Binder process state.
+pub struct ProcessState;
+
+impl ProcessState {
+    /// Start the Binder IPC thread pool
+    pub fn start_thread_pool() {
+        unsafe {
+            // Safety: Safe FFI
+            sys::ABinderProcess_startThreadPool();
+        }
+    }
+
+    /// Set the maximum number of threads that can be started in the threadpool.
+    ///
+    /// By default, after startThreadPool is called, this is 15. If it is called
+    /// additional times, it will only prevent the kernel from starting new
+    /// threads and will not delete already existing threads.
+    pub fn set_thread_pool_max_thread_count(num_threads: u32) {
+        unsafe {
+            // Safety: Safe FFI
+            sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads);
+        }
+    }
+
+    /// Block on the Binder IPC thread pool
+    pub fn join_thread_pool() {
+        unsafe {
+            // Safety: Safe FFI
+            sys::ABinderProcess_joinThreadPool();
+        }
+    }
+}
+
+/// Static utility functions to manage Binder thread state.
+pub struct ThreadState;
+
+impl ThreadState {
+    /// This returns the calling UID assuming that this thread is called from a
+    /// thread that is processing a binder transaction (for instance, in the
+    /// implementation of
+    /// [`Remotable::on_transact`](crate::Remotable::on_transact)).
+    ///
+    /// This can be used with higher-level system services to determine the
+    /// caller's identity and check permissions.
+    ///
+    /// Available since API level 29.
+    ///
+    /// \return calling uid or the current process's UID if this thread isn't
+    /// processing a transaction.
+    pub fn get_calling_uid() -> uid_t {
+        unsafe {
+            // Safety: Safe FFI
+            sys::AIBinder_getCallingUid()
+        }
+    }
+
+    /// This returns the calling PID assuming that this thread is called from a
+    /// thread that is processing a binder transaction (for instance, in the
+    /// implementation of
+    /// [`Remotable::on_transact`](crate::Remotable::on_transact)).
+    ///
+    /// This can be used with higher-level system services to determine the
+    /// caller's identity and check permissions. However, when doing this, one
+    /// should be aware of possible TOCTOU problems when the calling process
+    /// dies and is replaced with another process with elevated permissions and
+    /// the same PID.
+    ///
+    /// Available since API level 29.
+    ///
+    /// \return calling pid or the current process's PID if this thread isn't
+    /// processing a transaction.
+    ///
+    /// If the transaction being processed is a oneway transaction, then this
+    /// method will return 0.
+    pub fn get_calling_pid() -> pid_t {
+        unsafe {
+            // Safety: Safe FFI
+            sys::AIBinder_getCallingPid()
+        }
+    }
+
+    /// This function makes the client's security context available to the
+    /// service calling this function. This can be used for access control.
+    /// It does not suffer from the TOCTOU issues of get_calling_pid.
+    ///
+    /// Implementations of `check_permission` should use the given CStr
+    /// argument as context for selinux permission checks. If `None` is
+    /// given, the implementation should fall back to using the PID
+    /// instead.
+    ///
+    /// Note: `None` may be passed to the callback if the caller did not
+    /// `set_requesting_sid` on the serviced binder, or if the underlying
+    /// kernel is too old to support this feature.
+    pub fn with_calling_sid<T, F>(check_permission: F) -> T
+    where
+        for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+        // Safety: AIBinder_getCallingSid returns a c-string pointer
+        // that is valid for a transaction. Also, the string returned
+        // is thread local. By restricting the lifetime of the CStr
+        // reference to the scope of the callback, we prevent it being
+        // used beyond the guaranteed lifetime.
+        check_permission(unsafe {
+            let sid = sys::AIBinder_getCallingSid();
+            // AIBinder_getCallingSid() returns a '\0' terminated string
+            // or NULL.
+            if sid.is_null() {
+                None
+            } else {
+                Some(std::ffi::CStr::from_ptr(sid))
+            }
+        })
+    }
+}
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
new file mode 100644
index 0000000..ef142b5
--- /dev/null
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_ibinder.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_platform.h>
+#include <android/binder_process.h>
+#include <android/binder_shell.h>
+#include <android/binder_status.h>
+
+namespace android {
+
+namespace c_interface {
+
+// Expose error codes from anonymous enum in binder_status.h
+enum StatusCode {
+    OK = STATUS_OK,
+    UNKNOWN_ERROR = STATUS_UNKNOWN_ERROR,
+    NO_MEMORY = STATUS_NO_MEMORY,
+    INVALID_OPERATION = STATUS_INVALID_OPERATION,
+    BAD_VALUE = STATUS_BAD_VALUE,
+    BAD_TYPE = STATUS_BAD_TYPE,
+    NAME_NOT_FOUND = STATUS_NAME_NOT_FOUND,
+    PERMISSION_DENIED = STATUS_PERMISSION_DENIED,
+    NO_INIT = STATUS_NO_INIT,
+    ALREADY_EXISTS = STATUS_ALREADY_EXISTS,
+    DEAD_OBJECT = STATUS_DEAD_OBJECT,
+    FAILED_TRANSACTION = STATUS_FAILED_TRANSACTION,
+    BAD_INDEX = STATUS_BAD_INDEX,
+    NOT_ENOUGH_DATA = STATUS_NOT_ENOUGH_DATA,
+    WOULD_BLOCK = STATUS_WOULD_BLOCK,
+    TIMED_OUT = STATUS_TIMED_OUT,
+    UNKNOWN_TRANSACTION = STATUS_UNKNOWN_TRANSACTION,
+    FDS_NOT_ALLOWED = STATUS_FDS_NOT_ALLOWED,
+    UNEXPECTED_NULL = STATUS_UNEXPECTED_NULL,
+};
+
+// Expose exception codes from anonymous enum in binder_status.h
+enum ExceptionCode {
+    NONE = EX_NONE,
+    SECURITY = EX_SECURITY,
+    BAD_PARCELABLE = EX_BAD_PARCELABLE,
+    ILLEGAL_ARGUMENT = EX_ILLEGAL_ARGUMENT,
+    NULL_POINTER = EX_NULL_POINTER,
+    ILLEGAL_STATE = EX_ILLEGAL_STATE,
+    NETWORK_MAIN_THREAD = EX_NETWORK_MAIN_THREAD,
+    UNSUPPORTED_OPERATION = EX_UNSUPPORTED_OPERATION,
+    SERVICE_SPECIFIC = EX_SERVICE_SPECIFIC,
+    PARCELABLE = EX_PARCELABLE,
+
+    /**
+     * This is special, and indicates to native binder proxies that the
+     * transaction has failed at a low level.
+     */
+    TRANSACTION_FAILED = EX_TRANSACTION_FAILED,
+};
+
+namespace consts {
+
+enum {
+    FIRST_CALL_TRANSACTION = FIRST_CALL_TRANSACTION,
+    LAST_CALL_TRANSACTION = LAST_CALL_TRANSACTION,
+};
+
+enum {
+    FLAG_ONEWAY = FLAG_ONEWAY,
+    FLAG_CLEAR_BUF = FLAG_CLEAR_BUF,
+};
+
+} // namespace consts
+
+} // namespace c_interface
+
+} // namespace android
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
new file mode 100644
index 0000000..9095af2
--- /dev/null
+++ b/libs/binder/rust/sys/lib.rs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Generated Rust bindings to libbinder_ndk
+
+#![allow(
+    non_camel_case_types,
+    non_snake_case,
+    non_upper_case_globals,
+    unused,
+    improper_ctypes,
+    missing_docs
+)]
+use std::error::Error;
+use std::fmt;
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+
+impl Error for android_c_interface_StatusCode {}
+
+impl fmt::Display for android_c_interface_StatusCode {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "StatusCode::{:?}", self)
+    }
+}
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
new file mode 100644
index 0000000..8810b5d
--- /dev/null
+++ b/libs/binder/rust/tests/Android.bp
@@ -0,0 +1,128 @@
+rust_test {
+    name: "rustBinderTest",
+    srcs: ["integration.rs"],
+    rustlibs: [
+        "libbinder_rs",
+        "libselinux_bindgen",
+    ],
+    shared_libs: [
+        "libselinux",
+    ],
+    // For the binaries to be pushed properly as specified in AndroidTest.xml,
+    // this cannot be the same as the module name.
+    stem: "rustBinderTestClientBinary",
+    test_suites: ["general-tests"],
+}
+
+rust_test {
+    name: "rustBinderTestService",
+    srcs: ["integration.rs"],
+    rustlibs: [
+        "libbinder_rs",
+        "liblibc",
+    ],
+    // For the binaries to be pushed properly as specified in AndroidTest.xml,
+    // this cannot be the same as the module name.
+    stem: "rustBinderTestServiceBinary",
+    test_harness: false,
+    // TODO(b/164473602): Remove this setting and add the module to `data`
+    // attribute of rustBinderTest.
+    auto_gen_config: false,
+    test_suites: ["general-tests"],
+}
+
+cc_test {
+    name: "binderRustNdkInteropTest",
+    srcs: [
+        "binderRustNdkInteropTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "IBinderRustNdkInteropTest-ndk_platform",
+        "libbinder_ndk_rust_interop",
+    ],
+    test_suites: ["general-tests"],
+    require_root: true,
+
+    // rustBinderTestService uses a custom config
+    auto_gen_config: true,
+}
+
+aidl_interface {
+    name: "IBinderRustNdkInteropTest",
+    unstable: true,
+    srcs: [
+        "IBinderRustNdkInteropTest.aidl",
+        "IBinderRustNdkInteropTestOther.aidl",
+    ],
+    backend: {
+        ndk: {
+            enabled: true,
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+rust_ffi_static {
+    name: "libbinder_ndk_rust_interop",
+    crate_name: "binder_ndk_rust_interop",
+    srcs: [
+        "ndk_rust_interop.rs",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+        "IBinderRustNdkInteropTest-rust",
+    ],
+}
+
+cc_test {
+    name: "rustBinderSerializationTest",
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+        "libbase",
+    ],
+    static_libs: [
+        "libbinder_rs_serialization_test"
+    ],
+    srcs: [
+        "serialization.cpp",
+    ],
+    auto_gen_config: true,
+    test_suites: ["general-tests"],
+}
+
+rust_bindgen {
+    name: "libbinder_rs_serialization_bindgen",
+    crate_name: "binder_rs_serialization_bindgen",
+    wrapper_src: "serialization.hpp",
+    source_stem: "bindings",
+    cpp_std: "gnu++17",
+    bindgen_flags: [
+        "--whitelist-type", "Transaction",
+        "--whitelist-var", "TESTDATA_.*",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libc++",
+    ],
+}
+
+rust_ffi_static {
+    name: "libbinder_rs_serialization_test",
+    crate_name: "binder_rs_serialization_test",
+    srcs: [
+        "serialization.rs",
+        ":libbinder_rs_serialization_bindgen",
+    ],
+    rustlibs: [
+        "libbinder_rs",
+    ],
+}
diff --git a/libs/binder/ndk/test/AndroidTest.xml b/libs/binder/rust/tests/AndroidTest.xml
similarity index 61%
copy from libs/binder/ndk/test/AndroidTest.xml
copy to libs/binder/rust/tests/AndroidTest.xml
index 89646f7..d8d735d 100644
--- a/libs/binder/ndk/test/AndroidTest.xml
+++ b/libs/binder/rust/tests/AndroidTest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2019 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,20 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs binderVendorDoubleLoadTest.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-
+<configuration description="Runs Binder Rust integration tests.">
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
-        <option name="push" value="binderVendorDoubleLoadTest->/data/nativetest/vendor/binderVendorDoubleLoadTest" />
+        <option name="push" value="rustBinderTestClientBinary->/data/local/tmp/rustBinderTest" />
+        <option name="push" value="rustBinderTestServiceBinary->/data/local/tmp/rustBinderTestService" />
     </target_preparer>
 
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/nativetest/vendor" />
-        <option name="module-name" value="binderVendorDoubleLoadTest" />
+    <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+        <option name="test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="rustBinderTest" />
     </test>
 </configuration>
-
diff --git a/libs/binder/fuzzer/parcel_fuzzer.h b/libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl
similarity index 78%
copy from libs/binder/fuzzer/parcel_fuzzer.h
copy to libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl
index 10cf17c..7f5e837 100644
--- a/libs/binder/fuzzer/parcel_fuzzer.h
+++ b/libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,5 +14,6 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+interface IBinderRustNdkInteropTest {
+    @utf8InCpp String echo(@utf8InCpp String str);
+}
diff --git a/libs/binder/fuzzer/parcel_fuzzer.h b/libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl
similarity index 78%
copy from libs/binder/fuzzer/parcel_fuzzer.h
copy to libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl
index 10cf17c..82a0323 100644
--- a/libs/binder/fuzzer/parcel_fuzzer.h
+++ b/libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,5 +14,6 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+interface IBinderRustNdkInteropTestOther {
+    @utf8InCpp String echo(@utf8InCpp String str);
+}
diff --git a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
new file mode 100644
index 0000000..59ca6ed
--- /dev/null
+++ b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/BnBinderRustNdkInteropTest.h>
+#include <aidl/IBinderRustNdkInteropTest.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+using namespace android;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
+
+static const char* kNdkServerName = "NdkServer-BinderRustNdkInteropTest";
+static const char* kRustServerName = "RustServer-BinderRustNdkInteropTest";
+
+extern "C" {
+int rust_call_ndk(const char* service_name);
+int rust_start_service(const char* service_name);
+}
+
+class NdkServer : public aidl::BnBinderRustNdkInteropTest {
+    ScopedAStatus echo(const std::string& in, std::string* out) override {
+        *out = in;
+        return ScopedAStatus::ok();
+    }
+};
+
+TEST(RustNdkInterop, RustCanCallNdk) {
+    ASSERT_EQ(STATUS_OK, rust_call_ndk(kNdkServerName));
+}
+
+TEST(RustNdkInterop, NdkCanCallRust) {
+    ASSERT_EQ(STATUS_OK, rust_start_service(kRustServerName));
+
+    SpAIBinder binder = SpAIBinder(AServiceManager_checkService(kRustServerName));
+    ASSERT_NE(nullptr, binder.get());
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+
+    auto interface = aidl::IBinderRustNdkInteropTest::fromBinder(binder);
+    // TODO(b/167723746): this test requires that fromBinder allow association
+    // with an already associated local binder by treating it as remote.
+    EXPECT_EQ(interface, nullptr);
+
+    // std::string in("testing");
+    // std::string out;
+    // EXPECT_TRUE(interface->echo(in, &out).isOk());
+    // EXPECT_EQ(in, out);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // so we can host a client and service concurrently
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
+    std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+    EXPECT_EQ(STATUS_OK, AServiceManager_addService(ndkServer->asBinder().get(), kNdkServerName));
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
new file mode 100644
index 0000000..bb8c492
--- /dev/null
+++ b/libs/binder/rust/tests/integration.rs
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Rust Binder crate integration tests
+
+use binder::declare_binder_interface;
+use binder::parcel::Parcel;
+use binder::{Binder, IBinder, Interface, SpIBinder, StatusCode, ThreadState, TransactionCode};
+use std::convert::{TryFrom, TryInto};
+
+/// Name of service runner.
+///
+/// Must match the binary name in Android.bp
+const RUST_SERVICE_BINARY: &str = "rustBinderTestService";
+
+/// Binary to run a test service.
+///
+/// This needs to be in a separate process from the tests, so we spawn this
+/// binary as a child, providing the service name as an argument.
+fn main() -> Result<(), &'static str> {
+    // Ensure that we can handle all transactions on the main thread.
+    binder::ProcessState::set_thread_pool_max_thread_count(0);
+    binder::ProcessState::start_thread_pool();
+
+    let mut args = std::env::args().skip(1);
+    if args.len() < 1 || args.len() > 2 {
+        print_usage();
+        return Err("");
+    }
+    let service_name = args.next().ok_or_else(|| {
+        print_usage();
+        "Missing SERVICE_NAME argument"
+    })?;
+    let extension_name = args.next();
+
+    {
+        let mut service = Binder::new(BnTest(Box::new(TestService {
+            s: service_name.clone(),
+        })));
+        service.set_requesting_sid(true);
+        if let Some(extension_name) = extension_name {
+            let extension = BnTest::new_binder(TestService { s: extension_name });
+            service
+                .set_extension(&mut extension.as_binder())
+                .expect("Could not add extension");
+        }
+        binder::add_service(&service_name, service.as_binder())
+            .expect("Could not register service");
+    }
+
+    binder::ProcessState::join_thread_pool();
+    Err("Unexpected exit after join_thread_pool")
+}
+
+fn print_usage() {
+    eprintln!(
+        "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
+        RUST_SERVICE_BINARY
+    );
+    eprintln!(concat!(
+        "Spawn a Binder test service identified by SERVICE_NAME,",
+        " optionally with an extesion named EXTENSION_NAME",
+    ));
+}
+
+#[derive(Clone)]
+struct TestService {
+    s: String,
+}
+
+#[repr(u32)]
+enum TestTransactionCode {
+    Test = SpIBinder::FIRST_CALL_TRANSACTION,
+    GetSelinuxContext,
+}
+
+impl TryFrom<u32> for TestTransactionCode {
+    type Error = StatusCode;
+
+    fn try_from(c: u32) -> Result<Self, Self::Error> {
+        match c {
+            _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
+            _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
+                Ok(TestTransactionCode::GetSelinuxContext)
+            }
+            _ => Err(StatusCode::UNKNOWN_TRANSACTION),
+        }
+    }
+}
+
+impl Interface for TestService {}
+
+impl ITest for TestService {
+    fn test(&self) -> binder::Result<String> {
+        Ok(self.s.clone())
+    }
+
+    fn get_selinux_context(&self) -> binder::Result<String> {
+        let sid =
+            ThreadState::with_calling_sid(|sid| sid.map(|s| s.to_string_lossy().into_owned()));
+        sid.ok_or(StatusCode::UNEXPECTED_NULL)
+    }
+}
+
+/// Trivial testing binder interface
+pub trait ITest: Interface {
+    /// Returns a test string
+    fn test(&self) -> binder::Result<String>;
+
+    /// Returns the caller's SELinux context
+    fn get_selinux_context(&self) -> binder::Result<String>;
+}
+
+declare_binder_interface! {
+    ITest["android.os.ITest"] {
+        native: BnTest(on_transact),
+        proxy: BpTest {
+            x: i32 = 100
+        },
+    }
+}
+
+fn on_transact(
+    service: &dyn ITest,
+    code: TransactionCode,
+    _data: &Parcel,
+    reply: &mut Parcel,
+) -> binder::Result<()> {
+    match code.try_into()? {
+        TestTransactionCode::Test => reply.write(&service.test()?),
+        TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
+    }
+}
+
+impl ITest for BpTest {
+    fn test(&self) -> binder::Result<String> {
+        let reply =
+            self.binder
+                .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+        reply.read()
+    }
+
+    fn get_selinux_context(&self) -> binder::Result<String> {
+        let reply = self.binder.transact(
+            TestTransactionCode::GetSelinuxContext as TransactionCode,
+            0,
+            |_| Ok(()),
+        )?;
+        reply.read()
+    }
+}
+
+impl ITest for Binder<BnTest> {
+    fn test(&self) -> binder::Result<String> {
+        self.0.test()
+    }
+
+    fn get_selinux_context(&self) -> binder::Result<String> {
+        self.0.get_selinux_context()
+    }
+}
+
+/// Trivial testing binder interface
+pub trait ITestSameDescriptor: Interface {}
+
+declare_binder_interface! {
+    ITestSameDescriptor["android.os.ITest"] {
+        native: BnTestSameDescriptor(on_transact_same_descriptor),
+        proxy: BpTestSameDescriptor,
+    }
+}
+
+fn on_transact_same_descriptor(
+    _service: &dyn ITestSameDescriptor,
+    _code: TransactionCode,
+    _data: &Parcel,
+    _reply: &mut Parcel,
+) -> binder::Result<()> {
+    Ok(())
+}
+
+impl ITestSameDescriptor for BpTestSameDescriptor {}
+
+impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
+
+
+#[cfg(test)]
+mod tests {
+    use selinux_bindgen as selinux_sys;
+    use std::ffi::CStr;
+    use std::fs::File;
+    use std::process::{Child, Command};
+    use std::ptr;
+    use std::sync::atomic::{AtomicBool, Ordering};
+    use std::sync::Arc;
+    use std::thread;
+    use std::time::Duration;
+
+    use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
+
+    use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
+
+    pub struct ScopedServiceProcess(Child);
+
+    impl ScopedServiceProcess {
+        pub fn new(identifier: &str) -> Self {
+            Self::new_internal(identifier, None)
+        }
+
+        pub fn new_with_extension(identifier: &str, extension: &str) -> Self {
+            Self::new_internal(identifier, Some(extension))
+        }
+
+        fn new_internal(identifier: &str, extension: Option<&str>) -> Self {
+            let mut binary_path =
+                std::env::current_exe().expect("Could not retrieve current executable path");
+            binary_path.pop();
+            binary_path.push(RUST_SERVICE_BINARY);
+            let mut command = Command::new(&binary_path);
+            command.arg(identifier);
+            if let Some(ext) = extension {
+                command.arg(ext);
+            }
+            let child = command.spawn().expect("Could not start service");
+            Self(child)
+        }
+    }
+
+    impl Drop for ScopedServiceProcess {
+        fn drop(&mut self) {
+            self.0.kill().expect("Could not kill child process");
+            self.0
+                .wait()
+                .expect("Could not wait for child process to die");
+        }
+    }
+
+    #[test]
+    fn check_services() {
+        let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
+        assert!(sm.is_binder_alive());
+        assert!(sm.ping_binder().is_ok());
+
+        assert!(binder::get_service("this_service_does_not_exist").is_none());
+        assert_eq!(
+            binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+
+        // The service manager service isn't an ITest, so this must fail.
+        assert_eq!(
+            binder::get_interface::<dyn ITest>("manager").err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+    }
+
+    #[test]
+    fn trivial_client() {
+        let service_name = "trivial_client_test";
+        let _process = ScopedServiceProcess::new(service_name);
+        let test_client: Box<dyn ITest> =
+            binder::get_interface(service_name).expect("Did not get manager binder service");
+        assert_eq!(test_client.test().unwrap(), "trivial_client_test");
+    }
+
+    #[test]
+    fn get_selinux_context() {
+        let service_name = "get_selinux_context";
+        let _process = ScopedServiceProcess::new(service_name);
+        let test_client: Box<dyn ITest> =
+            binder::get_interface(service_name).expect("Did not get manager binder service");
+        let expected_context = unsafe {
+            let mut out_ptr = ptr::null_mut();
+            assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
+            assert!(!out_ptr.is_null());
+            CStr::from_ptr(out_ptr)
+        };
+        assert_eq!(
+            test_client.get_selinux_context().unwrap(),
+            expected_context.to_str().expect("context was invalid UTF-8"),
+        );
+    }
+
+    fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
+        let binder_died = Arc::new(AtomicBool::new(false));
+
+        let mut death_recipient = {
+            let flag = binder_died.clone();
+            DeathRecipient::new(move || {
+                flag.store(true, Ordering::Relaxed);
+            })
+        };
+
+        binder
+            .link_to_death(&mut death_recipient)
+            .expect("link_to_death failed");
+
+        (binder_died, death_recipient)
+    }
+
+    /// Killing a remote service should unregister the service and trigger
+    /// death notifications.
+    #[test]
+    fn test_death_notifications() {
+        binder::ProcessState::start_thread_pool();
+
+        let service_name = "test_death_notifications";
+        let service_process = ScopedServiceProcess::new(service_name);
+        let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
+
+        let (binder_died, _recipient) = register_death_notification(&mut remote);
+
+        drop(service_process);
+        remote
+            .ping_binder()
+            .expect_err("Service should have died already");
+
+        // Pause to ensure any death notifications get delivered
+        thread::sleep(Duration::from_secs(1));
+
+        assert!(
+            binder_died.load(Ordering::Relaxed),
+            "Did not receive death notification"
+        );
+    }
+
+    /// Test unregistering death notifications.
+    #[test]
+    fn test_unregister_death_notifications() {
+        binder::ProcessState::start_thread_pool();
+
+        let service_name = "test_unregister_death_notifications";
+        let service_process = ScopedServiceProcess::new(service_name);
+        let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
+
+        let (binder_died, mut recipient) = register_death_notification(&mut remote);
+
+        remote
+            .unlink_to_death(&mut recipient)
+            .expect("Could not unlink death notifications");
+
+        drop(service_process);
+        remote
+            .ping_binder()
+            .expect_err("Service should have died already");
+
+        // Pause to ensure any death notifications get delivered
+        thread::sleep(Duration::from_secs(1));
+
+        assert!(
+            !binder_died.load(Ordering::Relaxed),
+            "Received unexpected death notification after unlinking",
+        );
+    }
+
+    /// Dropping a remote handle should unregister any death notifications.
+    #[test]
+    fn test_death_notification_registration_lifetime() {
+        binder::ProcessState::start_thread_pool();
+
+        let service_name = "test_death_notification_registration_lifetime";
+        let service_process = ScopedServiceProcess::new(service_name);
+        let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
+
+        let (binder_died, _recipient) = register_death_notification(&mut remote);
+
+        // This should automatically unregister our death notification.
+        drop(remote);
+
+        drop(service_process);
+
+        // Pause to ensure any death notifications get delivered
+        thread::sleep(Duration::from_secs(1));
+
+        // We dropped the remote handle, so we should not receive the death
+        // notification when the remote process dies here.
+        assert!(
+            !binder_died.load(Ordering::Relaxed),
+            "Received unexpected death notification after dropping remote handle"
+        );
+    }
+
+    /// Test IBinder interface methods not exercised elsewhere.
+    #[test]
+    fn test_misc_ibinder() {
+        let service_name = "rust_test_ibinder";
+
+        {
+            let _process = ScopedServiceProcess::new(service_name);
+
+            let mut remote = binder::get_service(service_name);
+            assert!(remote.is_binder_alive());
+            remote.ping_binder().expect("Could not ping remote service");
+
+            // We're not testing the output of dump here, as that's really a
+            // property of the C++ implementation. There is the risk that the
+            // method just does nothing, but we don't want to depend on any
+            // particular output from the underlying library.
+            let null_out = File::open("/dev/null").expect("Could not open /dev/null");
+            remote
+                .dump(&null_out, &[])
+                .expect("Could not dump remote service");
+        }
+
+        // get/set_extensions is tested in test_extensions()
+
+        // transact is tested everywhere else, and we can't make raw
+        // transactions outside the [FIRST_CALL_TRANSACTION,
+        // LAST_CALL_TRANSACTION] range from the NDK anyway.
+
+        // link_to_death is tested in test_*_death_notification* tests.
+    }
+
+    #[test]
+    fn test_extensions() {
+        let service_name = "rust_test_extensions";
+        let extension_name = "rust_test_extensions_ext";
+
+        {
+            let _process = ScopedServiceProcess::new(service_name);
+
+            let mut remote = binder::get_service(service_name);
+            assert!(remote.is_binder_alive());
+
+            let extension = remote
+                .get_extension()
+                .expect("Could not check for an extension");
+            assert!(extension.is_none());
+        }
+
+        {
+            let _process = ScopedServiceProcess::new_with_extension(service_name, extension_name);
+
+            let mut remote = binder::get_service(service_name);
+            assert!(remote.is_binder_alive());
+
+            let maybe_extension = remote
+                .get_extension()
+                .expect("Could not check for an extension");
+
+            let extension = maybe_extension.expect("Remote binder did not have an extension");
+
+            let extension: Box<dyn ITest> = FromIBinder::try_from(extension)
+                .expect("Extension could not be converted to the expected interface");
+
+            assert_eq!(extension.test().unwrap(), extension_name);
+        }
+    }
+
+    /// Test re-associating a local binder object with a different class.
+    ///
+    /// This is needed because different binder service (e.g. NDK vs Rust)
+    /// implementations are incompatible and must not be interchanged. A local
+    /// service with the same descriptor string but a different class pointer
+    /// may have been created by an NDK service and is therefore incompatible
+    /// with the Rust service implementation. It must be treated as remote and
+    /// all API calls parceled and sent through transactions.
+    ///
+    /// Further tests of this behavior with the C NDK and Rust API are in
+    /// rust_ndk_interop.rs
+    #[test]
+    fn associate_existing_class() {
+        let service = Binder::new(BnTest(Box::new(TestService {
+            s: "testing_service".to_string(),
+        })));
+
+        // This should succeed although we will have to treat the service as
+        // remote.
+        let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
+            .expect("Could not re-interpret service as the ITestSameDescriptor interface");
+    }
+
+    /// Test that we can round-trip a rust service through a generic IBinder
+    #[test]
+    fn reassociate_rust_binder() {
+        let service_name = "testing_service";
+        let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
+            .as_binder();
+
+        let service: Box<dyn ITest> = service_ibinder.into_interface()
+            .expect("Could not reassociate the generic ibinder");
+
+        assert_eq!(service.test().unwrap(), service_name);
+    }
+}
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
new file mode 100644
index 0000000..70a6dc0
--- /dev/null
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Rust Binder NDK interop tests
+
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_int};
+use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
+    BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
+};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{
+    IBinderRustNdkInteropTestOther,
+};
+
+/// Look up the provided AIDL service and call its echo method.
+///
+/// # Safety
+///
+/// service_name must be a valid, non-null C-style string (null-terminated).
+#[no_mangle]
+pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
+    let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+
+    // The Rust class descriptor pointer will not match the NDK one, but the
+    // descriptor strings match so this needs to still associate.
+    let service: Box<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
+        Err(e) => {
+            eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
+            return StatusCode::NAME_NOT_FOUND as c_int;
+        }
+        Ok(service) => service,
+    };
+
+    match service.echo("testing") {
+        Ok(s) => if s != "testing" {
+            return StatusCode::BAD_VALUE as c_int;
+        },
+        Err(e) => return e.into(),
+    }
+
+    // Try using the binder service through the wrong interface type
+    let wrong_service: Result<Box<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
+        binder::get_interface(service_name);
+    match wrong_service {
+        Err(e) if e == StatusCode::BAD_TYPE => {}
+        Err(e) => {
+            eprintln!("Trying to use a service via the wrong interface errored with unexpected error {:?}", e);
+            return e as c_int;
+        }
+        Ok(_) => {
+            eprintln!("We should not be allowed to use a service via the wrong interface");
+            return StatusCode::BAD_TYPE as c_int;
+        }
+    }
+
+    StatusCode::OK as c_int
+}
+
+struct Service;
+
+impl Interface for Service {}
+
+impl IBinderRustNdkInteropTest for Service {
+    fn echo(&self, s: &str) -> binder::Result<String> {
+        Ok(s.to_string())
+    }
+}
+
+/// Start the interop Echo test service with the given service name.
+///
+/// # Safety
+///
+/// service_name must be a valid, non-null C-style string (null-terminated).
+#[no_mangle]
+pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
+    let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+    let service = BnBinderRustNdkInteropTest::new_binder(Service);
+    match binder::add_service(&service_name, service.as_binder()) {
+        Ok(_) => StatusCode::OK as c_int,
+        Err(e) => e as c_int,
+    }
+}
diff --git a/libs/binder/rust/tests/serialization.cpp b/libs/binder/rust/tests/serialization.cpp
new file mode 100644
index 0000000..ec780f2
--- /dev/null
+++ b/libs/binder/rust/tests/serialization.cpp
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_libbinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include "android-base/file.h"
+#include "serialization.hpp"
+
+#include <cmath>
+#include <cstdint>
+#include <iostream>
+#include <optional>
+
+using namespace std;
+using namespace android;
+using android::base::unique_fd;
+using android::os::ParcelFileDescriptor;
+
+// defined in Rust
+extern "C" AIBinder *rust_service();
+
+
+const int8_t TESTDATA_I8[4] = {-128, 0, 117, 127};
+const uint8_t TESTDATA_U8[4] = {0, 42, 117, 255};
+const char16_t TESTDATA_CHARS[4] = {0, 42, 117, numeric_limits<char16_t>::max()};
+const int32_t TESTDATA_I32[4] = {numeric_limits<int32_t>::min(), 0, 117, numeric_limits<int32_t>::max()};
+const int64_t TESTDATA_I64[4] = {numeric_limits<int64_t>::min(), 0, 117, numeric_limits<int64_t>::max()};
+const uint64_t TESTDATA_U64[4] = {0, 42, 117, numeric_limits<uint64_t>::max()};
+const float TESTDATA_FLOAT[4] = {
+        numeric_limits<float>::quiet_NaN(),
+        -numeric_limits<float>::infinity(),
+        117.0,
+        numeric_limits<float>::infinity(),
+};
+const double TESTDATA_DOUBLE[4] = {
+        numeric_limits<double>::quiet_NaN(),
+        -numeric_limits<double>::infinity(),
+        117.0,
+        numeric_limits<double>::infinity(),
+};
+const bool TESTDATA_BOOL[4] = {true, false, false, true};
+const char* const TESTDATA_STRS[4] = {"", nullptr, "test", ""};
+
+static ::testing::Environment* gEnvironment;
+
+class SerializationEnvironment : public ::testing::Environment {
+public:
+    void SetUp() override {
+        m_server = AIBinder_toPlatformBinder(rust_service());
+    }
+
+    sp<IBinder> getServer(void) { return m_server; }
+
+private:
+    sp<IBinder> m_server;
+};
+
+
+class SerializationTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        ASSERT_NE(gEnvironment, nullptr);
+        m_server = static_cast<SerializationEnvironment *>(gEnvironment)->getServer();
+    }
+
+    sp<IBinder> m_server;
+};
+
+
+TEST_F(SerializationTest, SerializeBool) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<bool> bools(begin(TESTDATA_BOOL), end(TESTDATA_BOOL));
+    ASSERT_EQ(data.writeBool(true), OK);
+    ASSERT_EQ(data.writeBool(false), OK);
+    ASSERT_EQ(data.writeBoolVector(bools), OK);
+    ASSERT_EQ(data.writeBoolVector(nullopt), OK);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_BOOL, data, &reply), OK);
+
+    vector<bool> read_bools;
+    optional<vector<bool>> maybe_bools;
+    ASSERT_EQ(reply.readBool(), true);
+    ASSERT_EQ(reply.readBool(), false);
+    ASSERT_EQ(reply.readBoolVector(&read_bools), OK);
+    ASSERT_EQ(read_bools, bools);
+    ASSERT_EQ(reply.readBoolVector(&maybe_bools), OK);
+    ASSERT_EQ(maybe_bools, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeByte) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<int8_t> i8s(begin(TESTDATA_I8), end(TESTDATA_I8));
+    vector<uint8_t> u8s(begin(TESTDATA_U8), end(TESTDATA_U8));
+    data.writeByte(0);
+    data.writeByte(1);
+    data.writeByte(numeric_limits<int8_t>::max());
+    data.writeByteVector(i8s);
+    data.writeByteVector(u8s);
+    data.writeByteVector(optional<vector<int8_t>>({}));
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_BYTE, data, &reply), OK);
+
+    vector<int8_t> read_i8s;
+    vector<uint8_t> read_u8s;
+    optional<vector<int8_t>> maybe_i8s;
+    ASSERT_EQ(reply.readByte(), 0);
+    ASSERT_EQ(reply.readByte(), 1);
+    ASSERT_EQ(reply.readByte(), numeric_limits<int8_t>::max());
+    ASSERT_EQ(reply.readByteVector(&read_i8s), OK);
+    ASSERT_EQ(read_i8s, i8s);
+    ASSERT_EQ(reply.readByteVector(&read_u8s), OK);
+    ASSERT_EQ(read_u8s, u8s);
+    ASSERT_EQ(reply.readByteVector(&maybe_i8s), OK);
+    ASSERT_EQ(maybe_i8s, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeU16) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<char16_t> chars(begin(TESTDATA_CHARS), end(TESTDATA_CHARS));
+    data.writeChar(0);
+    data.writeChar(1);
+    data.writeChar(numeric_limits<char16_t>::max());
+    data.writeCharVector(chars);
+    data.writeCharVector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_U16, data, &reply), OK);
+
+    vector<char16_t> read_chars;
+    optional<vector<char16_t>> maybe_chars;
+    ASSERT_EQ(reply.readChar(), 0);
+    ASSERT_EQ(reply.readChar(), 1);
+    ASSERT_EQ(reply.readChar(), numeric_limits<char16_t>::max());
+    ASSERT_EQ(reply.readCharVector(&read_chars), OK);
+    ASSERT_EQ(read_chars, chars);
+    ASSERT_EQ(reply.readCharVector(&maybe_chars), OK);
+    ASSERT_EQ(maybe_chars, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeI32) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<int32_t> i32s(begin(TESTDATA_I32), end(TESTDATA_I32));
+    data.writeInt32(0);
+    data.writeInt32(1);
+    data.writeInt32(numeric_limits<int32_t>::max());
+    data.writeInt32Vector(i32s);
+    data.writeInt32Vector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_I32, data, &reply), OK);
+
+    vector<int32_t> read_i32s;
+    optional<vector<int32_t>> maybe_i32s;
+    ASSERT_EQ(reply.readInt32(), 0);
+    ASSERT_EQ(reply.readInt32(), 1);
+    ASSERT_EQ(reply.readInt32(), numeric_limits<int32_t>::max());
+    ASSERT_EQ(reply.readInt32Vector(&read_i32s), OK);
+    ASSERT_EQ(read_i32s, i32s);
+    ASSERT_EQ(reply.readInt32Vector(&maybe_i32s), OK);
+    ASSERT_EQ(maybe_i32s, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeI64) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<int64_t> i64s(begin(TESTDATA_I64), end(TESTDATA_I64));
+    data.writeInt64(0);
+    data.writeInt64(1);
+    data.writeInt64(numeric_limits<int64_t>::max());
+    data.writeInt64Vector(i64s);
+    data.writeInt64Vector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_I64, data, &reply), OK);
+
+    vector<int64_t> read_i64s;
+    optional<vector<int64_t>> maybe_i64s;
+    ASSERT_EQ(reply.readInt64(), 0);
+    ASSERT_EQ(reply.readInt64(), 1);
+    ASSERT_EQ(reply.readInt64(), numeric_limits<int64_t>::max());
+    ASSERT_EQ(reply.readInt64Vector(&read_i64s), OK);
+    ASSERT_EQ(read_i64s, i64s);
+    ASSERT_EQ(reply.readInt64Vector(&maybe_i64s), OK);
+    ASSERT_EQ(maybe_i64s, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeU64) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<uint64_t> u64s(begin(TESTDATA_U64), end(TESTDATA_U64));
+    data.writeUint64(0);
+    data.writeUint64(1);
+    data.writeUint64(numeric_limits<uint64_t>::max());
+    data.writeUint64Vector(u64s);
+    data.writeUint64Vector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_U64, data, &reply), OK);
+
+    vector<uint64_t> read_u64s;
+    optional<vector<uint64_t>> maybe_u64s;
+    ASSERT_EQ(reply.readUint64(), 0);
+    ASSERT_EQ(reply.readUint64(), 1);
+    ASSERT_EQ(reply.readUint64(), numeric_limits<uint64_t>::max());
+    ASSERT_EQ(reply.readUint64Vector(&read_u64s), OK);
+    ASSERT_EQ(read_u64s, u64s);
+    ASSERT_EQ(reply.readUint64Vector(&maybe_u64s), OK);
+    ASSERT_EQ(maybe_u64s, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeF32) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<float> floats(begin(TESTDATA_FLOAT), end(TESTDATA_FLOAT));
+    data.writeFloat(0);
+    data.writeFloatVector(floats);
+    data.writeFloatVector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_F32, data, &reply), OK);
+
+    vector<float> read_floats;
+    optional<vector<float>> maybe_floats;
+    ASSERT_EQ(reply.readFloat(), 0);
+    ASSERT_EQ(reply.readFloatVector(&read_floats), OK);
+    ASSERT_TRUE(isnan(read_floats[0]));
+    ASSERT_EQ(read_floats[1], floats[1]);
+    ASSERT_EQ(read_floats[2], floats[2]);
+    ASSERT_EQ(read_floats[3], floats[3]);
+    ASSERT_EQ(reply.readFloatVector(&maybe_floats), OK);
+    ASSERT_EQ(maybe_floats, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeF64) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<double> doubles(begin(TESTDATA_DOUBLE), end(TESTDATA_DOUBLE));
+    data.writeDouble(0);
+    data.writeDoubleVector(doubles);
+    data.writeDoubleVector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_F64, data, &reply), OK);
+
+    vector<double> read_doubles;
+    optional<vector<double>> maybe_doubles;
+    ASSERT_EQ(reply.readDouble(), 0);
+    ASSERT_EQ(reply.readDoubleVector(&read_doubles), OK);
+    ASSERT_TRUE(isnan(read_doubles[0]));
+    ASSERT_EQ(read_doubles[1], doubles[1]);
+    ASSERT_EQ(read_doubles[2], doubles[2]);
+    ASSERT_EQ(read_doubles[3], doubles[3]);
+    ASSERT_EQ(reply.readDoubleVector(&maybe_doubles), OK);
+    ASSERT_EQ(maybe_doubles, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeString) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    vector<optional<String16>> strings;
+    for (auto I = begin(TESTDATA_STRS), E = end(TESTDATA_STRS); I != E; ++I) {
+        if (*I == nullptr) {
+            strings.push_back(optional<String16>());
+        } else {
+            strings.emplace_back(*I);
+        }
+    }
+    data.writeUtf8AsUtf16(string("testing"));
+    data.writeString16(nullopt);
+    data.writeString16Vector(strings);
+    data.writeString16Vector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_STRING, data, &reply), OK);
+
+    optional<String16> maybe_string;
+    optional<vector<optional<String16>>> read_strings;
+    ASSERT_EQ(reply.readString16(), String16("testing"));
+    ASSERT_EQ(reply.readString16(&maybe_string), OK);
+    ASSERT_EQ(maybe_string, nullopt);
+    ASSERT_EQ(reply.readString16Vector(&read_strings), OK);
+    ASSERT_EQ(read_strings, strings);
+    ASSERT_EQ(reply.readString16Vector(&read_strings), OK);
+    ASSERT_EQ(read_strings, nullopt);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeFileDescriptor) {
+    unique_fd out_file, in_file;
+    ASSERT_TRUE(base::Pipe(&out_file, &in_file));
+
+    vector<ParcelFileDescriptor> file_descriptors;
+    file_descriptors.push_back(ParcelFileDescriptor(std::move(out_file)));
+    file_descriptors.push_back(ParcelFileDescriptor(std::move(in_file)));
+
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    data.writeParcelable(file_descriptors[0]);
+    data.writeParcelable(file_descriptors[1]);
+    data.writeParcelableVector(file_descriptors);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_FILE_DESCRIPTOR, data, &reply), OK);
+
+    ParcelFileDescriptor returned_fd1, returned_fd2;
+    vector<ParcelFileDescriptor> returned_file_descriptors;
+    ASSERT_EQ(reply.readParcelable(&returned_fd1), OK);
+    ASSERT_EQ(reply.readParcelable(&returned_fd2), OK);
+    ASSERT_EQ(reply.readParcelableVector(&returned_file_descriptors), OK);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+
+    base::WriteStringToFd("Testing", returned_fd2.get());
+    base::WriteStringToFd("File", returned_file_descriptors[1].get());
+    base::WriteStringToFd("Descriptors", file_descriptors[1].get());
+
+    string expected = "TestingFileDescriptors";
+    vector<char> buf(expected.length());
+    base::ReadFully(file_descriptors[0].release(), buf.data(), buf.size());
+    ASSERT_EQ(expected, string(buf.data()));
+}
+
+TEST_F(SerializationTest, SerializeIBinder) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    data.writeStrongBinder(m_server);
+    data.writeStrongBinder(nullptr);
+    data.writeStrongBinderVector({m_server, nullptr});
+    data.writeStrongBinderVector(nullopt);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_IBINDER, data, &reply), OK);
+
+    optional<vector<sp<IBinder>>> binders;
+    ASSERT_TRUE(reply.readStrongBinder());
+    ASSERT_FALSE(reply.readStrongBinder());
+    ASSERT_EQ(reply.readStrongBinderVector(&binders), OK);
+    ASSERT_EQ(binders->size(), 2);
+    ASSERT_TRUE((*binders)[0]);
+    ASSERT_FALSE((*binders)[1]);
+    ASSERT_EQ(reply.readStrongBinderVector(&binders), OK);
+    ASSERT_FALSE(binders);
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+TEST_F(SerializationTest, SerializeStatus) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+
+    binder::Status::ok().writeToParcel(&data);
+    binder::Status::fromExceptionCode(binder::Status::EX_NULL_POINTER, "a status message")
+            .writeToParcel(&data);
+    binder::Status::fromServiceSpecificError(42, "a service-specific error").writeToParcel(&data);
+
+    android::Parcel reply;
+    ASSERT_EQ(m_server->transact(TEST_STATUS, data, &reply), OK);
+
+    binder::Status status;
+
+    ASSERT_EQ(status.readFromParcel(reply), OK);
+    ASSERT_TRUE(status.isOk());
+
+    ASSERT_EQ(status.readFromParcel(reply), OK);
+    ASSERT_EQ(status.exceptionCode(), binder::Status::EX_NULL_POINTER);
+    ASSERT_EQ(status.exceptionMessage(), "a status message");
+
+    ASSERT_EQ(status.readFromParcel(reply), OK);
+    ASSERT_EQ(status.serviceSpecificErrorCode(), 42);
+    ASSERT_EQ(status.exceptionMessage(), "a service-specific error");
+
+    int32_t end;
+    ASSERT_EQ(reply.readInt32(&end), NOT_ENOUGH_DATA);
+}
+
+// Test that failures from Rust properly propagate to C++
+TEST_F(SerializationTest, SerializeRustFail) {
+    android::Parcel data;
+    data.writeInterfaceToken(String16("read_parcel_test"));
+    ASSERT_EQ(m_server->transact(TEST_FAIL, data, nullptr), FAILED_TRANSACTION);
+}
+
+int main(int argc, char **argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnvironment = AddGlobalTestEnvironment(new SerializationEnvironment());
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/rust/tests/serialization.hpp b/libs/binder/rust/tests/serialization.hpp
new file mode 100644
index 0000000..0041608
--- /dev/null
+++ b/libs/binder/rust/tests/serialization.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+
+using namespace android;
+
+enum Transaction {
+    TEST_BOOL = IBinder::FIRST_CALL_TRANSACTION,
+    TEST_BYTE,
+    TEST_U16,
+    TEST_I32,
+    TEST_I64,
+    TEST_U64,
+    TEST_F32,
+    TEST_F64,
+    TEST_STRING,
+    TEST_FILE_DESCRIPTOR,
+    TEST_IBINDER,
+    TEST_STATUS,
+    TEST_FAIL,
+};
+
+extern const int8_t TESTDATA_I8[4];
+extern const uint8_t TESTDATA_U8[4];
+extern const char16_t TESTDATA_CHARS[4];
+extern const int32_t TESTDATA_I32[4];
+extern const int64_t TESTDATA_I64[4];
+extern const uint64_t TESTDATA_U64[4];
+extern const float TESTDATA_FLOAT[4];
+extern const double TESTDATA_DOUBLE[4];
+extern const bool TESTDATA_BOOL[4];
+extern const char* const TESTDATA_STRS[4];
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
new file mode 100644
index 0000000..2bf3d03
--- /dev/null
+++ b/libs/binder/rust/tests/serialization.rs
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Included as a module in the binder crate internal tests for internal API
+//! access.
+
+use binder::declare_binder_interface;
+use binder::{
+    Binder, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+    StatusCode, TransactionCode,
+};
+use binder::parcel::ParcelFileDescriptor;
+
+use std::ffi::{c_void, CStr, CString};
+use std::sync::Once;
+
+#[allow(
+    non_camel_case_types,
+    non_snake_case,
+    non_upper_case_globals,
+    unused,
+    improper_ctypes,
+    missing_docs,
+    clippy::all
+)]
+mod bindings {
+    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+static SERVICE_ONCE: Once = Once::new();
+static mut SERVICE: Option<SpIBinder> = None;
+
+/// Start binder service and return a raw AIBinder pointer to it.
+///
+/// Safe to call multiple times, only creates the service once.
+#[no_mangle]
+pub extern "C" fn rust_service() -> *mut c_void {
+    unsafe {
+        SERVICE_ONCE.call_once(|| {
+            SERVICE = Some(BnReadParcelTest::new_binder(()).as_binder());
+        });
+        SERVICE.as_ref().unwrap().as_raw().cast()
+    }
+}
+
+/// Empty interface just to use the declare_binder_interface macro
+pub trait ReadParcelTest: Interface {}
+
+declare_binder_interface! {
+    ReadParcelTest["read_parcel_test"] {
+        native: BnReadParcelTest(on_transact),
+        proxy: BpReadParcelTest,
+    }
+}
+
+impl ReadParcelTest for Binder<BnReadParcelTest> {}
+
+impl ReadParcelTest for BpReadParcelTest {}
+
+impl ReadParcelTest for () {}
+
+#[allow(clippy::float_cmp)]
+fn on_transact(_service: &dyn ReadParcelTest, code: TransactionCode,
+               parcel: &Parcel, reply: &mut Parcel) -> Result<()> {
+    match code {
+        bindings::Transaction_TEST_BOOL => {
+            assert_eq!(parcel.read::<bool>()?, true);
+            assert_eq!(parcel.read::<bool>()?, false);
+            assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
+                bindings::TESTDATA_BOOL
+            });
+            assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
+
+            reply.write(&true)?;
+            reply.write(&false)?;
+            reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?;
+            reply.write(&(None as Option<Vec<bool>>))?;
+        }
+        bindings::Transaction_TEST_BYTE => {
+            assert_eq!(parcel.read::<i8>()?, 0);
+            assert_eq!(parcel.read::<i8>()?, 1);
+            assert_eq!(parcel.read::<i8>()?, i8::max_value());
+            assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
+            assert_eq!(parcel.read::<Vec<u8>>()?, unsafe { bindings::TESTDATA_U8 });
+            assert_eq!(parcel.read::<Option<Vec<i8>>>()?, None);
+
+            reply.write(&0i8)?;
+            reply.write(&1i8)?;
+            reply.write(&i8::max_value())?;
+            reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
+            reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?;
+            reply.write(&(None as Option<Vec<i8>>))?;
+        }
+        bindings::Transaction_TEST_U16 => {
+            assert_eq!(parcel.read::<u16>()?, 0);
+            assert_eq!(parcel.read::<u16>()?, 1);
+            assert_eq!(parcel.read::<u16>()?, u16::max_value());
+            assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
+                bindings::TESTDATA_CHARS
+            });
+            assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
+
+            reply.write(&0u16)?;
+            reply.write(&1u16)?;
+            reply.write(&u16::max_value())?;
+            reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
+            reply.write(&(None as Option<Vec<u16>>))?;
+        }
+        bindings::Transaction_TEST_I32 => {
+            assert_eq!(parcel.read::<i32>()?, 0);
+            assert_eq!(parcel.read::<i32>()?, 1);
+            assert_eq!(parcel.read::<i32>()?, i32::max_value());
+            assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
+                bindings::TESTDATA_I32
+            });
+            assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
+
+            reply.write(&0i32)?;
+            reply.write(&1i32)?;
+            reply.write(&i32::max_value())?;
+            reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
+            reply.write(&(None as Option<Vec<i32>>))?;
+        }
+        bindings::Transaction_TEST_I64 => {
+            assert_eq!(parcel.read::<i64>()?, 0);
+            assert_eq!(parcel.read::<i64>()?, 1);
+            assert_eq!(parcel.read::<i64>()?, i64::max_value());
+            assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
+                bindings::TESTDATA_I64
+            });
+            assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
+
+            reply.write(&0i64)?;
+            reply.write(&1i64)?;
+            reply.write(&i64::max_value())?;
+            reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
+            reply.write(&(None as Option<Vec<i64>>))?;
+        }
+        bindings::Transaction_TEST_U64 => {
+            assert_eq!(parcel.read::<u64>()?, 0);
+            assert_eq!(parcel.read::<u64>()?, 1);
+            assert_eq!(parcel.read::<u64>()?, u64::max_value());
+            assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
+                bindings::TESTDATA_U64
+            });
+            assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
+
+            reply.write(&0u64)?;
+            reply.write(&1u64)?;
+            reply.write(&u64::max_value())?;
+            reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
+            reply.write(&(None as Option<Vec<u64>>))?;
+        }
+        bindings::Transaction_TEST_F32 => {
+            assert_eq!(parcel.read::<f32>()?, 0f32);
+            let floats = parcel.read::<Vec<f32>>()?;
+            assert!(floats[0].is_nan());
+            assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]);
+            assert_eq!(parcel.read::<Option<Vec<f32>>>()?, None);
+
+            reply.write(&0f32)?;
+            reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?;
+            reply.write(&(None as Option<Vec<f32>>))?;
+        }
+        bindings::Transaction_TEST_F64 => {
+            assert_eq!(parcel.read::<f64>()?, 0f64);
+            let doubles = parcel.read::<Vec<f64>>()?;
+            assert!(doubles[0].is_nan());
+            assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]);
+            assert_eq!(parcel.read::<Option<Vec<f64>>>()?, None);
+
+            reply.write(&0f64)?;
+            reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?;
+            reply.write(&(None as Option<Vec<f64>>))?;
+        }
+        bindings::Transaction_TEST_STRING => {
+            let s: Option<String> = parcel.read()?;
+            assert_eq!(s.as_deref(), Some("testing"));
+            let s: Option<String> = parcel.read()?;
+            assert_eq!(s, None);
+            let s: Option<Vec<Option<String>>> = parcel.read()?;
+            for (s, expected) in s
+                .unwrap()
+                .iter()
+                .zip(unsafe { bindings::TESTDATA_STRS }.iter())
+            {
+                let expected = unsafe {
+                    expected
+                        .as_ref()
+                        .and_then(|e| CStr::from_ptr(e).to_str().ok())
+                };
+                assert_eq!(s.as_deref(), expected);
+            }
+            let s: Option<Vec<Option<String>>> = parcel.read()?;
+            assert_eq!(s, None);
+
+            let strings: Vec<Option<String>> = unsafe {
+                bindings::TESTDATA_STRS
+                    .iter()
+                    .map(|s| {
+                        s.as_ref().map(|s| {
+                            CStr::from_ptr(s)
+                                .to_str()
+                                .expect("String was not UTF-8")
+                                .to_owned()
+                        })
+                    })
+                    .collect()
+            };
+
+            reply.write("testing")?;
+            reply.write(&(None as Option<String>))?;
+            reply.write(&strings)?;
+            reply.write(&(None as Option<Vec<String>>))?;
+        }
+        bindings::Transaction_TEST_FILE_DESCRIPTOR => {
+            let file1 = parcel.read::<ParcelFileDescriptor>()?;
+            let file2 = parcel.read::<ParcelFileDescriptor>()?;
+            let files = parcel.read::<Vec<Option<ParcelFileDescriptor>>>()?;
+
+            reply.write(&file1)?;
+            reply.write(&file2)?;
+            reply.write(&files)?;
+        }
+        bindings::Transaction_TEST_IBINDER => {
+            assert!(parcel.read::<Option<SpIBinder>>()?.is_some());
+            assert!(parcel.read::<Option<SpIBinder>>()?.is_none());
+            let ibinders = parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.unwrap();
+            assert_eq!(ibinders.len(), 2);
+            assert!(ibinders[0].is_some());
+            assert!(ibinders[1].is_none());
+            assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
+
+            let service = unsafe {
+                SERVICE
+                    .as_ref()
+                    .expect("Global binder service not initialized")
+                    .clone()
+            };
+            reply.write(&service)?;
+            reply.write(&(None as Option<&SpIBinder>))?;
+            reply.write(&[Some(&service), None][..])?;
+            reply.write(&(None as Option<Vec<Option<&SpIBinder>>>))?;
+        }
+        bindings::Transaction_TEST_STATUS => {
+            let status: Status = parcel.read()?;
+            assert!(status.is_ok());
+            let status: Status = parcel.read()?;
+            assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
+            assert_eq!(
+                status.get_description(),
+                "Status(-4, EX_NULL_POINTER): 'a status message'"
+            );
+            let status: Status = parcel.read()?;
+            assert_eq!(status.service_specific_error(), 42);
+            assert_eq!(
+                status.get_description(),
+                "Status(-8, EX_SERVICE_SPECIFIC): '42: a service-specific error'"
+            );
+
+            reply.write(&Status::ok())?;
+            reply.write(&Status::new_exception(
+                ExceptionCode::NULL_POINTER,
+                Some(&CString::new("a status message").unwrap()),
+            ))?;
+            reply.write(&Status::new_service_specific_error(
+                42,
+                Some(&CString::new("a service-specific error").unwrap()),
+            ))?;
+        }
+        bindings::Transaction_TEST_FAIL => {
+            return Err(StatusCode::FAILED_TRANSACTION)
+        }
+        _ => return Err(StatusCode::UNKNOWN_TRANSACTION),
+    }
+
+    assert_eq!(parcel.read::<i32>(), Err(StatusCode::NOT_ENOUGH_DATA));
+    Ok(())
+}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index c0da2cd..988f7f3 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -60,6 +60,23 @@
     require_root: true,
 }
 
+// unit test only, which can run on host and doesn't use /dev/binder
+cc_test {
+    name: "binderParcelTest",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: ["binderParcelTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    test_suites: ["general-tests"],
+}
+
 cc_test {
     name: "binderLibTest",
     defaults: ["binder_test_defaults"],
@@ -140,6 +157,24 @@
     require_root: true,
 }
 
+cc_test {
+    name: "binderClearBufTest",
+    defaults: ["binder_test_defaults"],
+    srcs: [
+        "binderClearBufTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
 aidl_interface {
     name: "binderStabilityTestIface",
     unstable: true,
@@ -155,6 +190,7 @@
         "binderStabilityTest.cpp",
     ],
 
+    // critical that libbinder/libbinder_ndk are shared for VTS
     shared_libs: [
         "libbinder_ndk",
         "libbinder",
@@ -166,6 +202,21 @@
         "binderStabilityTestIface-ndk_platform",
     ],
 
+    test_suites: ["device-tests", "vts"],
+    require_root: true,
+}
+
+cc_test {
+    name: "binderAllocationLimits",
+    defaults: ["binder_test_defaults"],
+    srcs: ["binderAllocationLimits.cpp"],
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libutils",
+        "libutilscallstack",
+        "libbase",
+    ],
     test_suites: ["device-tests"],
     require_root: true,
 }
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
new file mode 100644
index 0000000..e1f5ed5
--- /dev/null
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <utils/CallStack.h>
+
+#include <malloc.h>
+#include <functional>
+#include <vector>
+
+struct DestructionAction {
+    DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
+    ~DestructionAction() { mF(); };
+private:
+    std::function<void()> mF;
+};
+
+// Group of hooks
+struct MallocHooks {
+    decltype(__malloc_hook) malloc_hook;
+    decltype(__realloc_hook) realloc_hook;
+
+    static MallocHooks save() {
+        return {
+            .malloc_hook = __malloc_hook,
+            .realloc_hook = __realloc_hook,
+        };
+    }
+
+    void overwrite() const {
+        __malloc_hook = malloc_hook;
+        __realloc_hook = realloc_hook;
+    }
+};
+
+static const MallocHooks orig_malloc_hooks = MallocHooks::save();
+
+// When malloc is hit, executes lambda.
+namespace LambdaHooks {
+    using AllocationHook = std::function<void(size_t)>;
+    static std::vector<AllocationHook> lambdas = {};
+
+    static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg);
+    static void* lambda_malloc_hook(size_t bytes, const void* arg);
+
+    static const MallocHooks lambda_malloc_hooks = {
+        .malloc_hook = lambda_malloc_hook,
+        .realloc_hook = lambda_realloc_hook,
+    };
+
+    static void* lambda_malloc_hook(size_t bytes, const void* arg) {
+        {
+            orig_malloc_hooks.overwrite();
+            lambdas.at(lambdas.size() - 1)(bytes);
+            lambda_malloc_hooks.overwrite();
+        }
+        return orig_malloc_hooks.malloc_hook(bytes, arg);
+    }
+
+    static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg) {
+        {
+            orig_malloc_hooks.overwrite();
+            lambdas.at(lambdas.size() - 1)(bytes);
+            lambda_malloc_hooks.overwrite();
+        }
+        return orig_malloc_hooks.realloc_hook(ptr, bytes, arg);
+    }
+
+}
+
+// Action to execute when malloc is hit. Supports nesting. Malloc is not
+// restricted when the allocation hook is being processed.
+__attribute__((warn_unused_result))
+DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
+    MallocHooks before = MallocHooks::save();
+    LambdaHooks::lambdas.emplace_back(std::move(f));
+    LambdaHooks::lambda_malloc_hooks.overwrite();
+    return DestructionAction([before]() {
+        before.overwrite();
+        LambdaHooks::lambdas.pop_back();
+    });
+}
+
+// exported symbol, to force compiler not to optimize away pointers we set here
+const void* imaginary_use;
+
+TEST(TestTheTest, OnMalloc) {
+    size_t mallocs = 0;
+    {
+        const auto on_malloc = OnMalloc([&](size_t bytes) {
+            mallocs++;
+            EXPECT_EQ(bytes, 40);
+        });
+
+        imaginary_use = new int[10];
+    }
+    EXPECT_EQ(mallocs, 1);
+}
+
+
+__attribute__((warn_unused_result))
+DestructionAction ScopeDisallowMalloc() {
+    return OnMalloc([&](size_t bytes) {
+        ADD_FAILURE() << "Unexpected allocation: " << bytes;
+        using android::CallStack;
+        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
+                  << std::endl;
+    });
+}
+
+using android::IBinder;
+using android::Parcel;
+using android::String16;
+using android::defaultServiceManager;
+using android::sp;
+using android::IServiceManager;
+
+static sp<IBinder> GetRemoteBinder() {
+    // This gets binder representing the service manager
+    // the current IServiceManager API doesn't expose the binder, and
+    // I want to avoid adding usages of the AIDL generated interface it
+    // is using underneath, so to avoid people copying it.
+    sp<IBinder> binder = defaultServiceManager()->checkService(String16("manager"));
+    EXPECT_NE(nullptr, binder);
+    return binder;
+}
+
+TEST(BinderAllocation, ParcelOnStack) {
+    const auto m = ScopeDisallowMalloc();
+    Parcel p;
+    imaginary_use = p.data();
+}
+
+TEST(BinderAllocation, GetServiceManager) {
+    defaultServiceManager(); // first call may alloc
+    const auto m = ScopeDisallowMalloc();
+    defaultServiceManager();
+}
+
+// note, ping does not include interface descriptor
+TEST(BinderAllocation, PingTransaction) {
+    sp<IBinder> a_binder = GetRemoteBinder();
+    const auto m = ScopeDisallowMalloc();
+    a_binder->pingBinder();
+}
+
+TEST(BinderAllocation, SmallTransaction) {
+    String16 empty_descriptor = String16("");
+    sp<IServiceManager> manager = defaultServiceManager();
+
+    size_t mallocs = 0;
+    const auto on_malloc = OnMalloc([&](size_t bytes) {
+        mallocs++;
+        // Parcel should allocate a small amount by default
+        EXPECT_EQ(bytes, 128);
+    });
+    manager->checkService(empty_descriptor);
+
+    EXPECT_EQ(mallocs, 1);
+}
+
+int main(int argc, char** argv) {
+    if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
+        CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
+        execv(argv[0], argv);
+        return 1;
+    }
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp
new file mode 100644
index 0000000..2d30c8d
--- /dev/null
+++ b/libs/binder/tests/binderClearBufTest.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+#include <thread>
+
+using namespace android;
+
+const String16 kServerName = String16("binderClearBuf");
+
+std::string hexString(const void* bytes, size_t len) {
+    if (bytes == nullptr) return "<null>";
+
+    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+    char chars[] = "0123456789abcdef";
+    std::string result;
+    result.resize(len * 2);
+
+    for (size_t i = 0; i < len; i++) {
+        result[2 * i] = chars[bytes8[i] >> 4];
+        result[2 * i + 1] = chars[bytes8[i] & 0xf];
+    }
+
+    return result;
+}
+
+class FooBar : public BBinder {
+ public:
+    enum {
+        TRANSACTION_REPEAT_STRING = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+    std::mutex foo;
+    std::string last;
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+        // not checking data, since there is no hook at the time this test is
+        // written to check values there are set to zero. Instead, we only check
+        // the reply parcel.
+
+        switch (code) {
+            case TRANSACTION_REPEAT_STRING: {
+                const char* str = data.readCString();
+                return reply->writeCString(str == nullptr ? "<null>" : str);
+            }
+        }
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    static std::string RepeatString(const sp<IBinder> binder,
+                                    const std::string& repeat,
+                                    std::string* outBuffer) {
+        Parcel data;
+        data.writeCString(repeat.c_str());
+        std::string result;
+        const uint8_t* lastReply;
+        size_t lastReplySize;
+        {
+            Parcel reply;
+            binder->transact(TRANSACTION_REPEAT_STRING, data, &reply, FLAG_CLEAR_BUF);
+            result = reply.readCString();
+            lastReply = reply.data();
+            lastReplySize = reply.dataSize();
+        }
+        *outBuffer = hexString(lastReply, lastReplySize);
+        return result;
+    }
+};
+
+TEST(BinderClearBuf, ClearKernelBuffer) {
+    sp<IBinder> binder = defaultServiceManager()->getService(kServerName);
+    ASSERT_NE(nullptr, binder);
+
+    std::string replyBuffer;
+    std::string result = FooBar::RepeatString(binder, "foo", &replyBuffer);
+    EXPECT_EQ("foo", result);
+
+    // the buffer must have at least some length for the string, but we will
+    // just check it has some length, to avoid assuming anything about the
+    // format
+    EXPECT_GT(replyBuffer.size(), 0);
+
+    for (size_t i = 0; i < replyBuffer.size(); i++) {
+        EXPECT_EQ(replyBuffer[i], '0') << "reply buffer at " << i;
+    }
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        sp<IBinder> server = new FooBar;
+        android::defaultServiceManager()->addService(kServerName, server);
+
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1);  // should not reach
+    }
+
+    // This is not racey. Just giving these services some time to register before we call
+    // getService which sleeps for much longer. One alternative would be to
+    // start a threadpool + use waitForService, but we want to have as few
+    // binder things going on in this test as possible, since we are checking
+    // memory is zero'd which the kernel has a right to change.
+    usleep(100000);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 98f0868..a5261e5 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
 #include <binder/IServiceManager.h>
 
 #include <private/binder/binder_module.h>
+#include <linux/sched.h>
 #include <sys/epoll.h>
 #include <sys/prctl.h>
 
@@ -53,6 +54,7 @@
 
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
+static constexpr int kSchedPriorityMore = 8;
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -402,6 +404,21 @@
     EXPECT_EQ(NO_ERROR, ret);
 }
 
+TEST_F(BinderLibTest, NopTransactionOneway) {
+    status_t ret;
+    Parcel data, reply;
+    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, NopTransactionClear) {
+    status_t ret;
+    Parcel data, reply;
+    // make sure it accepts the transaction flag
+    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 TEST_F(BinderLibTest, Freeze) {
     status_t ret;
     Parcel data, reply, replypid;
@@ -1080,6 +1097,25 @@
     EXPECT_EQ(kSchedPriority, priority);
 }
 
+TEST_F(BinderLibTest, InheritRt) {
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+
+    const struct sched_param param {
+        .sched_priority = kSchedPriorityMore,
+    };
+    EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, &param));
+
+    Parcel data, reply;
+    status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
+    EXPECT_EQ(NO_ERROR, ret);
+
+    int policy = reply.readInt32();
+    int priority = reply.readInt32();
+
+    EXPECT_EQ(kSchedPolicy, policy & (~SCHED_RESET_ON_FORK));
+    EXPECT_EQ(kSchedPriorityMore, priority);
+}
 
 TEST_F(BinderLibTest, VectorSent) {
     Parcel data, reply;
@@ -1153,9 +1189,6 @@
         virtual status_t onTransact(uint32_t code,
                                     const Parcel& data, Parcel* reply,
                                     uint32_t flags = 0) {
-            //printf("%s: code %d\n", __func__, code);
-            (void)flags;
-
             if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) {
                 return PERMISSION_DENIED;
             }
@@ -1229,8 +1262,12 @@
                 return NO_ERROR;
             case BINDER_LIB_TEST_NOP_TRANSACTION_WAIT:
                 usleep(5000);
-                return NO_ERROR;
+                [[fallthrough]];
             case BINDER_LIB_TEST_NOP_TRANSACTION:
+                // oneway error codes should be ignored
+                if (flags & TF_ONE_WAY) {
+                    return UNKNOWN_ERROR;
+                }
                 return NO_ERROR;
             case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
                 // Note: this transaction is only designed for use with a
@@ -1452,6 +1489,8 @@
 
         testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
 
+        testService->setInheritRt(true);
+
         /*
          * Normally would also contain functionality as well, but we are only
          * testing the extension mechanism.
diff --git a/libs/binder/tests/binderParcelTest.cpp b/libs/binder/tests/binderParcelTest.cpp
new file mode 100644
index 0000000..1764228
--- /dev/null
+++ b/libs/binder/tests/binderParcelTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <gtest/gtest.h>
+
+using android::IPCThreadState;
+using android::OK;
+using android::Parcel;
+using android::String16;
+using android::String8;
+using android::status_t;
+
+// Tests a second operation results in a parcel at the same location as it
+// started.
+void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
+    Parcel p;
+    a(&p);
+    size_t end = p.dataPosition();
+    p.setDataPosition(0);
+    b(&p);
+    EXPECT_EQ(end, p.dataPosition());
+}
+
+TEST(Parcel, InverseInterfaceToken) {
+    const String16 token = String16("asdf");
+    parcelOpSameLength([&] (Parcel* p) {
+        p->writeInterfaceToken(token);
+    }, [&] (Parcel* p) {
+        EXPECT_TRUE(p->enforceInterface(token, IPCThreadState::self()));
+    });
+}
+
+TEST(Parcel, Utf8FromUtf16Read) {
+    const char* token = "asdf";
+    parcelOpSameLength([&] (Parcel* p) {
+        p->writeString16(String16(token));
+    }, [&] (Parcel* p) {
+        std::string s;
+        EXPECT_EQ(OK, p->readUtf8FromUtf16(&s));
+        EXPECT_EQ(token, s);
+    });
+}
+
+TEST(Parcel, Utf8AsUtf16Write) {
+    std::string token = "asdf";
+    parcelOpSameLength([&] (Parcel* p) {
+        p->writeUtf8AsUtf16(token);
+    }, [&] (Parcel* p) {
+        String16 s;
+        EXPECT_EQ(OK, p->readString16(&s));
+        EXPECT_EQ(s, String16(token.c_str()));
+    });
+}
+
+template <typename T>
+using readFunc = status_t (Parcel::*)(T* out) const;
+template <typename T>
+using writeFunc = status_t (Parcel::*)(const T& in);
+template <typename T>
+using copyWriteFunc = status_t (Parcel::*)(T in);
+
+template <typename T, typename WRITE_FUNC>
+void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, WRITE_FUNC w) {
+    for (const T& value : ts) {
+        parcelOpSameLength([&] (Parcel* p) {
+            (*p.*w)(value);
+        }, [&] (Parcel* p) {
+            T outValue;
+            EXPECT_EQ(OK, (*p.*r)(&outValue));
+            EXPECT_EQ(value, outValue);
+        });
+    }
+}
+
+template <typename T>
+void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, writeFunc<T> w) {
+    readWriteInverse<T, writeFunc<T>>(std::move(ts), r, w);
+}
+template <typename T>
+void readWriteInverse(std::vector<T>&& ts, readFunc<T> r, copyWriteFunc<T> w) {
+    readWriteInverse<T, copyWriteFunc<T>>(std::move(ts), r, w);
+}
+
+#define TEST_READ_WRITE_INVERSE(type, name, ...) \
+    TEST(Parcel, Inverse##name) { \
+        readWriteInverse<type>(__VA_ARGS__, &Parcel::read##name, &Parcel::write##name); \
+    }
+
+TEST_READ_WRITE_INVERSE(int32_t, Int32, {-2, -1, 0, 1, 2});
+TEST_READ_WRITE_INVERSE(uint32_t, Uint32, {0, 1, 2});
+TEST_READ_WRITE_INVERSE(int64_t, Int64, {-2, -1, 0, 1, 2});
+TEST_READ_WRITE_INVERSE(uint64_t, Uint64, {0, 1, 2});
+TEST_READ_WRITE_INVERSE(float, Float, {-1.0f, 0.0f, 3.14f});
+TEST_READ_WRITE_INVERSE(double, Double, {-1.0, 0.0, 3.14});
+TEST_READ_WRITE_INVERSE(bool, Bool, {true, false});
+TEST_READ_WRITE_INVERSE(char16_t, Char, {u'a', u'\0'});
+TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1});
+TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")});
+TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index 09f58cc..ffb3ef2 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -36,12 +36,15 @@
 #include <optional>
 
 #include <sys/eventfd.h>
+#include <sys/prctl.h>
 
 using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
 
 namespace android {
 namespace tests {
 
+static const String16 kServiceName("SafeInterfaceTest");
+
 enum class TestEnum : uint32_t {
     INVALID = 0,
     INITIAL = 1,
@@ -184,7 +187,7 @@
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wexit-time-destructors"
-IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback")
 #pragma clang diagnostic pop
 
 class BnCallback : public SafeBnInterface<ICallback> {
@@ -373,7 +376,7 @@
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wexit-time-destructors"
-IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest")
 
 static sp<IBinder::DeathRecipient> getDeathRecipient() {
     static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
@@ -601,40 +604,13 @@
     static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
 
     sp<ISafeInterfaceTest> getRemoteService() {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wexit-time-destructors"
-        static std::mutex sMutex;
-        static sp<ISafeInterfaceTest> sService;
-        static sp<IBinder> sDeathToken = new BBinder;
-#pragma clang diagnostic pop
+        sp<IBinder> binder = defaultServiceManager()->getService(kServiceName);
+        sp<ISafeInterfaceTest> iface = interface_cast<ISafeInterfaceTest>(binder);
+        EXPECT_TRUE(iface != nullptr);
 
-        std::unique_lock<decltype(sMutex)> lock;
-        if (sService == nullptr) {
-            ALOG(LOG_INFO, getLogTag(), "Forking remote process");
-            pid_t forkPid = fork();
-            EXPECT_NE(forkPid, -1);
+        iface->setDeathToken(new BBinder);
 
-            const String16 serviceName("SafeInterfaceTest");
-
-            if (forkPid == 0) {
-                ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
-                sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
-                defaultServiceManager()->addService(serviceName,
-                                                    IInterface::asBinder(nativeService));
-                ProcessState::self()->startThreadPool();
-                IPCThreadState::self()->joinThreadPool();
-                // We shouldn't get to this point
-                [&]() { FAIL(); }();
-            }
-
-            sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
-            sService = interface_cast<ISafeInterfaceTest>(binder);
-            EXPECT_TRUE(sService != nullptr);
-
-            sService->setDeathToken(sDeathToken);
-        }
-
-        return sService;
+        return iface;
     }
 };
 
@@ -840,5 +816,23 @@
     ASSERT_EQ(b + 1, bPlusOne);
 }
 
+extern "C" int main(int argc, char **argv) {
+    testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        sp<BnSafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+        status_t status = defaultServiceManager()->addService(kServiceName, nativeService);
+        if (status != OK) {
+            ALOG(LOG_INFO, "SafeInterfaceServer", "could not register");
+            return EXIT_FAILURE;
+        }
+        IPCThreadState::self()->joinThreadPool();
+        return EXIT_FAILURE;
+    }
+
+    return RUN_ALL_TESTS();
+}
+
 } // namespace tests
 } // namespace android
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index b790997..3b1faa8 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -116,7 +116,7 @@
         if (time > max_time_bucket) {
             m_long_transactions++;
         }
-        m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
+        m_buckets[min((uint32_t)(time / time_per_bucket), num_buckets - 1)] += 1;
         m_best = min(time, m_best);
         m_worst = max(time, m_worst);
         m_transactions += 1;
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..5531296
--- /dev/null
+++ b/libs/binder/tests/fuzzers/Android.bp
@@ -0,0 +1,86 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "binder_fuzz_defaults",
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libbase",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    }
+}
+
+cc_fuzz {
+    name: "binder_binderFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["BinderFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_bpBinderFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    host_supported: false,
+    srcs: ["BpBinderFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_persistableBundleFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["PersistableBundleFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_stabilityFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["StabilityFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_statusFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["StatusFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_textOutputFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["TextOutputFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_bufferedTextOutputFuzz",
+    include_dirs: [
+        "frameworks/native/libs/binder",
+    ],
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["BufferedTextOutputFuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "binder_memoryDealerFuzz",
+    defaults: ["binder_fuzz_defaults"],
+    srcs: ["MemoryDealerFuzz.cpp"],
+}
diff --git a/libs/binder/tests/fuzzers/BinderFuzz.cpp b/libs/binder/tests/fuzzers/BinderFuzz.cpp
new file mode 100644
index 0000000..1e5d80a
--- /dev/null
+++ b/libs/binder/tests/fuzzers/BinderFuzz.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BinderFuzzFunctions.h>
+#include <IBinderFuzzFunctions.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/Binder.h>
+
+namespace android {
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    sp<BBinder> bbinder = new BBinder();
+
+    // To prevent memory from running out from calling too many add item operations.
+    const uint32_t MAX_RUNS = 2048;
+    uint32_t count = 0;
+
+    while (fdp.remaining_bytes() > 0 && count++ < MAX_RUNS) {
+        if (fdp.ConsumeBool()) {
+            callArbitraryFunction(&fdp, gBBinderOperations, bbinder);
+        } else {
+            callArbitraryFunction(&fdp, gIBinderOperations,
+                                  reinterpret_cast<IBinder *>(bbinder.get()));
+        }
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
new file mode 100644
index 0000000..69f1b9d
--- /dev/null
+++ b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <IBinderFuzzFunctions.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <stdint.h>
+#include <atomic>
+
+namespace android {
+
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<std::function<void(FuzzedDataProvider*, const sp<BBinder>&)>>
+        gBBinderOperations = {[](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->isRequestingSid();
+                              },
+                              [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+                                  bool requestSid = fdp->ConsumeBool();
+                                  bbinder->setRequestingSid(requestSid);
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->getExtension();
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  static IBinder* extension = nullptr;
+                                  bbinder->setExtension(extension);
+                              },
+                              [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+                                  int priority;
+                                  int policy = fdp->ConsumeIntegralInRange<int>(0, 2);
+                                  if (policy == 0) {
+                                      priority = fdp->ConsumeIntegralInRange<int>(-20, 19);
+                                  } else {
+                                      priority = fdp->ConsumeIntegralInRange<int>(1, 99);
+                                  }
+                                  bbinder->setMinSchedulerPolicy(policy, priority);
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->getMinSchedulerPolicy();
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->getMinSchedulerPriority();
+                              },
+                              [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+                                  bool inheritRt = fdp->ConsumeBool();
+                                  bbinder->setInheritRt(inheritRt);
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->isInheritRt();
+                              },
+                              [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+                                  bbinder->getDebugPid();
+                              }};
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/fuzzers/BpBinderFuzz.cpp
new file mode 100644
index 0000000..c50279b
--- /dev/null
+++ b/libs/binder/tests/fuzzers/BpBinderFuzz.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BpBinderFuzzFunctions.h>
+#include <IBinderFuzzFunctions.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    // TODO: In the future it would be more effective to fork a new process and then pass a BBinder
+    // to your process. Right now this is not implemented because it would involved fuzzing IPC on a
+    // forked process, and libfuzzer will not be able to handle code coverage. This would lead to
+    // crashes that are not easy to diagnose.
+    int32_t handle = fdp.ConsumeIntegralInRange<int32_t>(0, 1024);
+    sp<BpBinder> bpbinder = BpBinder::create(handle);
+    if (bpbinder == nullptr) return 0;
+
+    // To prevent memory from running out from calling too many add item operations.
+    const uint32_t MAX_RUNS = 2048;
+    uint32_t count = 0;
+    sp<IBinder::DeathRecipient> s_recipient = new FuzzDeathRecipient();
+
+    while (fdp.remaining_bytes() > 0 && count++ < MAX_RUNS) {
+        if (fdp.ConsumeBool()) {
+            callArbitraryFunction(&fdp, gBPBinderOperations, bpbinder, s_recipient);
+        } else {
+            callArbitraryFunction(&fdp, gIBinderOperations, bpbinder.get());
+        }
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
new file mode 100644
index 0000000..6ca0e2f
--- /dev/null
+++ b/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <IBinderFuzzFunctions.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/BpBinder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+
+#include <cutils/compiler.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/threads.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// Static variable to reference so we don't consume a bunch of memory to link and
+// unlink DeathRecipients.
+static int8_t kBpBinderCookie = 0;
+
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<std::function<void(FuzzedDataProvider*, const sp<BpBinder>&,
+                                            const sp<IBinder::DeathRecipient>&)>>
+        gBPBinderOperations =
+                {[](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>& s_recipient) -> void {
+                     // Clean up possible leftover memory.
+                     wp<IBinder::DeathRecipient> outRecipient(nullptr);
+                     bpbinder->sendObituary();
+                     bpbinder->unlinkToDeath(nullptr, reinterpret_cast<void*>(&kBpBinderCookie), 0,
+                                             &outRecipient);
+
+                     uint32_t flags = fdp->ConsumeIntegral<uint32_t>();
+                     kBpBinderCookie = fdp->ConsumeIntegral<int8_t>();
+                     bpbinder->linkToDeath(s_recipient.get(),
+                                           reinterpret_cast<void*>(&kBpBinderCookie), flags);
+                 },
+                 [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     wp<IBinder::DeathRecipient> out_recipient(nullptr);
+                     uint32_t flags = fdp->ConsumeIntegral<uint32_t>();
+                     int8_t random_cookie = fdp->ConsumeIntegral<int8_t>();
+                     bpbinder->unlinkToDeath(nullptr, reinterpret_cast<void*>(&random_cookie),
+                                             flags, &out_recipient);
+                 },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->remoteBinder(); },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->sendObituary(); },
+                 [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     uint32_t uid = fdp->ConsumeIntegral<uint32_t>();
+                     bpbinder->getBinderProxyCount(uid);
+                 },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->enableCountByUid(); },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->disableCountByUid(); },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     Vector<uint32_t> uids;
+                     Vector<uint32_t> counts;
+                     bpbinder->getCountByUid(uids, counts);
+                 },
+                 [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     bool enable = fdp->ConsumeBool();
+                     bpbinder->setCountByUidEnabled(enable);
+                 },
+                 [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     binder_proxy_limit_callback cb = binder_proxy_limit_callback();
+                     bpbinder->setLimitCallback(cb);
+                 },
+                 [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     int high = fdp->ConsumeIntegral<int>();
+                     int low = fdp->ConsumeIntegral<int>();
+                     bpbinder->setBinderProxyCountWatermarks(high, low);
+                 }};
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp b/libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp
new file mode 100644
index 0000000..09cb216
--- /dev/null
+++ b/libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <string>
+#include <vector>
+#include "BufferedTextOutput.h"
+
+namespace android {
+
+class FuzzBufferedTextOutput : public BufferedTextOutput {
+public:
+    FuzzBufferedTextOutput(uint32_t flags) : BufferedTextOutput(flags) {}
+    virtual status_t writeLines(const struct iovec& buf, size_t) {
+        size_t len = buf.iov_len;
+        void* tmp_buf = malloc(len);
+
+        if (tmp_buf == NULL) {
+            return status_t();
+        }
+
+        // This will attempt to read data from iov_base to ensure valid params were passed.
+        memcpy(tmp_buf, buf.iov_base, len);
+        free(tmp_buf);
+        return status_t();
+    }
+};
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    uint32_t flags = fdp.ConsumeIntegral<uint32_t>();
+    size_t push_count = 0;
+    std::shared_ptr<BufferedTextOutput> bTextOutput(new FuzzBufferedTextOutput(flags));
+
+    while (fdp.remaining_bytes() > 0) {
+        fdp.PickValueInArray<std::function<void()>>({
+                [&]() -> void {
+                    bTextOutput->pushBundle();
+                    push_count++;
+                },
+                [&]() -> void {
+                    std::string txt = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+                    size_t len = fdp.ConsumeIntegralInRange<size_t>(0, txt.length());
+                    bTextOutput->print(txt.c_str(), len);
+                },
+                [&]() -> void {
+                    if (push_count == 0) return;
+
+                    bTextOutput->popBundle();
+                    push_count--;
+                },
+        })();
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/fuzzers/IBinderFuzzFunctions.h
new file mode 100644
index 0000000..626b758
--- /dev/null
+++ b/libs/binder/tests/fuzzers/IBinderFuzzFunctions.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <cutils/compiler.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class FuzzDeathRecipient : public IBinder::DeathRecipient {
+private:
+    virtual void binderDied(const wp<IBinder>& who) { (void)who; };
+};
+
+// Allow objects to be attached that aren't stack locals
+static uint32_t objectID = 0;
+static uint32_t object = 0;
+static uint32_t cleanup_cookie = 0;
+
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<std::function<void(FuzzedDataProvider*, IBinder*)>> gIBinderOperations =
+        {[](FuzzedDataProvider*, IBinder* ibinder) -> void { ibinder->getInterfaceDescriptor(); },
+         [](FuzzedDataProvider*, IBinder* ibinder) -> void { ibinder->isBinderAlive(); },
+         [](FuzzedDataProvider*, IBinder* ibinder) -> void { ibinder->pingBinder(); },
+         [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
+             int fd = STDOUT_FILENO;
+             std::string rand_str = fdp->ConsumeRandomLengthString(fdp->remaining_bytes());
+             Vector<String16> args;
+             args.push(String16(rand_str.c_str()));
+             ibinder->dump(fd, args);
+         },
+         [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
+             objectID = fdp->ConsumeIntegral<uint32_t>();
+             object = fdp->ConsumeIntegral<uint32_t>();
+             cleanup_cookie = fdp->ConsumeIntegral<uint32_t>();
+             IBinder::object_cleanup_func func = IBinder::object_cleanup_func();
+             ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
+                                                      : nullptr,
+                                   fdp->ConsumeBool() ? reinterpret_cast<void*>(&object) : nullptr,
+                                   fdp->ConsumeBool() ? reinterpret_cast<void*>(&cleanup_cookie)
+                                                      : nullptr,
+                                   func);
+         },
+         [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
+             uint32_t id = fdp->ConsumeIntegral<uint32_t>();
+             ibinder->findObject(reinterpret_cast<void*>(&id));
+         },
+         [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
+             uint32_t id = fdp->ConsumeIntegral<uint32_t>();
+             ibinder->detachObject(reinterpret_cast<void*>(&id));
+         },
+         [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
+             uint32_t code = fdp->ConsumeIntegral<uint32_t>();
+             Parcel p_data;
+             Parcel reply;
+             uint32_t flags = fdp->ConsumeIntegral<uint32_t>();
+             ibinder->transact(code, p_data, &reply, flags);
+         }};
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp b/libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp
new file mode 100644
index 0000000..f9dda8c
--- /dev/null
+++ b/libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/MemoryDealer.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <string>
+#include <unordered_set>
+
+namespace android {
+
+static constexpr size_t kMaxBufferSize = 10000;
+static constexpr size_t kMaxDealerSize = 1024 * 512;
+static constexpr size_t kMaxAllocSize = 1024;
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size > kMaxBufferSize) {
+        return 0;
+    }
+
+    FuzzedDataProvider fdp(data, size);
+    size_t dSize = fdp.ConsumeIntegralInRange<size_t>(0, kMaxDealerSize);
+    std::string name = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+    uint32_t flags = fdp.ConsumeIntegral<uint32_t>();
+    sp<MemoryDealer> dealer = new MemoryDealer(dSize, name.c_str(), flags);
+
+    // This is used to track offsets that have been freed already to avoid an expected fatal log.
+    std::unordered_set<size_t> free_list;
+
+    while (fdp.remaining_bytes() > 0) {
+        fdp.PickValueInArray<std::function<void()>>({
+                [&]() -> void { dealer->getAllocationAlignment(); },
+                [&]() -> void { dealer->getMemoryHeap(); },
+                [&]() -> void {
+                    size_t offset = fdp.ConsumeIntegral<size_t>();
+
+                    // Offset has already been freed, so return instead.
+                    if (free_list.find(offset) != free_list.end()) return;
+
+                    dealer->deallocate(offset);
+                    free_list.insert(offset);
+                },
+                [&]() -> void {
+                    std::string randString = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+                    dealer->dump(randString.c_str());
+                },
+                [&]() -> void {
+                    size_t allocSize = fdp.ConsumeIntegralInRange<size_t>(0, kMaxAllocSize);
+                    sp<IMemory> allocated = dealer->allocate(allocSize);
+                    // If the allocation was successful, try to write to it
+                    if (allocated != nullptr && allocated->unsecurePointer() != nullptr) {
+                        memset(allocated->unsecurePointer(), 1, allocated->size());
+
+                        // Clear the address from freelist since it has been allocated over again.
+                        free_list.erase(allocated->offset());
+                    }
+                },
+        })();
+    }
+
+    return 0;
+}
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp b/libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp
new file mode 100644
index 0000000..4843c46
--- /dev/null
+++ b/libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <PersistableBundleFuzzFunctions.h>
+#include <binder/PersistableBundle.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/String16.h>
+
+namespace android {
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    std::shared_ptr<os::PersistableBundle> p_bundle(new os::PersistableBundle());
+
+    while (fdp.remaining_bytes() > 0) {
+        String16 key(fdp.ConsumeRandomLengthString(fdp.remaining_bytes()).c_str());
+        callArbitraryFunction(&fdp, gPersistableBundleOperations, p_bundle, &key);
+    }
+
+    return 0;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h b/libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h
new file mode 100644
index 0000000..820e9e8
--- /dev/null
+++ b/libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <map>
+#include <set>
+#include <vector>
+
+namespace android {
+
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<std::function<
+        void(FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const&, String16*)>>
+        gPersistableBundleOperations =
+                {[](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16*) -> void { p_bundle->empty(); },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16*) -> void {
+                     Parcel parcel;
+                     p_bundle->writeToParcel(&parcel);
+                 },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16*) -> void {
+                     Parcel parcel;
+                     std::vector<uint8_t> buf = fdp->ConsumeBytes<uint8_t>(
+                             fdp->ConsumeIntegralInRange<size_t>(0, fdp->remaining_bytes() - 1));
+                     parcel.write(buf.data(), buf.size());
+                     p_bundle->readFromParcel(&parcel);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16*) -> void { p_bundle->size(); },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void { p_bundle->erase(*key); },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     bool value = fdp->ConsumeBool();
+                     p_bundle->putBoolean(*key, value);
+                 },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     int32_t value = fdp->ConsumeIntegral<int32_t>();
+                     p_bundle->putInt(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     os::PersistableBundle value = os::PersistableBundle();
+                     p_bundle->putPersistableBundle(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<String16> value;
+                     p_bundle->putStringVector(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<double> value;
+                     p_bundle->putDoubleVector(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<int64_t> value;
+                     p_bundle->putLongVector(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<int32_t> value;
+                     p_bundle->putIntVector(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<bool> value;
+                     p_bundle->putBooleanVector(*key, value);
+                 },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     String16 value(fdp->ConsumeRandomLengthString(fdp->remaining_bytes()).c_str());
+                     p_bundle->putString(*key, value);
+                 },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     int64_t value = fdp->ConsumeIntegral<int64_t>();
+                     p_bundle->putLong(*key, value);
+                 },
+                 [](FuzzedDataProvider* fdp, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     double value = fdp->ConsumeFloatingPoint<double>();
+                     p_bundle->putDouble(*key, value);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     bool out;
+                     p_bundle->getBoolean(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     os::PersistableBundle out;
+                     p_bundle->getPersistableBundle(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<String16> out;
+                     p_bundle->getStringVector(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<double> out;
+                     p_bundle->getDoubleVector(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<int64_t> out;
+                     p_bundle->getLongVector(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<int32_t> out;
+                     p_bundle->getIntVector(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     std::vector<bool> out;
+                     p_bundle->getBooleanVector(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     String16 out;
+                     p_bundle->getString(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     double out;
+                     p_bundle->getDouble(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     int64_t out;
+                     p_bundle->getLong(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16* key) -> void {
+                     int32_t out;
+                     p_bundle->getInt(*key, &out);
+                 },
+                 [](FuzzedDataProvider*, std::shared_ptr<os::PersistableBundle> const& p_bundle,
+                    String16*) -> void {
+                     p_bundle->getBooleanKeys();
+                     p_bundle->getIntKeys();
+                     p_bundle->getLongKeys();
+                     p_bundle->getDoubleKeys();
+                     p_bundle->getStringKeys();
+                     p_bundle->getBooleanVectorKeys();
+                     p_bundle->getIntVectorKeys();
+                     p_bundle->getLongVectorKeys();
+                     p_bundle->getDoubleVectorKeys();
+                     p_bundle->getStringVectorKeys();
+                     p_bundle->getPersistableBundleKeys();
+                 }};
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/StabilityFuzz.cpp b/libs/binder/tests/fuzzers/StabilityFuzz.cpp
new file mode 100644
index 0000000..8ad9b44
--- /dev/null
+++ b/libs/binder/tests/fuzzers/StabilityFuzz.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <StabilityFuzzFunctions.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    // Init our wrapper
+    FuzzedDataProvider dataProvider(data, size);
+    android::sp<android::IBinder> bbinder = new android::BBinder();
+
+    // Call some functions
+    while (dataProvider.remaining_bytes() > 0) {
+        callArbitraryFunction(&dataProvider, gStabilityOperations, bbinder);
+    }
+
+    return 0;
+}
diff --git a/libs/binder/tests/fuzzers/StabilityFuzzFunctions.h b/libs/binder/tests/fuzzers/StabilityFuzzFunctions.h
new file mode 100644
index 0000000..8b4ed70
--- /dev/null
+++ b/libs/binder/tests/fuzzers/StabilityFuzzFunctions.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Binder.h>
+#include <binder/Stability.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#define STABILITY_MAX_TAG_LENGTH 2048
+static bool marked = false;
+
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<
+        std::function<void(FuzzedDataProvider*, android::sp<android::IBinder> const&)>>
+        gStabilityOperations = {
+                // markCompilationUnit(IBinder* binder)
+                [](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
+                    if (!marked) {
+                        android::internal::Stability::markCompilationUnit(bbinder.get());
+                        marked = true;
+                    }
+                },
+
+                // markVintf(IBinder* binder)
+                [](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
+                    if (!marked) {
+                        android::internal::Stability::markVintf(bbinder.get());
+                        marked = true;
+                    }
+                },
+
+                // debugLogStability(const std::string& tag, const sp<IBinder>& binder)
+                [](FuzzedDataProvider* fdp, android::sp<android::IBinder> const& bbinder) -> void {
+                    std::string tag = fdp->ConsumeRandomLengthString(STABILITY_MAX_TAG_LENGTH);
+                    android::internal::Stability::debugLogStability(tag, bbinder);
+                },
+
+                // markVndk(IBinder* binder)
+                [](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
+                    if (!marked) {
+                        android::internal::Stability::markVndk(bbinder.get());
+                        marked = true;
+                    }
+                },
+
+                // requiresVintfDeclaration(const sp<IBinder>& binder)
+                [](FuzzedDataProvider*, android::sp<android::IBinder> const& bbinder) -> void {
+                    android::internal::Stability::requiresVintfDeclaration(bbinder);
+                }};
diff --git a/libs/binder/tests/fuzzers/StatusFuzz.cpp b/libs/binder/tests/fuzzers/StatusFuzz.cpp
new file mode 100644
index 0000000..4f6ad6f
--- /dev/null
+++ b/libs/binder/tests/fuzzers/StatusFuzz.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <StatusFuzzFunctions.h>
+#include <binder/Parcel.h>
+#include <binder/Status.h>
+#include <commonFuzzHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/String8.h>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+namespace android {
+// Fuzzer entry point.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    int32_t exceptionCode = fdp.ConsumeIntegral<int32_t>();
+    std::string message_str = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+    String8 message(message_str.c_str());
+
+    Parcel parcel;
+    std::vector<uint8_t> buf = fdp.ConsumeBytes<uint8_t>(
+            fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes() - 1));
+    parcel.write(buf.data(), buf.size());
+    binder::Status status = binder::Status::fromExceptionCode(exceptionCode, message);
+
+    while (fdp.remaining_bytes() > 0) {
+        callArbitraryFunction(&fdp, gStatusOperations, &status, &parcel);
+    }
+    return 0;
+}
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/StatusFuzzFunctions.h b/libs/binder/tests/fuzzers/StatusFuzzFunctions.h
new file mode 100644
index 0000000..bc8d17a
--- /dev/null
+++ b/libs/binder/tests/fuzzers/StatusFuzzFunctions.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/Parcel.h>
+#include <binder/Status.h>
+#include <stdio.h>
+#include <utils/String8.h>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+namespace android {
+/* This is a vector of lambda functions the fuzzer will pull from.
+ *  This is done so new functions can be added to the fuzzer easily
+ *  without requiring modifications to the main fuzzer file. This also
+ *  allows multiple fuzzers to include this file, if functionality is needed.
+ */
+static const std::vector<std::function<void(FuzzedDataProvider*, binder::Status*, Parcel*)>>
+        gStatusOperations = {
+                [](FuzzedDataProvider*, binder::Status* status, Parcel* parcel) -> void {
+                    parcel->setDataPosition(0);
+                    status->readFromParcel(*parcel);
+                },
+                [](FuzzedDataProvider*, binder::Status* status, Parcel* parcel) -> void {
+                    status->writeToParcel(parcel);
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    std::string message_str =
+                            fdp->ConsumeRandomLengthString(fdp->remaining_bytes());
+                    String8 message(message_str.c_str());
+                    status->setServiceSpecificError(fdp->ConsumeIntegral<int32_t>(), message);
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    std::string message_str =
+                            fdp->ConsumeRandomLengthString(fdp->remaining_bytes());
+                    String8 message(message_str.c_str());
+                    status->setException(fdp->ConsumeIntegral<int32_t>(), message);
+                },
+                [](FuzzedDataProvider*, binder::Status* status, Parcel*) -> void { status->ok(); },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    std::string message_str =
+                            fdp->ConsumeRandomLengthString(fdp->remaining_bytes());
+                    String8 message(message_str.c_str());
+                    *status = binder::Status::fromExceptionCode(fdp->ConsumeIntegral<int32_t>(),
+                                                                message);
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    *status = binder::Status::fromServiceSpecificError(
+                            fdp->ConsumeIntegral<int32_t>());
+                },
+                [](FuzzedDataProvider* fdp, binder::Status*, Parcel*) -> void {
+                    binder::Status::exceptionToString(fdp->ConsumeIntegral<int32_t>());
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    std::string message_str =
+                            fdp->ConsumeRandomLengthString(fdp->remaining_bytes());
+                    String8 message(message_str.c_str());
+                    *status = binder::Status::fromServiceSpecificError(fdp->ConsumeIntegral<
+                                                                               int32_t>(),
+                                                                       message);
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    *status = binder::Status::fromStatusT(fdp->ConsumeIntegral<status_t>());
+                },
+                [](FuzzedDataProvider* fdp, binder::Status* status, Parcel*) -> void {
+                    status->setFromStatusT(fdp->ConsumeIntegral<status_t>());
+                },
+                [](FuzzedDataProvider*, binder::Status* status, Parcel*) -> void {
+                    std::stringstream ss;
+                    ss << *status;
+                },
+};
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/TextOutputFuzz.cpp b/libs/binder/tests/fuzzers/TextOutputFuzz.cpp
new file mode 100644
index 0000000..c950020
--- /dev/null
+++ b/libs/binder/tests/fuzzers/TextOutputFuzz.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <binder/Debug.h>
+#include <binder/Parcel.h>
+#include <binder/TextOutput.h>
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstddef>
+#include <limits>
+
+// Fuzzer for the TextOutput class. These were lifted from the existing
+// test suite.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    CapturedStderr cap;
+
+    while (fdp.remaining_bytes() > 1) {
+        switch (fdp.ConsumeIntegral<uint8_t>() % 3) {
+            case 0: {
+                std::string input = fdp.ConsumeBytesAsString(
+                        fdp.ConsumeIntegralInRange<size_t>(0, fdp.remaining_bytes()));
+                android::aerr << input << android::endl;
+                break;
+            }
+            case 1: {
+                std::string str = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+                android::HexDump input(str.c_str(), sizeof(str.c_str()));
+                android::aerr << input << android::endl;
+                break;
+            }
+            case 2: {
+                android::TypeCode input(fdp.ConsumeIntegral<uint32_t>());
+                android::aerr << input << android::endl;
+            }
+        }
+    }
+    cap.Stop();
+
+    return 0;
+}
diff --git a/libs/binder/tests/fuzzers/commonFuzzHelpers.h b/libs/binder/tests/fuzzers/commonFuzzHelpers.h
new file mode 100644
index 0000000..d58d9b6
--- /dev/null
+++ b/libs/binder/tests/fuzzers/commonFuzzHelpers.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vector>
+
+// Calls a function from the ops_vector
+template <class F, class T, class... Types>
+void callArbitraryFunction(F* fdp, T const& ops_vector, Types... args) {
+    // Choose which function we'll be calling
+    uint8_t function_id = fdp->template ConsumeIntegralInRange<uint8_t>(0, ops_vector.size() - 1);
+
+    // Call the function we've chosen
+    ops_vector[function_id](fdp, args...);
+}
+
+template <class T>
+T getArbitraryVectorElement(FuzzedDataProvider* fdp, std::vector<T> const& vect, bool allow_null) {
+    // If we're allowing null, give it a 50:50 shot at returning a nullptr
+    if (vect.empty() || (allow_null && fdp->ConsumeBool())) {
+        return nullptr;
+    }
+
+    // Otherwise, return an element from our vector
+    return vect.at(fdp->ConsumeIntegralInRange<size_t>(0, vect.size() - 1));
+}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index ab4c56a..56d958c 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -245,7 +245,7 @@
     double best = (double)m_best / 1.0E6;
     double worst = (double)m_worst / 1.0E6;
     double average = (double)m_total_time / m_transactions / 1.0E6;
-    // FIXME: libjson?
+    // TODO: libjson?
     int W = DUMP_PRESICION + 2;
     cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
          << average << ",\"wst\":" << setw(W) << left << worst
@@ -376,7 +376,7 @@
   if (is_client(num)) {
     int no_trans = iterations * 2;
     double sync_ratio = (1.0 - (double)no_sync / no_trans);
-    // FIXME: libjson?
+    // TODO: libjson?
     cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
          << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
          << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
@@ -466,7 +466,7 @@
   }
   vector<Pipe> pipes;
   thread_dump("main");
-  // FIXME: libjson?
+  // TODO: libjson?
   cout << "{" << endl;
   cout << "\"cfg\":{\"pair\":" << (no_process / 2)
        << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
@@ -495,7 +495,7 @@
     // detected in the child process
     no_inherent += status;
   }
-  // FIXME: libjson?
+  // TODO: libjson?
   cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
        << endl;
   cout << "}" << endl;
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
new file mode 100644
index 0000000..343246a
--- /dev/null
+++ b/libs/binderdebug/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+    name: "libbinderdebug",
+    vendor_available: true,
+    shared_libs: [
+        "libbase",
+        "libbinder",
+    ],
+    srcs: [
+        "BinderDebug.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
new file mode 100644
index 0000000..b435dba
--- /dev/null
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <binder/Binder.h>
+#include <sys/types.h>
+#include <fstream>
+#include <regex>
+
+#include <binderdebug/BinderDebug.h>
+
+namespace android {
+
+static std::string contextToString(BinderDebugContext context) {
+    switch (context) {
+        case BinderDebugContext::BINDER:
+            return "binder";
+        case BinderDebugContext::HWBINDER:
+            return "hwbinder";
+        case BinderDebugContext::VNDBINDER:
+            return "vndbinder";
+        default:
+            return std::string();
+    }
+}
+
+static status_t scanBinderContext(pid_t pid, const std::string& contextName,
+                                  std::function<void(const std::string&)> eachLine) {
+    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
+    if (!ifs.is_open()) {
+        ifs.open("/d/binder/proc/" + std::to_string(pid));
+        if (!ifs.is_open()) {
+            return -errno;
+        }
+    }
+    static const std::regex kContextLine("^context (\\w+)$");
+
+    bool isDesiredContext = false;
+    std::string line;
+    std::smatch match;
+    while (getline(ifs, line)) {
+        if (std::regex_search(line, match, kContextLine)) {
+            isDesiredContext = match.str(1) == contextName;
+            continue;
+        }
+        if (!isDesiredContext) {
+            continue;
+        }
+        eachLine(line);
+    }
+    return OK;
+}
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
+    std::smatch match;
+    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+    std::string contextStr = contextToString(context);
+    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+        if (std::regex_search(line, match, kReferencePrefix)) {
+            const std::string& ptrString = "0x" + match.str(2); // use number after c
+            uint64_t ptr;
+            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+                // Should not reach here, but just be tolerant.
+                return;
+            }
+            const std::string proc = " proc ";
+            auto pos = line.rfind(proc);
+            if (pos != std::string::npos) {
+                for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
+                    int32_t pid;
+                    if (!::android::base::ParseInt(pidStr, &pid)) {
+                        return;
+                    }
+                    pidInfo->refPids[ptr].push_back(pid);
+                }
+            }
+
+            return;
+        }
+        if (std::regex_search(line, match, kThreadPrefix)) {
+            // "1" is waiting in binder driver
+            // "2" is poll. It's impossible to tell if these are in use.
+            //     and HIDL default code doesn't use it.
+            bool isInUse = match.str(1) != "1";
+            // "0" is a thread that has called into binder
+            // "1" is looper thread
+            // "2" is main looper thread
+            bool isBinderThread = match.str(2) != "0";
+            if (!isBinderThread) {
+                return;
+            }
+            if (isInUse) {
+                pidInfo->threadUsage++;
+            }
+
+            pidInfo->threadCount++;
+            return;
+        }
+        return;
+    });
+    return ret;
+}
+
+} // namespace  android
diff --git a/libs/binderdebug/TEST_MAPPING b/libs/binderdebug/TEST_MAPPING
new file mode 100644
index 0000000..2f3353e
--- /dev/null
+++ b/libs/binderdebug/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "libbinderdebug_test"
+    }
+  ]
+}
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
new file mode 100644
index 0000000..14a0ef3
--- /dev/null
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <map>
+#include <vector>
+
+namespace android {
+
+struct BinderPidInfo {
+    std::map<uint64_t, std::vector<pid_t>> refPids; // cookie -> processes which hold binder
+    uint32_t threadUsage;                           // number of threads in use
+    uint32_t threadCount;                           // number of threads total
+};
+
+enum class BinderDebugContext {
+    BINDER,
+    HWBINDER,
+    VNDBINDER,
+};
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+
+} // namespace  android
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
new file mode 100644
index 0000000..4c06b1d
--- /dev/null
+++ b/libs/binderdebug/tests/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "libbinderdebug_test",
+    test_suites: ["general-tests"],
+    srcs: [
+        "binderdebug_test.cpp",
+        "android/binderdebug/test/IControl.aidl",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+    static_libs: ["libbinderdebug"],
+    cflags: ["-Wall", "-Werror"],
+    require_root: true,
+}
diff --git a/libs/binder/fuzzer/parcel_fuzzer.h b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
similarity index 74%
copy from libs/binder/fuzzer/parcel_fuzzer.h
copy to libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
index 10cf17c..8efeb63 100644
--- a/libs/binder/fuzzer/parcel_fuzzer.h
+++ b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,5 +14,9 @@
  * limitations under the License.
  */
 
-template <typename P>
-using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+package android.binderdebug.test;
+
+interface IControl {
+    // Notifies the service to continue execution
+    void Continue();
+}
diff --git a/libs/binderdebug/tests/binderdebug_test.cpp b/libs/binderdebug/tests/binderdebug_test.cpp
new file mode 100644
index 0000000..ea799c0
--- /dev/null
+++ b/libs/binderdebug/tests/binderdebug_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/IPCThreadState.h>
+#include <binderdebug/BinderDebug.h>
+#include <gtest/gtest.h>
+#include <semaphore.h>
+#include <thread>
+
+#include <android/binderdebug/test/BnControl.h>
+#include <android/binderdebug/test/IControl.h>
+
+namespace android {
+namespace binderdebug {
+namespace test {
+
+class Control : public BnControl {
+public:
+    Control() {sem_init(&s, 1, 0);};
+    ::android::binder::Status Continue() override;
+    sem_t s;
+};
+
+::android::binder::Status Control::Continue() {
+    IPCThreadState::self()->flushCommands();
+    sem_post(&s);
+    return binder::Status::ok();
+}
+
+TEST(BinderDebugTests, BinderPid) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    // There should be one referenced PID for servicemanager
+    EXPECT_TRUE(!pidInfo.refPids.empty());
+}
+
+TEST(BinderDebugTests, BinderThreads) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    EXPECT_TRUE(pidInfo.threadUsage <= pidInfo.threadCount);
+    // The second looper thread can sometimes take longer to spawn.
+    EXPECT_GE(pidInfo.threadCount, 1);
+}
+
+extern "C" {
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Create a child/client process to call into the main process so we can ensure
+    // looper thread has been registered before attempting to get the BinderPidInfo
+    pid_t pid = fork();
+    if (pid == 0) {
+        sp<IBinder> binder = android::defaultServiceManager()->getService(String16("binderdebug"));
+        sp<IControl> service;
+        if (binder != nullptr) {
+            service = android::interface_cast<IControl>(binder);
+        }
+        service->Continue();
+        exit(0);
+    }
+    sp<Control> iface = new Control;
+    android::defaultServiceManager()->addService(String16("binderdebug"), iface);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+    ProcessState::self()->startThreadPool();
+    sem_wait(&iface->s);
+
+    return RUN_ALL_TESTS();
+}
+} // extern "C"
+} // namespace  test
+} // namespace  binderdebug
+} // namespace  android
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 88752ee..08c62df 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -19,6 +19,11 @@
     double_loadable: true,
     vendor_available: true,
     host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
 
     shared_libs: [
         "libbinder",
diff --git a/libs/binderthreadstate/test.cpp b/libs/binderthreadstate/test.cpp
index 68cc225..44e2fd1 100644
--- a/libs/binderthreadstate/test.cpp
+++ b/libs/binderthreadstate/test.cpp
@@ -165,7 +165,6 @@
     android::ProcessState::self()->startThreadPool();
 
     // HIDL
-    setenv("TREBLE_TESTING_OVERRIDE", "true", true);
     android::hardware::configureRpcThreadpool(1, true /*callerWillJoin*/);
     sp<IHidlStuff> hidlServer = new HidlServer(thisId, otherId);
     CHECK(OK == hidlServer->registerAsService(id2name(thisId).c_str()));
@@ -176,7 +175,7 @@
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+    android::hardware::details::setTrebleTestingOverride(true);
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
         return server(kP1Id, kP2Id);
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index b1943a4..e3cd085 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -33,5 +33,6 @@
         "-Wall",
         "-Wextra",
     ],
+    require_root: true,
 }
 
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 50f6289..462f0db 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -56,9 +56,11 @@
 static std::vector<std::vector<uint32_t>> gPolicyFreqs;
 static std::vector<std::vector<uint32_t>> gPolicyCpus;
 static std::set<uint32_t> gAllFreqs;
+static unique_fd gTisTotalMapFd;
 static unique_fd gTisMapFd;
 static unique_fd gConcurrentMapFd;
 static unique_fd gUidLastUpdateMapFd;
+static unique_fd gPidTisMapFd;
 
 static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
     std::string data;
@@ -97,7 +99,7 @@
     struct dirent **dirlist;
     const char basepath[] = "/sys/devices/system/cpu/cpufreq";
     int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
-    if (ret == -1) return false;
+    if (ret == -1 || ret == 0) return false;
     gNPolicies = ret;
 
     std::vector<std::string> policyFileNames;
@@ -128,6 +130,10 @@
         gPolicyCpus.emplace_back(*cpus);
     }
 
+    gTisTotalMapFd =
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_total_time_in_state_map")};
+    if (gTisTotalMapFd < 0) return false;
+
     gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
     if (gTisMapFd < 0) return false;
 
@@ -139,6 +145,12 @@
             unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
     if (gUidLastUpdateMapFd < 0) return false;
 
+    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_time_in_state_pid_time_in_state_map")};
+    if (gPidTisMapFd < 0) return false;
+
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    if (trackedPidMapFd < 0) return false;
+
     gInitialized = true;
     return true;
 }
@@ -222,7 +234,8 @@
     }
 
     gTracking = attachTracepointProgram("sched", "sched_switch") &&
-            attachTracepointProgram("power", "cpu_frequency");
+            attachTracepointProgram("power", "cpu_frequency") &&
+            attachTracepointProgram("sched", "sched_process_free");
     return gTracking;
 }
 
@@ -231,6 +244,31 @@
     return gPolicyFreqs;
 }
 
+std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes() {
+    if (!gInitialized && !initGlobals()) return {};
+
+    std::vector<std::vector<uint64_t>> out;
+    uint32_t maxFreqCount = 0;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+        out.emplace_back(freqList.size(), 0);
+    }
+
+    std::vector<uint64_t> vals(gNCpus);
+    const uint32_t freqCount = maxFreqCount <= MAX_FREQS_FOR_TOTAL ? maxFreqCount :
+            MAX_FREQS_FOR_TOTAL;
+    for (uint32_t freqIdx = 0; freqIdx < freqCount; ++freqIdx) {
+        if (findMapEntry(gTisTotalMapFd, &freqIdx, vals.data())) return {};
+        for (uint32_t policyIdx = 0; policyIdx < gNPolicies; ++policyIdx) {
+            if (freqIdx >= gPolicyFreqs[policyIdx].size()) continue;
+            for (const auto &cpu : gPolicyCpus[policyIdx]) {
+                out[policyIdx][freqIdx] += vals[cpu];
+            }
+        }
+    }
+
+    return out;
+}
 // Retrieve the times in ns that uid spent running at each CPU frequency.
 // Return contains no value on error, otherwise it contains a vector of vectors using the format:
 // [[t0_0, t0_1, ...],
@@ -251,7 +289,7 @@
     for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
         key.bucket = i;
         if (findMapEntry(gTisMapFd, &key, vals.data())) {
-            if (errno != ENOENT) return {};
+            if (errno != ENOENT || getFirstMapKey(gTisMapFd, &key)) return {};
             continue;
         }
 
@@ -362,7 +400,7 @@
     time_key_t key = {.uid = uid};
     for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
         if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
-            if (errno != ENOENT) return {};
+            if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &key)) return {};
             continue;
         }
         auto offset = key.bucket * CPUS_PER_ENTRY;
@@ -425,6 +463,7 @@
 
     uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
     do {
+        if (key.bucket > (gNCpus - 1) / CPUS_PER_ENTRY) return {};
         if (lastUpdate) {
             auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
             if (!uidUpdated.has_value()) return {};
@@ -501,5 +540,106 @@
     return true;
 }
 
+bool startTrackingProcessCpuTimes(pid_t pid) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    unique_fd trackedPidHashMapFd(
+            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_hash_map"));
+    if (trackedPidHashMapFd < 0) return false;
+
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    if (trackedPidMapFd < 0) return false;
+
+    for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
+        // Find first available [index, pid] entry in the pid_tracked_hash_map map
+        if (writeToMapEntry(trackedPidHashMapFd, &index, &pid, BPF_NOEXIST) != 0) {
+            if (errno != EEXIST) {
+                return false;
+            }
+            continue; // This index is already taken
+        }
+
+        tracked_pid_t tracked_pid = {.pid = pid, .state = TRACKED_PID_STATE_ACTIVE};
+        if (writeToMapEntry(trackedPidMapFd, &index, &tracked_pid, BPF_ANY) != 0) {
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+// Marks the specified task identified by its PID (aka TID) for CPU time-in-state tracking
+// aggregated with other tasks sharing the same TGID and aggregation key.
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    unique_fd taskAggregationMapFd(
+            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_task_aggregation_map"));
+    if (taskAggregationMapFd < 0) return false;
+
+    return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
+}
+
+// Retrieves the times in ns that each thread spent running at each CPU freq, aggregated by
+// aggregation key.
+// Return contains no value on error, otherwise it contains a map from aggregation keys
+// to vectors of vectors using the format:
+// { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+//   aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest freq.
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys) {
+    if (!gInitialized && !initGlobals()) return {};
+
+    uint32_t maxFreqCount = 0;
+    std::vector<std::vector<uint64_t>> mapFormat;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+        mapFormat.emplace_back(freqList.size(), 0);
+    }
+
+    bool dataCollected = false;
+    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
+    std::vector<tis_val_t> vals(gNCpus);
+    for (uint16_t aggregationKey : aggregationKeys) {
+        map.emplace(aggregationKey, mapFormat);
+
+        aggregated_task_tis_key_t key{.tgid = tgid, .aggregation_key = aggregationKey};
+        for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+            if (findMapEntry(gPidTisMapFd, &key, vals.data()) != 0) {
+                if (errno != ENOENT) {
+                    return {};
+                }
+                continue;
+            } else {
+                dataCollected = true;
+            }
+
+            // Combine data by aggregating time-in-state data grouped by CPU cluster aka policy.
+            uint32_t offset = key.bucket * FREQS_PER_ENTRY;
+            uint32_t nextOffset = offset + FREQS_PER_ENTRY;
+            for (uint32_t j = 0; j < gNPolicies; ++j) {
+                if (offset >= gPolicyFreqs[j].size()) continue;
+                auto begin = map[key.aggregation_key][j].begin() + offset;
+                auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY
+                                                               : map[key.aggregation_key][j].end();
+                for (const auto &cpu : gPolicyCpus[j]) {
+                    std::transform(begin, end, std::begin(vals[cpu].ar), begin,
+                                   std::plus<uint64_t>());
+                }
+            }
+        }
+    }
+
+    if (!dataCollected) {
+        // Check if eBPF is supported on this device. If it is, gTisMap should not be empty.
+        time_key_t key;
+        if (getFirstMapKey(gTisMapFd, &key) != 0) {
+            return {};
+        }
+    }
+    return map;
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index b7600f5..46de669 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -23,6 +23,7 @@
 namespace bpf {
 
 bool startTrackingUidTimes();
+std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
 std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
     getUidsCpuFreqTimes();
@@ -41,5 +42,10 @@
     getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate);
 bool clearUidTimes(unsigned int uid);
 
+bool startTrackingProcessCpuTimes(pid_t pid);
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys);
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index ea2a200..d25b2e9 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -19,6 +19,8 @@
 
 #include <sys/sysinfo.h>
 
+#include <pthread.h>
+#include <semaphore.h>
 #include <numeric>
 #include <unordered_map>
 #include <vector>
@@ -38,6 +40,12 @@
 
 using std::vector;
 
+TEST(TimeInStateTest, TotalTimeInState) {
+    auto times = getTotalCpuFreqTimes();
+    ASSERT_TRUE(times.has_value());
+    EXPECT_FALSE(times->empty());
+}
+
 TEST(TimeInStateTest, SingleUidTimeInState) {
     auto times = getUidCpuFreqTimes(0);
     ASSERT_TRUE(times.has_value());
@@ -184,6 +192,31 @@
     }
 }
 
+TEST(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
+    auto allUid = getUidsCpuFreqTimes();
+    auto total = getTotalCpuFreqTimes();
+
+    ASSERT_TRUE(allUid.has_value() && total.has_value());
+
+    // Check the number of policies.
+    ASSERT_EQ(allUid->at(0).size(), total->size());
+
+    for (uint32_t policyIdx = 0; policyIdx < total->size(); ++policyIdx) {
+        std::vector<uint64_t> totalTimes = total->at(policyIdx);
+        uint32_t totalFreqsCount = totalTimes.size();
+        std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
+        for (auto const &[uid, uidTimes]: *allUid) {
+            for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
+                allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
+            }
+        }
+
+        for (uint32_t freqIdx = 0; freqIdx < totalFreqsCount; ++freqIdx) {
+            ASSERT_LE(allUidTimes[freqIdx], totalTimes[freqIdx]);
+        }
+    }
+}
+
 TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
     uint64_t zero = 0;
     auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
@@ -290,6 +323,22 @@
     ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
 }
 
+TEST(TimeInStateTest, TotalTimeInStateMonotonic) {
+    auto before = getTotalCpuFreqTimes();
+    ASSERT_TRUE(before.has_value());
+    sleep(1);
+    auto after = getTotalCpuFreqTimes();
+    ASSERT_TRUE(after.has_value());
+
+    for (uint32_t policyIdx = 0; policyIdx < after->size(); ++policyIdx) {
+        auto timesBefore = before->at(policyIdx);
+        auto timesAfter = after->at(policyIdx);
+        for (uint32_t freqIdx = 0; freqIdx < timesAfter.size(); ++freqIdx) {
+            ASSERT_NO_FATAL_FAILURE(TestCheckDelta(timesBefore[freqIdx], timesAfter[freqIdx]));
+        }
+    }
+}
+
 TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
     auto map1 = getUidsCpuFreqTimes();
     ASSERT_TRUE(map1.has_value());
@@ -387,6 +436,28 @@
     }
 }
 
+TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+    uint32_t uid = 0;
+    {
+        // Find an unused UID
+        auto map = getUidsConcurrentTimes();
+        ASSERT_TRUE(map.has_value());
+        ASSERT_FALSE(map->empty());
+        for (const auto &kv : *map) uid = std::max(uid, kv.first);
+        ++uid;
+    }
+    android::base::unique_fd fd{
+        bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+    ASSERT_GE(fd, 0);
+    uint32_t nCpus = get_nprocs_conf();
+    uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
+    time_key_t key = {.uid = uid, .bucket = maxBucket + 1};
+    std::vector<concurrent_val_t> vals(nCpus);
+    ASSERT_FALSE(writeToMapEntry(fd, &key, vals.data(), BPF_NOEXIST));
+    EXPECT_FALSE(getUidsConcurrentTimes().has_value());
+    ASSERT_FALSE(deleteMapEntry(fd, &key));
+}
+
 TEST(TimeInStateTest, AllUidTimesConsistent) {
     auto tisMap = getUidsCpuFreqTimes();
     ASSERT_TRUE(tisMap.has_value());
@@ -482,5 +553,85 @@
     for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
 }
 
+uint64_t timeNanos() {
+    struct timespec spec;
+    clock_gettime(CLOCK_MONOTONIC, &spec);
+    return spec.tv_sec * 1000000000 + spec.tv_nsec;
+}
+
+// Keeps CPU busy with some number crunching
+void useCpu() {
+    long sum = 0;
+    for (int i = 0; i < 100000; i++) {
+        sum *= i;
+    }
+}
+
+sem_t pingsem, pongsem;
+
+void *testThread(void *) {
+    for (int i = 0; i < 10; i++) {
+        sem_wait(&pingsem);
+        useCpu();
+        sem_post(&pongsem);
+    }
+    return nullptr;
+}
+
+TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+    uint64_t startTimeNs = timeNanos();
+
+    sem_init(&pingsem, 0, 1);
+    sem_init(&pongsem, 0, 0);
+
+    pthread_t thread;
+    ASSERT_EQ(pthread_create(&thread, NULL, &testThread, NULL), 0);
+
+    // This process may have been running for some time, so when we start tracking
+    // CPU time, the very first switch may include the accumulated time.
+    // Yield the remainder of this timeslice to the newly created thread.
+    sem_wait(&pongsem);
+    sem_post(&pingsem);
+
+    pid_t tgid = getpid();
+    startTrackingProcessCpuTimes(tgid);
+
+    pid_t tid = pthread_gettid_np(thread);
+    startAggregatingTaskCpuTimes(tid, 42);
+
+    // Play ping-pong with the other thread to ensure that both threads get
+    // some CPU time.
+    for (int i = 0; i < 9; i++) {
+        sem_wait(&pongsem);
+        useCpu();
+        sem_post(&pingsem);
+    }
+
+    pthread_join(thread, NULL);
+
+    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> optionalMap =
+            getAggregatedTaskCpuFreqTimes(tgid, {0, 42});
+    ASSERT_TRUE(optionalMap);
+
+    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map = *optionalMap;
+    ASSERT_EQ(map.size(), 2u);
+
+    uint64_t testDurationNs = timeNanos() - startTimeNs;
+    for (auto pair : map) {
+        uint16_t aggregationKey = pair.first;
+        ASSERT_TRUE(aggregationKey == 0 || aggregationKey == 42);
+
+        std::vector<std::vector<uint64_t>> timesInState = pair.second;
+        uint64_t totalCpuTime = 0;
+        for (size_t i = 0; i < timesInState.size(); i++) {
+            for (size_t j = 0; j < timesInState[i].size(); j++) {
+                totalCpuTime += timesInState[i][j];
+            }
+        }
+        ASSERT_GT(totalCpuTime, 0ul);
+        ASSERT_LE(totalCpuTime, testDurationNs);
+    }
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index fd557b7..8b3c3ad 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -52,10 +52,14 @@
 
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
-        "android.hardware.audio@2.0::IDevicesFactory",
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
         "android.hardware.audio@6.0::IDevicesFactory",
+        "android.hardware.audio@7.0::IDevicesFactory",
+        "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
+        "android.hardware.automotive.audiocontrol@2.0::IAudioControl",
+        "android.hardware.automotive.evs@1.0::IEvsCamera",
+        "android.hardware.automotive.vehicle@2.0::IVehicle",
         "android.hardware.biometrics.face@1.0::IBiometricsFace",
         "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
         "android.hardware.bluetooth@1.0::IBluetoothHci",
@@ -67,16 +71,12 @@
         "android.hardware.media.c2@1.0::IComponentStore",
         "android.hardware.media.omx@1.0::IOmx",
         "android.hardware.media.omx@1.0::IOmxStore",
+        "android.hardware.neuralnetworks@1.0::IDevice",
         "android.hardware.power@1.3::IPower",
         "android.hardware.power.stats@1.0::IPowerStats",
         "android.hardware.sensors@1.0::ISensors",
         "android.hardware.thermal@2.0::IThermal",
         "android.hardware.vr@1.0::IVr",
-        "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
-        "android.hardware.automotive.audiocontrol@2.0::IAudioControl",
-        "android.hardware.automotive.vehicle@2.0::IVehicle",
-        "android.hardware.automotive.evs@1.0::IEvsCamera",
-        "android.hardware.neuralnetworks@1.0::IDevice",
         NULL,
 };
 
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index de32ff4..76518c1 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -1,5 +1,6 @@
 cc_defaults {
     name: "fakeservicemanager_defaults",
+    host_supported: true,
     srcs: [
         "ServiceManager.cpp",
     ],
@@ -8,6 +9,11 @@
         "libbinder",
         "libutils",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 cc_library {
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 6964324..4ecbe53 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -61,4 +61,16 @@
     return mNameToService.find(name) != mNameToService.end();
 }
 
+Vector<String16> ServiceManager::getDeclaredInstances(const String16& name) {
+    Vector<String16> out;
+    const String16 prefix = name + String16("/");
+    for (const auto& [registeredName, service] : mNameToService) {
+        (void) service;
+        if (registeredName.startsWith(prefix)) {
+            out.add(String16(registeredName.string() + prefix.size()));
+        }
+    }
+    return out;
+}
+
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 62311d4..4ef47fb 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -30,42 +30,23 @@
 public:
     ServiceManager();
 
-    /**
-     * Equivalent of checkService.
-     */
     sp<IBinder> getService( const String16& name) const override;
 
-    /**
-     * Retrieve an existing service, non-blocking.
-     */
     sp<IBinder> checkService( const String16& name) const override;
 
-    /**
-     * Register a service.
-     */
     status_t addService(const String16& name, const sp<IBinder>& service,
                         bool allowIsolated = false,
                         int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) override;
 
-    /**
-     * Return list of all existing services.
-     */
     Vector<String16> listServices(int dumpsysFlags = 0) override;
 
     IBinder* onAsBinder() override;
 
-    /**
-     * Effectively no-oped in this implementation - equivalent to checkService.
-     */
     sp<IBinder> waitForService(const String16& name) override;
 
-    /**
-     * Check if a service is declared (e.g. VINTF manifest).
-     *
-     * If this returns true, waitForService should always be able to return the
-     * service.
-     */
-     bool isDeclared(const String16& name) override;
+    bool isDeclared(const String16& name) override;
+
+    Vector<String16> getDeclaredInstances(const String16& iface) override;
 
 private:
     std::map<String16, sp<IBinder>> mNameToService;
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
index 67743cd..93879d8 100644
--- a/libs/gralloc/OWNERS
+++ b/libs/gralloc/OWNERS
@@ -1,2 +1 @@
-marissaw@google.com
-vhau@google.com
+chrisforbes@google.com
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 66fb295..243d7f1 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -21,6 +21,11 @@
         "-Wno-enum-compare",
     ],
     host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
 
     vendor_available: true,
     vndk: {
@@ -38,14 +43,14 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
     ],
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 53c68b7..e2f072a 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -706,35 +706,35 @@
         return err;
     }
 
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.offsetInBytes), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.offsetInBytes), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.sampleIncrementInBits), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.sampleIncrementInBits), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.strideInBytes), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.strideInBytes), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.widthInSamples), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.widthInSamples), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.heightInSamples), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.heightInSamples), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.totalSizeInBytes), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.totalSizeInBytes), output);
     if (err) {
         return err;
     }
-    err = encodeInteger<int64_t>(static_cast<int32_t>(input.horizontalSubsampling), output);
+    err = encodeInteger<int64_t>(static_cast<int64_t>(input.horizontalSubsampling), output);
     if (err) {
         return err;
     }
-    return encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output);
+    return encodeInteger<int64_t>(static_cast<int64_t>(input.verticalSubsampling), output);
 }
 
 status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8444883..8933dc3 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -2,6 +2,11 @@
     name: "libgralloctypes_fuzzer",
     defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
 
     fuzz_config: {
         cc: ["marissaw@google.com"],
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 1a7c2c9..2f418ac 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -32,202 +32,6 @@
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 
 namespace android {
-
-/**
- * Define equality operators for Stable AIDL types.
- */
-inline bool operator==(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !std::strcmp(lhs.name.c_str(), rhs.name.c_str()) && lhs.value == rhs.value;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    if (lhs.type.name != rhs.type.name) {
-        return false;
-    }
-    if (lhs.type.value != rhs.type.value) {
-        return false;
-    }
-    if (lhs.sizeInBits != rhs.sizeInBits) {
-        return false;
-    }
-    if (lhs.offsetInBits != rhs.offsetInBits) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    if (lhs.left != rhs.left) {
-        return false;
-    }
-    if (lhs.top != rhs.top) {
-        return false;
-    }
-    if (lhs.right != rhs.right) {
-        return false;
-    }
-    if (lhs.bottom != rhs.bottom) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    if (lhs.offsetInBytes != rhs.offsetInBytes) {
-        return false;
-    }
-    if (lhs.sampleIncrementInBits != rhs.sampleIncrementInBits) {
-        return false;
-    }
-    if (lhs.strideInBytes != rhs.strideInBytes) {
-        return false;
-    }
-    if (lhs.widthInSamples != rhs.widthInSamples) {
-        return false;
-    }
-    if (lhs.heightInSamples != rhs.heightInSamples) {
-        return false;
-    }
-    if (lhs.totalSizeInBytes != rhs.totalSizeInBytes) {
-        return false;
-    }
-    if (lhs.horizontalSubsampling != rhs.horizontalSubsampling) {
-        return false;
-    }
-    if (lhs.verticalSubsampling != rhs.verticalSubsampling) {
-        return false;
-    }
-    if (lhs.components.size() != rhs.components.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.components.size(); i++) {
-        if (lhs.components[i] != rhs.components[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    if (lhs.x != rhs.x) {
-        return false;
-    }
-    if (lhs.y != rhs.y) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    if (lhs.primaryRed != rhs.primaryRed) {
-        return false;
-    }
-    if (lhs.primaryGreen != rhs.primaryGreen) {
-        return false;
-    }
-    if (lhs.primaryBlue != rhs.primaryBlue) {
-        return false;
-    }
-    if (lhs.whitePoint != rhs.whitePoint) {
-        return false;
-    }
-    if (lhs.maxLuminance != rhs.maxLuminance) {
-        return false;
-    }
-    if (lhs.minLuminance != rhs.minLuminance) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    if (lhs.maxContentLightLevel != rhs.maxContentLightLevel) {
-        return false;
-    }
-    if (lhs.maxFrameAverageLightLevel != rhs.maxFrameAverageLightLevel) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    return !(lhs == rhs);
-}
-
 namespace gralloc4 {
 
 #define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 4a4510e..18ade37 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -32,9 +32,10 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: false,
+    vendor_available: true,
     vndk: {
         enabled: true,
+        private: true,
     },
     double_loadable: true,
 
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 489f3c3..1f71e23 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -696,7 +696,7 @@
     // relationship, thus |getConsumerName| from the producer side does not
     // make any sense.
     ALOGE("BufferHubProducer::getConsumerName not supported.");
-    return String8("BufferHubQueue::DummyConsumer");
+    return String8("BufferHubQueue::StubConsumer");
 }
 
 status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 59f1bcd..30d19e3 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -280,7 +280,7 @@
         mCurrentFenceTime = FenceTime::NO_FENCE;
 
         if (mAttached) {
-            // This binds a dummy buffer (mReleasedTexImage).
+            // This binds a buffer placeholder (mReleasedTexImage).
             status_t result = bindTextureImageLocked();
             if (result != NO_ERROR) {
                 return result;
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 5c81b9d..0683087 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -119,7 +119,7 @@
     return BBinder::onTransact(code, data, reply, flags);
 }
 
-DummyProducerListener::~DummyProducerListener() = default;
+StubProducerListener::~StubProducerListener() = default;
 
 bool BnProducerListener::needsReleaseNotify() {
     return true;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e43446a..0281279 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -176,7 +176,12 @@
         sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
     }
 
-    colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+    const void* color_transform_data = input.readInplace(16 * sizeof(float));
+    if (color_transform_data) {
+        colorTransform = mat4(static_cast<const float*>(color_transform_data));
+    } else {
+        return BAD_VALUE;
+    }
     cornerRadius = input.readFloat();
     backgroundBlurRadius = input.readUint32();
     cachedBuffer.token = input.readStrongBinder();
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index c13401d..1667fb0 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,12 +1,23 @@
 adyabr@google.com
 akrulec@google.com
 alecmouri@google.com
+chaviw@google.com
+chrisforbes@google.com
 jessehall@google.com
-jwcai@google.com
 lpy@google.com
-marissaw@google.com
 mathias@google.com
 racarr@google.com
-steventhomas@google.com
 stoza@google.com
-vhau@google.com
+vishnun@google.com
+
+per-file EndToEndNativeInputTest.cpp = svv@google.com
+
+# BufferQueue is feature-frozen
+per-file BufferQueue* = set noparent
+per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file IGraphicBuffer* = set noparent
+per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file include/gui/BufferQueue* = set noparent
+per-file include/gui/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file include/gui/IGraphicBuffer* = set noparent
+per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index e1a17db..d6f9e63 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1519,7 +1519,7 @@
 }
 
 int Surface::connect(int api) {
-    static sp<IProducerListener> listener = new DummyProducerListener();
+    static sp<IProducerListener> listener = new StubProducerListener();
     return connect(api, listener);
 }
 
diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS
index cbe9317..615dd79 100644
--- a/libs/gui/bufferqueue/OWNERS
+++ b/libs/gui/bufferqueue/OWNERS
@@ -1,5 +1,4 @@
-chz@google.com
-lajos@google.com
-pawin@google.com
-taklee@google.com
-wonsik@google.com
+# BufferQueue is feature-frozen
+jreck@google.com
+sumir@google.com
+alecmouri@google.com
\ No newline at end of file
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index ddd868d..2f538ff 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -499,7 +499,7 @@
     // protects static initialization
     static Mutex sStaticInitLock;
 
-    // mReleasedTexImageBuffer is a dummy buffer used when in single buffer
+    // mReleasedTexImageBuffer is a buffer placeholder used when in single buffer
     // mode and releaseTexImage() has been called
     static sp<GraphicBuffer> sReleasedTexImageBuffer;
     sp<EglImage> mReleasedTexImage;
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index d7f3492..45e0a13 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -458,7 +458,7 @@
     // the producer wants to be notified when the consumer releases a buffer
     // back to the BufferQueue. It is also used to detect the death of the
     // producer. If only the latter functionality is desired, there is a
-    // DummyProducerListener class in IProducerListener.h that can be used.
+    // StubProducerListener class in IProducerListener.h that can be used.
     //
     // The api should be one of the NATIVE_WINDOW_API_* values in <window.h>
     //
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index 0b1f4b5..f7ffbb9 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -80,10 +80,9 @@
 class BnProducerListener : public IProducerListener {
 };
 #endif
-class DummyProducerListener : public BnProducerListener
-{
+class StubProducerListener : public BnProducerListener {
 public:
-    virtual ~DummyProducerListener();
+    virtual ~StubProducerListener();
     virtual void onBufferReleased() {}
     virtual bool needsReleaseNotify() { return false; }
 };
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
index 99ab085..004d875 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
@@ -51,12 +51,14 @@
 typedef ::android::IProducerListener BProducerListener;
 
 #ifndef LOG
-struct LOG_dummy {
+struct LOG_stub {
     template <typename T>
-    LOG_dummy& operator<< (const T&) { return *this; }
+    LOG_stub& operator<<(const T&) {
+        return *this;
+    }
 };
 
-#define LOG(x)  LOG_dummy()
+#define LOG(x) LOG_stub()
 #endif
 
 // Instantiate only if HGraphicBufferProducer is base of BASE.
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index d929a59..da5bbdd 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -128,7 +128,7 @@
         ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
         IGraphicBufferProducer::QueueBufferOutput qbOutput;
         ASSERT_EQ(NO_ERROR,
-                  igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+                  igbProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
                                        &qbOutput));
         ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
         producer = igbProducer;
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index b87cbbd..fc6551c 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -51,7 +51,7 @@
         mBFL = new BufferFreedListener(this);
         mBIC->setBufferFreedListener(mBFL);
 
-        sp<IProducerListener> producerListener = new DummyProducerListener();
+        sp<IProducerListener> producerListener = new StubProducerListener();
         IGraphicBufferProducer::QueueBufferOutput bufferOutput;
         ASSERT_EQ(NO_ERROR,
                   mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
@@ -131,7 +131,7 @@
 // Test that detaching buffer from consumer side triggers onBufferFreed.
 TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DetachBufferFromConsumer) {
     int slot;
-    // Producer: generate a dummy buffer.
+    // Producer: generate a placeholder buffer.
     DequeueBuffer(&slot);
     QueueBuffer(slot);
 
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 6d7b6bb..d1208ee 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "BufferQueue_test"
 //#define LOG_NDEBUG 0
 
-#include "DummyConsumer.h"
+#include "MockConsumer.h"
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
@@ -134,8 +134,8 @@
     mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
     EXPECT_TRUE(mConsumer != nullptr);
 
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
     ASSERT_EQ(OK,
             mProducer->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
@@ -171,23 +171,22 @@
 
 TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
     int bufferCount = 50;
     mConsumer->setMaxBufferCount(bufferCount);
 
     IGraphicBufferProducer::QueueBufferOutput output;
-    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output);
+    mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output);
     ASSERT_EQ(output.maxBufferCount, bufferCount);
 }
 
 TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
     IGraphicBufferProducer::QueueBufferOutput qbo;
-    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
-            &qbo);
+    mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo);
     mProducer->setMaxDequeuedBufferCount(3);
 
     int slot;
@@ -219,15 +218,14 @@
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
 
     EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(10));
 
     IGraphicBufferProducer::QueueBufferOutput qbo;
-    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
-            &qbo);
+    mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo);
     mProducer->setMaxDequeuedBufferCount(3);
 
     int minBufferCount;
@@ -263,12 +261,11 @@
 
 TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
 
     IGraphicBufferProducer::QueueBufferOutput qbo;
-    mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
-            &qbo);
+    mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &qbo);
     mProducer->setMaxDequeuedBufferCount(2);
 
     int minBufferCount;
@@ -310,8 +307,8 @@
 
 TEST_F(BufferQueueTest, SetMaxBufferCountWithLegalValues_Succeeds) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
 
     // Test shared buffer mode
     EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
@@ -319,8 +316,8 @@
 
 TEST_F(BufferQueueTest, SetMaxBufferCountWithIllegalValues_ReturnsError) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    mConsumer->consumerConnect(dc, false);
+    sp<MockConsumer> mc(new MockConsumer);
+    mConsumer->consumerConnect(mc, false);
 
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(0));
     EXPECT_EQ(BAD_VALUE, mConsumer->setMaxBufferCount(
@@ -332,11 +329,11 @@
 
 TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output));
 
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(-1)); // Index too low
     ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(
@@ -386,11 +383,11 @@
 
 TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
@@ -445,11 +442,11 @@
 
 TEST_F(BufferQueueTest, MoveFromConsumerToProducer) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
@@ -488,11 +485,11 @@
 
 TEST_F(BufferQueueTest, TestDisallowingAllocation) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     static const uint32_t WIDTH = 320;
     static const uint32_t HEIGHT = 240;
@@ -526,11 +523,11 @@
 
 TEST_F(BufferQueueTest, TestGenerationNumbers) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     ASSERT_EQ(OK, mProducer->setGenerationNumber(1));
 
@@ -568,11 +565,11 @@
 
 TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     ASSERT_EQ(OK, mProducer->setSharedBufferMode(true));
 
@@ -618,11 +615,11 @@
 
 TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     ASSERT_EQ(OK, mProducer->setSharedBufferMode(true));
     ASSERT_EQ(OK, mProducer->setAutoRefresh(true));
@@ -687,11 +684,11 @@
 
 TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     // Dequeue a buffer
     int sharedSlot;
@@ -738,11 +735,11 @@
 
 TEST_F(BufferQueueTest, TestTimeouts) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     // Fill up the queue. Since the controlledByApp flags are set to true, this
     // queue should be in non-blocking mode, and we should be recycling the same
@@ -800,11 +797,11 @@
 
 TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> sourceFence;
@@ -822,11 +819,11 @@
 
 TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output));
 
     // Dequeue and queue the first buffer, storing the handle
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
@@ -876,11 +873,11 @@
 
 TEST_F(BufferQueueTest, TestOccupancyHistory) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence = Fence::NO_FENCE;
@@ -1030,8 +1027,8 @@
 
 TEST_F(BufferQueueTest, TestDiscardFreeBuffers) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
     sp<BufferDiscardedListener> pl(new BufferDiscardedListener);
     ASSERT_EQ(OK, mProducer->connect(pl,
@@ -1115,11 +1112,11 @@
 
 TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(OK,
+              mProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, true, &output));
     ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
 
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
@@ -1156,12 +1153,11 @@
 
 TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    sp<IProducerListener> dummyListener(new DummyProducerListener);
-    ASSERT_EQ(OK, mProducer->connect(dummyListener, NATIVE_WINDOW_API_CPU,
-            true, &output));
+    sp<IProducerListener> fakeListener(new StubProducerListener);
+    ASSERT_EQ(OK, mProducer->connect(fakeListener, NATIVE_WINDOW_API_CPU, true, &output));
 
     int slot = BufferQueue::INVALID_BUFFER_SLOT;
     sp<Fence> fence = Fence::NO_FENCE;
@@ -1215,15 +1211,13 @@
 
 TEST_F(BufferQueueTest, TestProducerConnectDisconnect) {
     createBufferQueue();
-    sp<DummyConsumer> dc(new DummyConsumer);
-    ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+    sp<MockConsumer> mc(new MockConsumer);
+    ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true));
     IGraphicBufferProducer::QueueBufferOutput output;
-    sp<IProducerListener> dummyListener(new DummyProducerListener);
+    sp<IProducerListener> fakeListener(new StubProducerListener);
     ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
-    ASSERT_EQ(OK, mProducer->connect(
-            dummyListener, NATIVE_WINDOW_API_CPU, true, &output));
-    ASSERT_EQ(BAD_VALUE, mProducer->connect(
-            dummyListener, NATIVE_WINDOW_API_MEDIA, true, &output));
+    ASSERT_EQ(OK, mProducer->connect(fakeListener, NATIVE_WINDOW_API_CPU, true, &output));
+    ASSERT_EQ(BAD_VALUE, mProducer->connect(fakeListener, NATIVE_WINDOW_API_MEDIA, true, &output));
 
     ASSERT_EQ(BAD_VALUE, mProducer->disconnect(NATIVE_WINDOW_API_MEDIA));
     ASSERT_EQ(OK, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 103f775..15bd32d 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "IGraphicBufferProducer_test"
 //#define LOG_NDEBUG 0
 
-#include "DummyConsumer.h"
+#include "MockConsumer.h"
 
 #include <gtest/gtest.h>
 
@@ -89,7 +89,7 @@
         ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
                 testInfo->name());
 
-        mDC = new DummyConsumer;
+        mMC = new MockConsumer;
 
         switch (GetParam()) {
             case USE_BUFFER_QUEUE_PRODUCER: {
@@ -114,7 +114,7 @@
         }
 
         // Must connect consumer before producer connects will succeed.
-        ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false));
+        ASSERT_OK(mConsumer->consumerConnect(mMC, /*controlledByApp*/ false));
     }
 
     virtual void TearDown() {
@@ -249,7 +249,7 @@
     }
 
 private: // hide from test body
-    sp<DummyConsumer> mDC;
+    sp<MockConsumer> mMC;
 
 protected: // accessible from test body
     sp<IGraphicBufferProducer> mProducer;
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index acd4297..58d7cc6 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -129,7 +129,7 @@
     int32_t mExpectedSlot = 0;
 };
 
-class DummyListener : public BnConsumerListener {
+class FakeListener : public BnConsumerListener {
 public:
     void onFrameAvailable(const BufferItem&) override {}
     void onBuffersReleased() override {}
@@ -140,7 +140,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    sp<IConsumerListener> listener = new DummyListener;
+    sp<IConsumerListener> listener = new FakeListener;
     consumer->consumerConnect(listener, false);
 
     sp<MaliciousBQP> malicious = new MaliciousBQP(producer);
diff --git a/libs/gui/tests/DummyConsumer.h b/libs/gui/tests/MockConsumer.h
similarity index 94%
rename from libs/gui/tests/DummyConsumer.h
rename to libs/gui/tests/MockConsumer.h
index 502bdf9..4a6c51c 100644
--- a/libs/gui/tests/DummyConsumer.h
+++ b/libs/gui/tests/MockConsumer.h
@@ -18,7 +18,7 @@
 
 namespace android {
 
-struct DummyConsumer : public BnConsumerListener {
+struct MockConsumer : public BnConsumerListener {
     void onFrameAvailable(const BufferItem& /* item */) override {}
     void onBuffersReleased() override {}
     void onSidebandStreamChanged() override {}
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index ad6e051..b65cdda 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -48,7 +48,7 @@
     }
 };
 
-struct DummyListener : public BnConsumerListener {
+struct FakeListener : public BnConsumerListener {
     virtual void onFrameAvailable(const BufferItem& /* item */) {}
     virtual void onBuffersReleased() {}
     virtual void onSidebandStreamChanged() {}
@@ -64,7 +64,7 @@
     sp<IGraphicBufferProducer> outputProducer;
     sp<IGraphicBufferConsumer> outputConsumer;
     BufferQueue::createBufferQueue(&outputProducer, &outputConsumer);
-    ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false));
+    ASSERT_EQ(OK, outputConsumer->consumerConnect(new FakeListener, false));
 
     sp<StreamSplitter> splitter;
     status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter);
@@ -75,8 +75,9 @@
     ASSERT_EQ(OK, outputProducer->allowAllocation(false));
 
     IGraphicBufferProducer::QueueBufferOutput qbOutput;
-    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &qbOutput));
+    ASSERT_EQ(OK,
+              inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
+                                     &qbOutput));
 
     int slot;
     sp<Fence> fence;
@@ -132,8 +133,7 @@
     for (int output = 0; output < NUM_OUTPUTS; ++output) {
         BufferQueue::createBufferQueue(&outputProducers[output],
                 &outputConsumers[output]);
-        ASSERT_EQ(OK, outputConsumers[output]->consumerConnect(
-                    new DummyListener, false));
+        ASSERT_EQ(OK, outputConsumers[output]->consumerConnect(new FakeListener, false));
     }
 
     sp<StreamSplitter> splitter;
@@ -147,8 +147,9 @@
     }
 
     IGraphicBufferProducer::QueueBufferOutput qbOutput;
-    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &qbOutput));
+    ASSERT_EQ(OK,
+              inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
+                                     &qbOutput));
 
     int slot;
     sp<Fence> fence;
@@ -203,7 +204,7 @@
     sp<IGraphicBufferProducer> outputProducer;
     sp<IGraphicBufferConsumer> outputConsumer;
     BufferQueue::createBufferQueue(&outputProducer, &outputConsumer);
-    ASSERT_EQ(OK, outputConsumer->consumerConnect(new DummyListener, false));
+    ASSERT_EQ(OK, outputConsumer->consumerConnect(new FakeListener, false));
 
     sp<StreamSplitter> splitter;
     status_t status = StreamSplitter::createSplitter(inputConsumer, &splitter);
@@ -211,8 +212,9 @@
     ASSERT_EQ(OK, splitter->addOutput(outputProducer));
 
     IGraphicBufferProducer::QueueBufferOutput qbOutput;
-    ASSERT_EQ(OK, inputProducer->connect(new DummyProducerListener,
-            NATIVE_WINDOW_API_CPU, false, &qbOutput));
+    ASSERT_EQ(OK,
+              inputProducer->connect(new StubProducerListener, NATIVE_WINDOW_API_CPU, false,
+                                     &qbOutput));
 
     int slot;
     sp<Fence> fence;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index c85e844..c7458a3 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -54,7 +54,7 @@
         mANW = mSTC;
 
         // We need a valid GL context so we can test updateTexImage()
-        // This initializes EGL and create a dummy GL context with a
+        // This initializes EGL and create a GL context placeholder with a
         // pbuffer render target.
         mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 9906166..592913c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "DummyConsumer.h"
+#include "MockConsumer.h"
 
 #include <gtest/gtest.h>
 
@@ -56,12 +56,11 @@
 
 static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
 
-class DummySurfaceListener : public SurfaceListener {
+class FakeSurfaceListener : public SurfaceListener {
 public:
-    DummySurfaceListener(bool enableReleasedCb = false) :
-            mEnableReleaseCb(enableReleasedCb),
-            mBuffersReleased(0) {}
-    virtual ~DummySurfaceListener() = default;
+    FakeSurfaceListener(bool enableReleasedCb = false)
+          : mEnableReleaseCb(enableReleasedCb), mBuffersReleased(0) {}
+    virtual ~FakeSurfaceListener() = default;
 
     virtual void onBufferReleased() {
         mBuffersReleased++;
@@ -124,15 +123,15 @@
         sp<IGraphicBufferConsumer> consumer;
         BufferQueue::createBufferQueue(&producer, &consumer);
 
-        sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-        consumer->consumerConnect(dummyConsumer, false);
+        sp<MockConsumer> mockConsumer(new MockConsumer);
+        consumer->consumerConnect(mockConsumer, false);
         consumer->setConsumerName(String8("TestConsumer"));
 
         sp<Surface> surface = new Surface(producer);
         sp<ANativeWindow> window(surface);
-        sp<DummySurfaceListener> listener;
+        sp<FakeSurfaceListener> listener;
         if (hasSurfaceListener) {
-            listener = new DummySurfaceListener(enableReleasedCb);
+            listener = new FakeSurfaceListener(enableReleasedCb);
         }
         ASSERT_EQ(OK, surface->connect(
                 NATIVE_WINDOW_API_CPU,
@@ -381,8 +380,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
@@ -397,8 +396,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
@@ -428,8 +427,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
@@ -452,8 +451,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
@@ -497,8 +496,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
@@ -523,13 +522,13 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setConsumerName(String8("TestConsumer"));
 
     sp<Surface> surface = new Surface(producer);
     sp<ANativeWindow> window(surface);
-    sp<DummyProducerListener> listener = new DummyProducerListener();
+    sp<StubProducerListener> listener = new StubProducerListener();
     ASSERT_EQ(OK, surface->connect(
             NATIVE_WINDOW_API_CPU,
             /*listener*/listener,
@@ -1910,8 +1909,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
     consumer->setDefaultBufferSize(10, 10);
 
     sp<Surface> surface = new Surface(producer);
@@ -1980,8 +1979,8 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<DummyConsumer> dummyConsumer(new DummyConsumer);
-    consumer->consumerConnect(dummyConsumer, false);
+    sp<MockConsumer> mockConsumer(new MockConsumer);
+    consumer->consumerConnect(mockConsumer, false);
 
     sp<Surface> surface = new Surface(producer);
     sp<ANativeWindow> window(surface);
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index d64dfd5..d98ffc6 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -72,13 +72,9 @@
 }
 
 String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
-    size_t len;
-    const char16_t* str = parcel->readString16Inplace(&len);
-    if (str != nullptr) {
-        return String16(str, len);
-    } else {
-        return String16();
-    }
+    std::optional<String16> str;
+    parcel->readString16(&str);
+    return str.value_or(String16());
 }
 
 } // namespace view
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 8efaf3d..6a5d434 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,12 +28,16 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
+        "PropertyMap.cpp",
         "TouchVideoFrame.cpp",
         "VirtualKeyMap.cpp",
     ],
 
     clang: true,
 
+    header_libs: ["jni_headers"],
+    export_header_lib_headers: ["jni_headers"],
+
     shared_libs: [
         "libbase",
         "liblog",
@@ -71,4 +75,23 @@
     },
 }
 
+cc_defaults {
+    name: "libinput_fuzz_defaults",
+    host_supported: true,
+    shared_libs: [
+        "libutils",
+        "libbase",
+        "liblog",
+    ],
+}
+
+cc_fuzz {
+    name: "libinput_fuzz_propertymap",
+    defaults: ["libinput_fuzz_defaults"],
+    srcs: [
+        "PropertyMap.cpp",
+        "PropertyMap_fuzz.cpp",
+    ],
+}
+
 subdirs = ["tests"]
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
new file mode 100644
index 0000000..4833eb9
--- /dev/null
+++ b/libs/input/PropertyMap.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2008 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 "PropertyMap"
+
+#include <input/PropertyMap.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
+
+// --- PropertyMap ---
+
+PropertyMap::PropertyMap() {}
+
+PropertyMap::~PropertyMap() {}
+
+void PropertyMap::clear() {
+    mProperties.clear();
+}
+
+void PropertyMap::addProperty(const String8& key, const String8& value) {
+    mProperties.add(key, value);
+}
+
+bool PropertyMap::hasProperty(const String8& key) const {
+    return mProperties.indexOfKey(key) >= 0;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
+    ssize_t index = mProperties.indexOfKey(key);
+    if (index < 0) {
+        return false;
+    }
+
+    outValue = mProperties.valueAt(index);
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
+    int32_t intValue;
+    if (!tryGetProperty(key, intValue)) {
+        return false;
+    }
+
+    outValue = intValue;
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
+    String8 stringValue;
+    if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+        return false;
+    }
+
+    char* end;
+    int value = strtol(stringValue.string(), &end, 10);
+    if (*end != '\0') {
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected an integer.", key.string(),
+              stringValue.string());
+        return false;
+    }
+    outValue = value;
+    return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
+    String8 stringValue;
+    if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+        return false;
+    }
+
+    char* end;
+    float value = strtof(stringValue.string(), &end);
+    if (*end != '\0') {
+        ALOGW("Property key '%s' has invalid value '%s'.  Expected a float.", key.string(),
+              stringValue.string());
+        return false;
+    }
+    outValue = value;
+    return true;
+}
+
+void PropertyMap::addAll(const PropertyMap* map) {
+    for (size_t i = 0; i < map->mProperties.size(); i++) {
+        mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
+    }
+}
+
+status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
+    *outMap = nullptr;
+
+    Tokenizer* tokenizer;
+    status_t status = Tokenizer::open(filename, &tokenizer);
+    if (status) {
+        ALOGE("Error %d opening property file %s.", status, filename.string());
+    } else {
+        PropertyMap* map = new PropertyMap();
+        if (!map) {
+            ALOGE("Error allocating property map.");
+            status = NO_MEMORY;
+        } else {
+#if DEBUG_PARSER_PERFORMANCE
+            nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+            Parser parser(map, tokenizer);
+            status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+            nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+            ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
+                  tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+                  elapsedTime / 1000000.0);
+#endif
+            if (status) {
+                delete map;
+            } else {
+                *outMap = map;
+            }
+        }
+        delete tokenizer;
+    }
+    return status;
+}
+
+// --- PropertyMap::Parser ---
+
+PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer)
+      : mMap(map), mTokenizer(tokenizer) {}
+
+PropertyMap::Parser::~Parser() {}
+
+status_t PropertyMap::Parser::parse() {
+    while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+        ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+              mTokenizer->peekRemainderOfLine().string());
+#endif
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+
+        if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+            String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
+            if (keyToken.isEmpty()) {
+                ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+
+            if (mTokenizer->nextChar() != '=') {
+                ALOGE("%s: Expected '=' between property key and value.",
+                      mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+
+            String8 valueToken = mTokenizer->nextToken(WHITESPACE);
+            if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
+                ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
+                      mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
+
+            mTokenizer->skipDelimiters(WHITESPACE);
+            if (!mTokenizer->isEol()) {
+                ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(),
+                      mTokenizer->peekRemainderOfLine().string());
+                return BAD_VALUE;
+            }
+
+            if (mMap->hasProperty(keyToken)) {
+                ALOGE("%s: Duplicate property value for key '%s'.",
+                      mTokenizer->getLocation().string(), keyToken.string());
+                return BAD_VALUE;
+            }
+
+            mMap->addProperty(keyToken, valueToken);
+        }
+
+        mTokenizer->nextLine();
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp
new file mode 100755
index 0000000..23ead0e
--- /dev/null
+++ b/libs/input/PropertyMap_fuzz.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/file.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "input/PropertyMap.h"
+#include "utils/String8.h"
+
+static constexpr int MAX_FILE_SIZE = 256;
+static constexpr int MAX_STR_LEN = 2048;
+static constexpr int MAX_OPERATIONS = 1000;
+
+static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>>
+        operations = {
+                [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
+                    propertyMap.getProperties();
+                },
+                [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
+                    propertyMap.clear();
+                },
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    android::String8 key = android::String8(keyStr.c_str());
+                    propertyMap.hasProperty(key);
+                },
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    android::String8 key = android::String8(keyStr.c_str());
+                    android::String8 out;
+                    propertyMap.tryGetProperty(key, out);
+                },
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+                    TemporaryFile tf;
+                    // Generate file contents
+                    std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE);
+                    // If we have string contents, dump them into the file.
+                    // Otherwise, just leave it as an empty file.
+                    if (contents.length() > 0) {
+                        const char* bytes = contents.c_str();
+                        android::base::WriteStringToFd(bytes, tf.fd);
+                    }
+                    android::PropertyMap* mapPtr = &propertyMap;
+                    android::PropertyMap::load(android::String8(tf.path), &mapPtr);
+                },
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+                    std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
+                    android::String8 key = android::String8(keyStr.c_str());
+                    android::String8 val = android::String8(valStr.c_str());
+                    propertyMap.addProperty(key, val);
+                },
+};
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    android::PropertyMap proprtyMap = android::PropertyMap();
+
+    int opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        operations[op](&dataProvider, proprtyMap);
+    }
+    return 0;
+}
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index f6a95ce..b431cbb 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -443,12 +443,18 @@
 }
 void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
                                            AChoreographer_frameCallback callback, void* data) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     return AChoreographer_postFrameCallback(choreographer, callback, data);
+#pragma clang diagnostic pop
 }
 void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
                                                   AChoreographer_frameCallback callback, void* data,
                                                   long delayMillis) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+#pragma clang diagnostic pop
 }
 void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
                                              AChoreographer_frameCallback64 callback, void* data) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 52d73e0..07e5d86 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -40,6 +40,7 @@
 
 cc_library {
     name: "libnativewindow",
+    llndk_stubs: "libnativewindow.llndk",
     export_include_dirs: [
         "include",
         "include-private",
@@ -95,7 +96,7 @@
 }
 
 llndk_library {
-    name: "libnativewindow",
+    name: "libnativewindow.llndk",
     symbol_file: "libnativewindow.map.txt",
     unversioned: true,
     export_include_dirs: ["include"],
diff --git a/libs/renderengine/Description.cpp b/libs/renderengine/Description.cpp
index b9cea10..245c9e1 100644
--- a/libs/renderengine/Description.cpp
+++ b/libs/renderengine/Description.cpp
@@ -52,5 +52,10 @@
     return colorMatrix != identity;
 }
 
+bool Description::hasDisplayColorMatrix() const {
+    const mat4 identity;
+    return displayColorMatrix != identity;
+}
+
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index c00fbba..b44456b 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,2 +1,4 @@
+alecmouri@google.com
+jreck@google.com
 lpy@google.com
 stoza@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0285c2f..56d470e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -245,22 +245,22 @@
     // if can't create a GL context, we can only abort.
     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
 
-    EGLSurface dummy = EGL_NO_SURFACE;
+    EGLSurface stub = EGL_NO_SURFACE;
     if (!extensions.hasSurfacelessContext()) {
-        dummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
-                                             Protection::UNPROTECTED);
-        LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+        stub = createStubEglPbufferSurface(display, config, args.pixelFormat,
+                                           Protection::UNPROTECTED);
+        LOG_ALWAYS_FATAL_IF(stub == EGL_NO_SURFACE, "can't create stub pbuffer");
     }
-    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
-    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
+    EGLBoolean success = eglMakeCurrent(display, stub, stub, ctxt);
+    LOG_ALWAYS_FATAL_IF(!success, "can't make stub pbuffer current");
     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
-    EGLSurface protectedDummy = EGL_NO_SURFACE;
+    EGLSurface protectedStub = EGL_NO_SURFACE;
     if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
-        protectedDummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
-                                                      Protection::PROTECTED);
-        ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
+        protectedStub = createStubEglPbufferSurface(display, config, args.pixelFormat,
+                                                    Protection::PROTECTED);
+        ALOGE_IF(protectedStub == EGL_NO_SURFACE, "can't create protected stub pbuffer");
     }
 
     // now figure out what version of GL did we actually get
@@ -278,8 +278,8 @@
             break;
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
-            engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, dummy,
-                                                        protectedContext, protectedDummy);
+            engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, stub,
+                                                        protectedContext, protectedStub);
             break;
     }
 
@@ -334,15 +334,15 @@
 }
 
 GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
-                                   EGLConfig config, EGLContext ctxt, EGLSurface dummy,
-                                   EGLContext protectedContext, EGLSurface protectedDummy)
+                                   EGLConfig config, EGLContext ctxt, EGLSurface stub,
+                                   EGLContext protectedContext, EGLSurface protectedStub)
       : renderengine::impl::RenderEngine(args),
         mEGLDisplay(display),
         mEGLConfig(config),
         mEGLContext(ctxt),
-        mDummySurface(dummy),
+        mStubSurface(stub),
         mProtectedEGLContext(protectedContext),
-        mProtectedDummySurface(protectedDummy),
+        mProtectedStubSurface(protectedStub),
         mVpWidth(0),
         mVpHeight(0),
         mFramebufferImageCacheSize(args.imageCacheSize),
@@ -355,12 +355,12 @@
 
     // Initialize protected EGL Context.
     if (mProtectedEGLContext != EGL_NO_CONTEXT) {
-        EGLBoolean success = eglMakeCurrent(display, mProtectedDummySurface, mProtectedDummySurface,
+        EGLBoolean success = eglMakeCurrent(display, mProtectedStubSurface, mProtectedStubSurface,
                                             mProtectedEGLContext);
         ALOGE_IF(!success, "can't make protected context current");
         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
         glPixelStorei(GL_PACK_ALIGNMENT, 4);
-        success = eglMakeCurrent(display, mDummySurface, mDummySurface, mEGLContext);
+        success = eglMakeCurrent(display, mStubSurface, mStubSurface, mEGLContext);
         LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
     }
 
@@ -942,7 +942,7 @@
         }
     }
 
-    // Bind the texture to dummy data so that backing image data can be freed.
+    // Bind the texture to placeholder so that backing image data can be freed.
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing());
     glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer);
     // Release the cached fence here, so that we don't churn reallocations when
@@ -980,7 +980,7 @@
     if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
         return false;
     }
-    const EGLSurface surface = useProtectedContext ? mProtectedDummySurface : mDummySurface;
+    const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface;
     const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
     const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
     if (success) {
@@ -1094,6 +1094,7 @@
 
     setOutputDataSpace(display.outputDataspace);
     setDisplayMaxLuminance(display.maxLuminance);
+    setDisplayColorTransform(display.colorTransform);
 
     const mat4 projectionMatrix =
             ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix;
@@ -1160,7 +1161,7 @@
         position[3] = vec2(bounds.right, bounds.top);
 
         setupLayerCropping(*layer, mesh);
-        setColorTransform(display.colorTransform * layer->colorTransform);
+        setColorTransform(layer->colorTransform);
 
         bool usePremultipliedAlpha = true;
         bool disableTexture = true;
@@ -1274,7 +1275,8 @@
 
     if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) {
         glEnable(GL_BLEND);
-        glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+        glBlendFuncSeparate(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
+                            GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
     } else {
         glDisable(GL_BLEND);
     }
@@ -1316,6 +1318,10 @@
     mState.colorMatrix = colorTransform;
 }
 
+void GLESRenderEngine::setDisplayColorTransform(const mat4& colorTransform) {
+    mState.displayColorMatrix = colorTransform;
+}
+
 void GLESRenderEngine::disableTexturing() {
     mState.textureEnabled = false;
 }
@@ -1608,11 +1614,11 @@
     return context;
 }
 
-EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                          int hwcFormat, Protection protection) {
-    EGLConfig dummyConfig = config;
-    if (dummyConfig == EGL_NO_CONFIG) {
-        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+EGLSurface GLESRenderEngine::createStubEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                         int hwcFormat, Protection protection) {
+    EGLConfig stubConfig = config;
+    if (stubConfig == EGL_NO_CONFIG) {
+        stubConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
     std::vector<EGLint> attributes;
     attributes.reserve(7);
@@ -1626,7 +1632,7 @@
     }
     attributes.push_back(EGL_NONE);
 
-    return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
+    return eglCreatePbufferSurface(display, stubConfig, attributes.data());
 }
 
 bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index d5254a8..d554041 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -53,8 +53,8 @@
     static std::unique_ptr<GLESRenderEngine> create(const RenderEngineCreationArgs& args);
 
     GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config,
-                     EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
-                     EGLSurface protectedDummy);
+                     EGLContext ctxt, EGLSurface stub, EGLContext protectedContext,
+                     EGLSurface protectedStub);
     ~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
 
     void primeCache() const override;
@@ -121,8 +121,8 @@
     static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
                                        EGLContext shareContext, bool useContextPriority,
                                        Protection protection);
-    static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                   int hwcFormat, Protection protection);
+    static EGLSurface createStubEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                  int hwcFormat, Protection protection);
     std::unique_ptr<Framebuffer> createFramebuffer();
     std::unique_ptr<Image> createImage();
     void checkErrors() const;
@@ -165,6 +165,7 @@
     void setupLayerTexturing(const Texture& texture);
     void setupFillWithColor(float r, float g, float b, float a);
     void setColorTransform(const mat4& colorTransform);
+    void setDisplayColorTransform(const mat4& colorTransform);
     void disableTexturing();
     void disableBlending();
     void setupCornerRadiusCropSize(float width, float height);
@@ -181,9 +182,9 @@
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
-    EGLSurface mDummySurface;
+    EGLSurface mStubSurface;
     EGLContext mProtectedEGLContext;
-    EGLSurface mProtectedDummySurface;
+    EGLSurface mProtectedStubSurface;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
     GLuint mVpWidth;
diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
index f4fbf35..a172c56 100644
--- a/libs/renderengine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -66,6 +66,7 @@
         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
+        mDisplayColorMatrixLoc = glGetUniformLocation(programId, "displayColorMatrix");
         mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
         mMaxMasteringLuminanceLoc = glGetUniformLocation(programId, "maxMasteringLuminance");
         mMaxContentLuminanceLoc = glGetUniformLocation(programId, "maxContentLuminance");
@@ -129,6 +130,9 @@
         const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a};
         glUniform4fv(mColorLoc, 1, color);
     }
+    if (mDisplayColorMatrixLoc >= 0) {
+        glUniformMatrix4fv(mDisplayColorMatrixLoc, 1, GL_FALSE, desc.displayColorMatrix.asArray());
+    }
     if (mInputTransformMatrixLoc >= 0) {
         mat4 inputTransformMatrix = desc.inputTransformMatrix;
         glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h
index fc3755e..4292645 100644
--- a/libs/renderengine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -104,6 +104,7 @@
     /* location of transform matrix */
     GLint mInputTransformMatrixLoc;
     GLint mOutputTransformMatrixLoc;
+    GLint mDisplayColorMatrixLoc;
 
     /* location of corner radius uniform */
     GLint mCornerRadiusLoc;
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 3ae35ec..611755e 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -180,6 +180,10 @@
                  description.hasOutputTransformMatrix() || description.hasColorMatrix()
                          ? Key::OUTPUT_TRANSFORM_MATRIX_ON
                          : Key::OUTPUT_TRANSFORM_MATRIX_OFF)
+            .set(Key::Key::DISPLAY_COLOR_TRANSFORM_MATRIX_MASK,
+                 description.hasDisplayColorMatrix()
+                         ? Key::DISPLAY_COLOR_TRANSFORM_MATRIX_ON
+                         : Key::DISPLAY_COLOR_TRANSFORM_MATRIX_OFF)
             .set(Key::ROUNDED_CORNERS_MASK,
                  description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF)
             .set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF);
@@ -661,7 +665,9 @@
             )__SHADER__";
     }
 
-    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+    if (needs.hasTransformMatrix() ||
+        (needs.getInputTF() != needs.getOutputTF()) ||
+        needs.hasDisplayColorMatrix()) {
         if (needs.needsToneMapping()) {
             fs << "uniform float displayMaxLuminance;";
             fs << "uniform float maxMasteringLuminance;";
@@ -700,6 +706,21 @@
             )__SHADER__";
         }
 
+        if (needs.hasDisplayColorMatrix()) {
+            fs << "uniform mat4 displayColorMatrix;";
+            fs << R"__SHADER__(
+                highp vec3 DisplayColorMatrix(const highp vec3 color) {
+                    return clamp(vec3(displayColorMatrix * vec4(color, 1.0)), 0.0, 1.0);
+                }
+            )__SHADER__";
+        } else {
+            fs << R"__SHADER__(
+                highp vec3 DisplayColorMatrix(const highp vec3 color) {
+                    return color;
+                }
+            )__SHADER__";
+        }
+
         generateEOTF(fs, needs);
         generateOOTF(fs, needs);
         generateOETF(fs, needs);
@@ -721,6 +742,31 @@
         if (needs.isOpaque()) {
             fs << "gl_FragColor.a = 1.0;";
         }
+    }
+
+    if (needs.hasTransformMatrix() ||
+        (needs.getInputTF() != needs.getOutputTF()) ||
+        needs.hasDisplayColorMatrix()) {
+        if (!needs.isOpaque() && needs.isPremultiplied()) {
+            // un-premultiply if needed before linearization
+            // avoid divide by 0 by adding 0.5/256 to the alpha channel
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
+        }
+        fs << "gl_FragColor.rgb = "
+              "DisplayColorMatrix(OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb))))));";
+
+        if (!needs.isOpaque() && needs.isPremultiplied()) {
+            // and re-premultiply if needed after gamma correction
+            fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
+        }
+    }
+
+    /*
+     * Whether applying layer alpha before or after color transform doesn't matter,
+     * as long as we can undo premultiplication. But we cannot un-premultiply
+     * for color transform if the layer alpha = 0, e.g. 0 / (0 + 0.0019) = 0.
+     */
+    if (!needs.drawShadows()) {
         if (needs.hasAlpha()) {
             // modulate the current alpha value with alpha set
             if (needs.isPremultiplied()) {
@@ -732,20 +778,6 @@
         }
     }
 
-    if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
-        if (!needs.isOpaque() && needs.isPremultiplied()) {
-            // un-premultiply if needed before linearization
-            // avoid divide by 0 by adding 0.5/256 to the alpha channel
-            fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
-        }
-        fs << "gl_FragColor.rgb = "
-              "OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
-        if (!needs.isOpaque() && needs.isPremultiplied()) {
-            // and re-premultiply if needed after gamma correction
-            fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
-        }
-    }
-
     if (needs.hasRoundedCorners()) {
         if (needs.isPremultiplied()) {
             fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));";
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 901e631..b492cb3 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -117,6 +117,11 @@
             SHADOW_MASK = 1 << SHADOW_SHIFT,
             SHADOW_OFF = 0 << SHADOW_SHIFT,
             SHADOW_ON = 1 << SHADOW_SHIFT,
+
+            DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT = 14,
+            DISPLAY_COLOR_TRANSFORM_MATRIX_MASK = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
+            DISPLAY_COLOR_TRANSFORM_MATRIX_OFF = 0 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
+            DISPLAY_COLOR_TRANSFORM_MATRIX_ON = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
         };
 
         inline Key() : mKey(0) {}
@@ -143,6 +148,9 @@
         inline bool hasOutputTransformMatrix() const {
             return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
         }
+        inline bool hasDisplayColorMatrix() const {
+            return (mKey & DISPLAY_COLOR_TRANSFORM_MATRIX_MASK) == DISPLAY_COLOR_TRANSFORM_MATRIX_ON;
+        }
         inline bool hasTransformMatrix() const {
             return hasInputTransformMatrix() || hasOutputTransformMatrix();
         }
diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
index a62161a..fa6ec10 100644
--- a/libs/renderengine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -44,6 +44,7 @@
     bool hasInputTransformMatrix() const;
     bool hasOutputTransformMatrix() const;
     bool hasColorMatrix() const;
+    bool hasDisplayColorMatrix() const;
 
     // whether textures are premultiplied
     bool isPremultipliedAlpha = false;
@@ -79,6 +80,8 @@
 
     // The color matrix will be applied in linear space right before OETF.
     mat4 colorMatrix;
+    // The display color matrix will be applied in gamma space after OETF
+    mat4 displayColorMatrix;
     mat4 inputTransformMatrix;
     mat4 outputTransformMatrix;
 
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f577eb3..1ec9412 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -38,22 +38,27 @@
 
 struct RenderEngineTest : public ::testing::Test {
     static void SetUpTestSuite() {
-        sRE = renderengine::gl::GLESRenderEngine::create(
-                renderengine::RenderEngineCreationArgs::Builder()
-                    .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
-                    .setImageCacheSize(1)
-                    .setUseColorManagerment(false)
-                    .setEnableProtectedContext(false)
-                    .setPrecacheToneMapperShaderOnly(false)
-                    .setSupportsBackgroundBlur(true)
-                    .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-        .build());
+        renderengine::RenderEngineCreationArgs reCreationArgs =
+            renderengine::RenderEngineCreationArgs::Builder()
+                .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                .setImageCacheSize(1)
+                .setUseColorManagerment(false)
+                .setEnableProtectedContext(false)
+                .setPrecacheToneMapperShaderOnly(false)
+                .setSupportsBackgroundBlur(true)
+                .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+                .build();
+        sRE = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+
+        reCreationArgs.useColorManagement = true;
+        sRECM = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
     }
 
     static void TearDownTestSuite() {
         // The ordering here is important - sCurrentBuffer must live longer
         // than RenderEngine to avoid a null reference on tear-down.
         sRE = nullptr;
+        sRECM = nullptr;
         sCurrentBuffer = nullptr;
     }
 
@@ -83,6 +88,9 @@
             sRE->deleteTextures(1, &texName);
             EXPECT_FALSE(sRE->isTextureNameKnownForTesting(texName));
         }
+        for (uint32_t texName : mTexNamesCM) {
+            sRECM->deleteTextures(1, &texName);
+        }
     }
 
     void writeBufferToFile(const char* basename) {
@@ -251,9 +259,13 @@
 
     void invokeDraw(renderengine::DisplaySettings settings,
                     std::vector<const renderengine::LayerSettings*> layers,
-                    sp<GraphicBuffer> buffer) {
+                    sp<GraphicBuffer> buffer,
+                    bool useColorManagement = false) {
         base::unique_fd fence;
-        status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
+        status_t status = useColorManagement ?
+                          sRECM ->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
+                                             base::unique_fd(), &fence) :
+                          sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
                                           base::unique_fd(), &fence);
         sCurrentBuffer = buffer;
 
@@ -265,7 +277,11 @@
 
         ASSERT_EQ(NO_ERROR, status);
         if (layers.size() > 0) {
-            ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
+            if (useColorManagement) {
+                ASSERT_TRUE(sRECM->isFramebufferImageCachedForTesting(buffer->getId()));
+            } else {
+                ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
+            }
         }
     }
 
@@ -320,12 +336,21 @@
     void fillBufferLayerTransform();
 
     template <typename SourceVariant>
-    void fillBufferWithColorTransform();
+    void fillBufferWithColorTransform(bool useColorManagement = false);
 
     template <typename SourceVariant>
     void fillBufferColorTransform();
 
     template <typename SourceVariant>
+    void fillBufferColorTransformCM();
+
+    template <typename SourceVariant>
+    void fillBufferWithColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
+    void fillBufferColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
     void fillRedBufferWithRoundedCorners();
 
     template <typename SourceVariant>
@@ -364,6 +389,8 @@
     // For now, exercise the GL backend directly so that some caching specifics
     // can be tested without changing the interface.
     static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRE;
+    // renderengine object with Color Management enabled
+    static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRECM;
     // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
     // be freed *after* RenderEngine is destroyed, so that the EGL image is
     // destroyed first.
@@ -372,14 +399,17 @@
     sp<GraphicBuffer> mBuffer;
 
     std::vector<uint32_t> mTexNames;
+    std::vector<uint32_t> mTexNamesCM;
 };
 
 std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRE = nullptr;
+std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRECM = nullptr;
+
 sp<GraphicBuffer> RenderEngineTest::sCurrentBuffer = nullptr;
 
 struct ColorSourceVariant {
     static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
-                          RenderEngineTest* /*fixture*/) {
+                          RenderEngineTest* /*fixture*/, bool /*useColorManagement*/ = false) {
         layer.source.solidColor = half3(r, g, b);
     }
 };
@@ -407,11 +437,17 @@
 template <typename OpaquenessVariant>
 struct BufferSourceVariant {
     static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
-                          RenderEngineTest* fixture) {
+                          RenderEngineTest* fixture,
+                          bool useColorManagement = false) {
         sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
         uint32_t texName;
-        fixture->sRE->genTextures(1, &texName);
-        fixture->mTexNames.push_back(texName);
+        if (useColorManagement) {
+            fixture->sRECM->genTextures(1, &texName);
+            fixture->mTexNamesCM.push_back(texName);
+        } else {
+            fixture->sRE->genTextures(1, &texName);
+            fixture->mTexNames.push_back(texName);
+        }
 
         uint8_t* pixels;
         buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
@@ -641,7 +677,46 @@
 }
 
 template <typename SourceVariant>
-void RenderEngineTest::fillBufferWithColorTransform() {
+void RenderEngineTest::fillBufferWithColorTransform(bool useColorManagement) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = Rect(1, 1);
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+    SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this, useColorManagement);
+    layer.alpha = 1.0f;
+
+    // construct a fake color matrix
+    // annihilate green and blue channels
+    settings.colorTransform = mat4::scale(vec4(0.9f, 0, 0, 1));
+    // set red channel to red + green
+    layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+
+    layer.alpha = 1.0f;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(&layer);
+
+    invokeDraw(settings, layers, mBuffer, useColorManagement);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransform() {
+    fillBufferWithColorTransform<SourceVariant>();
+    expectBufferColor(fullscreenRect(), 172, 0, 0, 255, 1);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformCM() {
+    fillBufferWithColorTransform<SourceVariant>(true);
+    expectBufferColor(fullscreenRect(), 126, 0, 0, 255, 1);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
     settings.clip = Rect(1, 1);
@@ -651,15 +726,15 @@
     renderengine::LayerSettings layer;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
     SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
-    layer.alpha = 1.0f;
+    layer.alpha = 0;
 
     // construct a fake color matrix
-    // annihilate green and blue channels
-    settings.colorTransform = mat4::scale(vec4(1, 0, 0, 1));
-    // set red channel to red + green
-    layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+    // simple inverse color
+    settings.colorTransform = mat4(-1, 0, 0, 0,
+                                   0, -1, 0, 0,
+                                   0, 0, -1, 0,
+                                   1, 1, 1, 1);
 
-    layer.alpha = 1.0f;
     layer.geometry.boundaries = Rect(1, 1).toFloatRect();
 
     layers.push_back(&layer);
@@ -668,9 +743,9 @@
 }
 
 template <typename SourceVariant>
-void RenderEngineTest::fillBufferColorTransform() {
-    fillBufferWithColorTransform<SourceVariant>();
-    expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
+void RenderEngineTest::fillBufferColorTransformZeroLayerAlpha() {
+    fillBufferWithColorTransformZeroLayerAlpha<SourceVariant>();
+    expectBufferColor(fullscreenRect(), 0, 0, 0, 0);
 }
 
 template <typename SourceVariant>
@@ -917,7 +992,7 @@
 
 void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
     fillRedBufferWithoutPremultiplyAlpha();
-    expectBufferColor(fullscreenRect(), 128, 0, 0, 64, 1);
+    expectBufferColor(fullscreenRect(), 128, 0, 0, 128, 1);
 }
 
 void RenderEngineTest::clearLeftRegion() {
@@ -927,7 +1002,7 @@
     settings.clip = Rect(4, 4);
     settings.clearRegion = Region(Rect(2, 4));
     std::vector<const renderengine::LayerSettings*> layers;
-    // dummy layer, without bounds should not render anything
+    // fake layer, without bounds should not render anything
     renderengine::LayerSettings layer;
     layers.push_back(&layer);
     invokeDraw(settings, layers, mBuffer);
@@ -1073,7 +1148,15 @@
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
-    fillBufferLayerTransform<ColorSourceVariant>();
+    fillBufferColorTransform<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_colorSource) {
+    fillBufferColorTransformCM<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
+    fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
@@ -1129,7 +1212,15 @@
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
-    fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+    fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_opaqueBufferSource) {
+    fillBufferColorTransformCM<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
@@ -1185,7 +1276,15 @@
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
-    fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+    fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_bufferSource) {
+    fillBufferColorTransformCM<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
diff --git a/libs/sensorprivacy/OWNERS b/libs/sensorprivacy/OWNERS
new file mode 100644
index 0000000..be955f5
--- /dev/null
+++ b/libs/sensorprivacy/OWNERS
@@ -0,0 +1,3 @@
+cbrubaker@google.com
+evanseverson@google.com
+mpgroover@google.com
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 1ee8c71..47eb59f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -72,7 +72,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
@@ -89,7 +89,7 @@
 
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libgralloctypes",
     ],
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index 97ead21..b1317b1 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -1,7 +1,7 @@
+alecmouri@google.com
+chrisforbes@google.com
+jreck@google.com
 lpy@google.com
-marissaw@google.com
 mathias@google.com
 romainguy@google.com
 stoza@google.com
-jwcai@google.com
-tianyuj@google.com
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 013505a..57be686 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -260,6 +260,9 @@
 
     uint64_t mId;
 
+    // Unused, but removing this may break GSI.
+    int32_t mBufferId = -1;
+
     // Stores the generation number of this buffer. If this number does not
     // match the BufferQueue's internal generation number (set through
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
index e95a080..33ab8ba 100644
--- a/libs/vibrator/Android.bp
+++ b/libs/vibrator/Android.bp
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_shared {
+cc_library {
     name: "libvibrator",
 
     shared_libs: [
@@ -45,4 +45,11 @@
     ],
 
     export_include_dirs: ["include"],
+
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
new file mode 100644
index 0000000..0997e9f
--- /dev/null
+++ b/libs/vibrator/OWNERS
@@ -0,0 +1,2 @@
+lsandrade@google.com
+michaelwr@google.com
diff --git a/libs/vibrator/fuzzer/Android.bp b/libs/vibrator/fuzzer/Android.bp
new file mode 100644
index 0000000..8020151
--- /dev/null
+++ b/libs/vibrator/fuzzer/Android.bp
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+
+cc_fuzz {
+    name: "vibrator_fuzzer",
+
+    host_supported: true,
+
+    srcs: [
+        "vibrator_fuzzer.cpp",
+    ],
+
+    static_libs: [
+        "liblog",
+        "libvibrator",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libutils",
+    ],
+
+    fuzz_config: {
+        componentid: 155276,
+    },
+}
diff --git a/libs/vibrator/fuzzer/README.md b/libs/vibrator/fuzzer/README.md
new file mode 100644
index 0000000..43eb2d2
--- /dev/null
+++ b/libs/vibrator/fuzzer/README.md
@@ -0,0 +1,65 @@
+# Fuzzer for libvibrator
+
+## Plugin Design Considerations
+This fuzzer fuzzes native code present in libvibrator and does not cover the Java implementation ExternalVibration
+The fuzzer plugin is designed based on the understanding of the
+library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libvibrator supports the following parameters:
+1. Uid (parameter name: `uid`)
+2. Package Name (parameter name: `pkg`)
+3. Audio Content Type (parameter name: `content_type`)
+4. Audio Usage (parameter name: `usage`)
+5. Audio Source (parameter name: `source`)
+6. Audio flags (parameter name: `flags`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `uid` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider |
+| `pkg`   | Any std::string value | Value obtained from FuzzedDataProvider |
+| `content_type`   | 0.`AUDIO_CONTENT_TYPE_UNKNOWN` 1.`AUDIO_CONTENT_TYPE_SPEECH` 2.`AUDIO_CONTENT_TYPE_MUSIC` 3.`AUDIO_CONTENT_TYPE_MOVIE` 4.`AUDIO_CONTENT_TYPE_SONIFICATION`| Value obtained from FuzzedDataProvider in the range 0 to 4|
+| `usage`   | 0.`AUDIO_USAGE_UNKNOWN` 1.`AUDIO_USAGE_MEDIA` 2.`AUDIO_USAGE_VOICE_COMMUNICATION` 3.`AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING` 4.`AUDIO_USAGE_ALARM` 5.`AUDIO_USAGE_NOTIFICATION` 6.`AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE`  7.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST` 8.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT` 9.`AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED` 10.`AUDIO_USAGE_NOTIFICATION_EVENT` 11.`AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY` 12.`AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE` 13.`AUDIO_USAGE_ASSISTANCE_SONIFICATION` 14.`AUDIO_USAGE_GAME` 15.`AUDIO_USAGE_VIRTUAL_SOURCE` 16.`AUDIO_USAGE_ASSISTANT` 17.`AUDIO_USAGE_CALL_ASSISTANT` 18.`AUDIO_USAGE_EMERGENCY` 19.`AUDIO_USAGE_SAFETY` 20.`AUDIO_USAGE_VEHICLE_STATUS` 21.`AUDIO_USAGE_ANNOUNCEMENT`| Value obtained from FuzzedDataProvider in the range 0 to 21|
+| `source`   |  0.`AUDIO_SOURCE_DEFAULT` 1.`AUDIO_SOURCE_MIC` 2.`AUDIO_SOURCE_VOICE_UPLINK` 3.`AUDIO_SOURCE_VOICE_DOWNLINK` 4.`AUDIO_SOURCE_VOICE_CALL` 5.`AUDIO_SOURCE_CAMCORDER` 6.`AUDIO_SOURCE_VOICE_RECOGNITION` 7.`AUDIO_SOURCE_VOICE_COMMUNICATION` 8.`AUDIO_SOURCE_REMOTE_SUBMIX` 9.`AUDIO_SOURCE_UNPROCESSED` 10.`AUDIO_SOURCE_VOICE_PERFORMANCE` 11.`AUDIO_SOURCE_ECHO_REFERENCE` 12.`AUDIO_SOURCE_FM_TUNER` | Value obtained from FuzzedDataProvider in the range 0 to 12 |
+| `flags`   | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesn't `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build vibrator_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) vibrator_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/vibrator_fuzzer/vibrator_fuzzer CORPUS_DIR
+```
+
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/vibrator_fuzzer/vibrator_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/libs/vibrator/fuzzer/vibrator_fuzzer.cpp b/libs/vibrator/fuzzer/vibrator_fuzzer.cpp
new file mode 100644
index 0000000..68b3ca6
--- /dev/null
+++ b/libs/vibrator/fuzzer/vibrator_fuzzer.cpp
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+
+#include <binder/Parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vibrator/ExternalVibration.h>
+
+using namespace android;
+
+constexpr size_t MAX_STRING_LENGTH = 100;
+constexpr audio_content_type_t AUDIO_CONTENT_TYPE[] = {AUDIO_CONTENT_TYPE_UNKNOWN,
+                                                       AUDIO_CONTENT_TYPE_SPEECH,
+                                                       AUDIO_CONTENT_TYPE_MUSIC,
+                                                       AUDIO_CONTENT_TYPE_MOVIE,
+                                                       AUDIO_CONTENT_TYPE_SONIFICATION};
+constexpr audio_usage_t AUDIO_USAGE[] = {
+        AUDIO_USAGE_UNKNOWN,
+        AUDIO_USAGE_MEDIA,
+        AUDIO_USAGE_VOICE_COMMUNICATION,
+        AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+        AUDIO_USAGE_ALARM,
+        AUDIO_USAGE_NOTIFICATION,
+        AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+        AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+        AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+        AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+        AUDIO_USAGE_NOTIFICATION_EVENT,
+        AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+        AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+        AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+        AUDIO_USAGE_GAME,
+        AUDIO_USAGE_VIRTUAL_SOURCE,
+        AUDIO_USAGE_ASSISTANT,
+        AUDIO_USAGE_CALL_ASSISTANT,
+        AUDIO_USAGE_EMERGENCY,
+        AUDIO_USAGE_SAFETY,
+        AUDIO_USAGE_VEHICLE_STATUS,
+        AUDIO_USAGE_ANNOUNCEMENT,
+};
+constexpr audio_source_t AUDIO_SOURCE[] = {
+        AUDIO_SOURCE_DEFAULT,           AUDIO_SOURCE_MIC,
+        AUDIO_SOURCE_VOICE_UPLINK,      AUDIO_SOURCE_VOICE_DOWNLINK,
+        AUDIO_SOURCE_VOICE_CALL,        AUDIO_SOURCE_CAMCORDER,
+        AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_SOURCE_VOICE_COMMUNICATION,
+        AUDIO_SOURCE_REMOTE_SUBMIX,     AUDIO_SOURCE_UNPROCESSED,
+        AUDIO_SOURCE_VOICE_PERFORMANCE, AUDIO_SOURCE_ECHO_REFERENCE,
+        AUDIO_SOURCE_FM_TUNER,
+};
+constexpr size_t NUM_AUDIO_CONTENT_TYPE = std::size(AUDIO_CONTENT_TYPE);
+constexpr size_t NUM_AUDIO_USAGE = std::size(AUDIO_USAGE);
+constexpr size_t NUM_AUDIO_SOURCE = std::size(AUDIO_SOURCE);
+
+class TestVibrationController : public os::IExternalVibrationController {
+public:
+    explicit TestVibrationController() {}
+    IBinder *onAsBinder() override { return nullptr; }
+    binder::Status mute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+    binder::Status unmute(/*out*/ bool *ret) override {
+        *ret = false;
+        return binder::Status::ok();
+    };
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    if (size < 1) {
+        return 0;
+    }
+    FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+    // Initialize the parameters using FuzzedDataProvider
+    int32_t uid = fdp.ConsumeIntegral<int32_t>();
+    std::string pkg = fdp.ConsumeRandomLengthString(MAX_STRING_LENGTH);
+    audio_attributes_t attributes;
+    attributes.content_type =
+            AUDIO_CONTENT_TYPE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_CONTENT_TYPE - 1)];
+    attributes.usage = AUDIO_USAGE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_USAGE - 1)];
+    attributes.source = AUDIO_SOURCE[fdp.ConsumeIntegralInRange<uint32_t>(0, NUM_AUDIO_SOURCE - 1)];
+    attributes.flags = static_cast<audio_flags_mask_t>(fdp.ConsumeIntegral<uint32_t>());
+
+    // Create an instance of TestVibrationController
+    sp<TestVibrationController> vibrationController = new TestVibrationController();
+    if (!vibrationController) {
+        return 0;
+    }
+
+    // Set all the parameters in the constructor call
+    sp<os::ExternalVibration> extVibration =
+            new os::ExternalVibration(uid, pkg, attributes, vibrationController);
+    if (!extVibration) {
+        return 0;
+    }
+
+    // Get all the parameters that were previously set
+    extVibration->getUid();
+    extVibration->getPackage();
+    extVibration->getAudioAttributes();
+    extVibration->getController();
+
+    // Set the parameters in a Parcel object and send it to libvibrator
+    // This parcel shall be read by libvibrator
+    Parcel parcel;
+    parcel.writeInt32(uid);
+    parcel.writeString16(String16(pkg.c_str()));
+    parcel.writeStrongBinder(IInterface::asBinder(vibrationController));
+    parcel.setDataPosition(0);
+    extVibration->readFromParcel(&parcel);
+
+    // Send a Parcel to libvibrator
+    // Parameters shall be written to this parcel by libvibrator
+    extVibration->writeToParcel(&parcel);
+    return 0;
+}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 2fcee7b..37c19d4 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -16,6 +16,12 @@
     name: "libbufferhub_headers",
     export_include_dirs: ["include"],
     vendor_available: true,  // TODO(b/112338314): Does shouldn't be available to vendor.
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
 
 sourceFiles = [
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
index 8cc7081..fab1097 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue_producer-test.cpp
@@ -108,7 +108,7 @@
   void ConnectProducer() {
     IGraphicBufferProducer::QueueBufferOutput output;
     // Can connect the first time.
-    ASSERT_EQ(OK, mProducer->connect(kDummyListener, kTestApi,
+    ASSERT_EQ(OK, mProducer->connect(kStubListener, kTestApi,
                                      kTestControlledByApp, &output));
   }
 
@@ -140,7 +140,7 @@
     return QueueBufferInputBuilder().build();
   }
 
-  const sp<IProducerListener> kDummyListener{new DummyProducerListener};
+  const sp<IProducerListener> kStubListener{new StubProducerListener};
 
   sp<BufferHubProducer> mProducer;
   sp<Surface> mSurface;
@@ -150,11 +150,11 @@
   IGraphicBufferProducer::QueueBufferOutput output;
 
   // NULL output returns BAD_VALUE
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi,
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
                                           kTestControlledByApp, nullptr));
 
   // Invalid API returns bad value
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApiInvalid,
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApiInvalid,
                                           kTestControlledByApp, &output));
 }
 
@@ -163,7 +163,7 @@
 
   // Can't connect when there is already a producer connected.
   IGraphicBufferProducer::QueueBufferOutput output;
-  EXPECT_EQ(BAD_VALUE, mProducer->connect(kDummyListener, kTestApi,
+  EXPECT_EQ(BAD_VALUE, mProducer->connect(kStubListener, kTestApi,
                                           kTestControlledByApp, &output));
 }
 
@@ -554,18 +554,18 @@
   ProducerQueueParcelable producer_parcelable;
   EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), BAD_VALUE);
 
-  // Create a valid dummy producer parcelable.
-  auto dummy_channel_parcelable =
+  // Create a valid fake producer parcelable.
+  auto fake_channel_parcelable =
       std::make_unique<pdx::default_transport::ChannelParcelable>(
           LocalHandle(0), LocalHandle(0), LocalHandle(0));
-  EXPECT_TRUE(dummy_channel_parcelable->IsValid());
-  ProducerQueueParcelable dummy_producer_parcelable(
-      std::move(dummy_channel_parcelable));
-  EXPECT_TRUE(dummy_producer_parcelable.IsValid());
+  EXPECT_TRUE(fake_channel_parcelable->IsValid());
+  ProducerQueueParcelable fake_producer_parcelable(
+      std::move(fake_channel_parcelable));
+  EXPECT_TRUE(fake_producer_parcelable.IsValid());
 
   // Disconnect producer can be taken out, but only to an invalid parcelable.
   ASSERT_EQ(mProducer->disconnect(kTestApi), OK);
-  EXPECT_EQ(mProducer->TakeAsParcelable(&dummy_producer_parcelable), BAD_VALUE);
+  EXPECT_EQ(mProducer->TakeAsParcelable(&fake_producer_parcelable), BAD_VALUE);
   EXPECT_FALSE(producer_parcelable.IsValid());
   EXPECT_EQ(mProducer->TakeAsParcelable(&producer_parcelable), OK);
   EXPECT_TRUE(producer_parcelable.IsValid());
@@ -583,7 +583,7 @@
 
   // But connect to API will fail.
   IGraphicBufferProducer::QueueBufferOutput output;
-  EXPECT_EQ(mProducer->connect(kDummyListener, kTestApi, kTestControlledByApp,
+  EXPECT_EQ(mProducer->connect(kStubListener, kTestApi, kTestControlledByApp,
                                &output),
             BAD_VALUE);
 
@@ -592,8 +592,8 @@
   sp<BufferHubProducer> new_producer =
       BufferHubProducer::Create(std::move(producer_parcelable));
   ASSERT_TRUE(new_producer != nullptr);
-  EXPECT_EQ(new_producer->connect(kDummyListener, kTestApi,
-                                  kTestControlledByApp, &output),
+  EXPECT_EQ(new_producer->connect(kStubListener, kTestApi, kTestControlledByApp,
+                                  &output),
             OK);
 }
 
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 81a9b2d..d5a19d3 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -17,6 +17,12 @@
     name: "libdvr_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_library_headers {
@@ -74,6 +80,7 @@
 
 cc_library_shared {
     name: "libdvr.google",
+    system_ext_specific: true,
     owner: "google",
     cflags: cflags,
     header_libs: ["libdvr_headers"],
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index 7b3717e..07e2121 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -308,14 +308,6 @@
 class DvrDisplayManagerTest : public Test {
  protected:
   void SetUp() override {
-    // dvr display manager test doesn't apply to standalone vr devices because
-    // tests cannot create display manager client on these devices.
-    if (property_get_bool("ro.boot.vr", false)) {
-      GTEST_SKIP()
-          << "All tests in DvrDisplayManagerTest test case are skipped "
-             "because the device boot to VR.";
-    }
-
     int ret;
     DvrDisplayManager* display_manager;
     DvrSurfaceState* surface_state;
diff --git a/libs/vr/libpdx/encoder_performance_test.cpp b/libs/vr/libpdx/encoder_performance_test.cpp
index b7d94b3..7b477c4 100644
--- a/libs/vr/libpdx/encoder_performance_test.cpp
+++ b/libs/vr/libpdx/encoder_performance_test.cpp
@@ -158,12 +158,12 @@
                                            size_t iterations,
                                            ResetFunc* write_reset,
                                            void* reset_data, size_t data_size) {
-  std::vector<uint8_t> dummy_data(data_size);
+  std::vector<uint8_t> fake_data(data_size);
   auto start = std::chrono::high_resolution_clock::now();
   for (size_t i = 0; i < iterations; i++) {
     write_reset(reset_data);
-    memcpy(writer->GetNextWriteBufferSection(dummy_data.size()),
-           dummy_data.data(), dummy_data.size());
+    memcpy(writer->GetNextWriteBufferSection(fake_data.size()),
+           fake_data.data(), fake_data.size());
   }
   auto stop = std::chrono::high_resolution_clock::now();
   return stop - start;
@@ -177,17 +177,17 @@
     MessageReader* reader, MessageWriter* writer, size_t iterations,
     ResetFunc* read_reset, ResetFunc* write_reset, void* reset_data,
     size_t data_size) {
-  std::vector<uint8_t> dummy_data(data_size);
+  std::vector<uint8_t> fake_data(data_size);
   write_reset(reset_data);
-  memcpy(writer->GetNextWriteBufferSection(dummy_data.size()),
-         dummy_data.data(), dummy_data.size());
+  memcpy(writer->GetNextWriteBufferSection(fake_data.size()), fake_data.data(),
+         fake_data.size());
   auto start = std::chrono::high_resolution_clock::now();
   for (size_t i = 0; i < iterations; i++) {
     read_reset(reset_data);
     auto section = reader->GetNextReadBufferSection();
-    memcpy(dummy_data.data(), section.first, dummy_data.size());
+    memcpy(fake_data.data(), section.first, fake_data.size());
     reader->ConsumeReadBufferSectionData(
-        AdvancePointer(section.first, dummy_data.size()));
+        AdvancePointer(section.first, fake_data.size()));
   }
   auto stop = std::chrono::high_resolution_clock::now();
   return stop - start;
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
new file mode 100644
index 0000000..b36e0de
--- /dev/null
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -0,0 +1,62 @@
+cc_fuzz {
+    name: "libpdx_service_dispatcher_fuzzer",
+    clang: true,
+    srcs: [
+        "service_dispatcher_fuzzer.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    static_libs: [
+        "libpdx",
+    ],
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libcutils"
+    ],
+}
+
+cc_fuzz {
+    name: "libpdx_message_fuzzer",
+    clang: true,
+    srcs: [
+        "message_fuzzer.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    static_libs: [
+        "libpdx",
+    ],
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libcutils"
+    ],
+}
+
+cc_fuzz {
+    name: "libpdx_serialization_fuzzer",
+    clang: true,
+    srcs: [
+        "serialization_fuzzer.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    static_libs: [
+        "libpdx",
+    ],
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libcutils"
+    ],
+}
diff --git a/libs/vr/libpdx/fuzz/helpers.h b/libs/vr/libpdx/fuzz/helpers.h
new file mode 100644
index 0000000..83ec409
--- /dev/null
+++ b/libs/vr/libpdx/fuzz/helpers.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          brian.balling@leviathansecurity.com
+
+#ifndef LEV_FUZZERS_LIBPDX_HELPERS_H_
+#define LEV_FUZZERS_LIBPDX_HELPERS_H_
+
+#define UNUSED(expr) \
+  do {               \
+    (void)(expr);    \
+  } while (0)
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <pdx/client.h>
+#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
+#include <pdx/service_endpoint.h>
+#include <sys/eventfd.h>
+#include <memory>
+#include <vector>
+
+using namespace android::pdx;
+
+// Vector of operations we can call in the dispatcher.
+static const std::vector<std::function<void(
+    const std::unique_ptr<ServiceDispatcher>&, FuzzedDataProvider*)>>
+    dispatcher_operations = {
+        [](const std::unique_ptr<ServiceDispatcher>& dispatcher,
+           FuzzedDataProvider*) -> void { dispatcher->EnterDispatchLoop(); },
+        [](const std::unique_ptr<ServiceDispatcher>& dispatcher,
+           FuzzedDataProvider*) -> void { dispatcher->ReceiveAndDispatch(); },
+        [](const std::unique_ptr<ServiceDispatcher>& dispatcher,
+           FuzzedDataProvider* fdp) -> void {
+          dispatcher->ReceiveAndDispatch(fdp->ConsumeIntegral<int>());
+        }};
+
+// Most of the fuzzing occurs within the endpoint, which is derived from an
+// abstract class. So we are returning garbage data for most functions besides
+// the ones we added or need to actually use.
+class FuzzEndpoint : public Endpoint {
+ public:
+  explicit FuzzEndpoint(FuzzedDataProvider* fdp) {
+    _fdp = fdp;
+    _epoll_fd = eventfd(0, 0);
+  }
+
+  ~FuzzEndpoint() { close(_epoll_fd); }
+
+  // Returns an fd that can be used with epoll() to wait for incoming messages
+  // from this endpoint.
+  int epoll_fd() const { return _epoll_fd; }
+
+  // Associates a Service instance with an endpoint by setting the service
+  // context pointer to the address of the Service. Only one Service may be
+  // associated with a given endpoint.
+  Status<void> SetService(Service* service) {
+    _service = service;
+    return Status<void>(0);
+  }
+
+  // Set the channel context for the given channel.
+  Status<void> SetChannel(int channel_id, Channel* channel) {
+    UNUSED(channel_id);
+    _channel = std::shared_ptr<Channel>(channel);
+    return Status<void>(0);
+  }
+
+  // Receives a message on the given endpoint file descriptor.
+  // This is called by the dispatcher to determine what operations
+  // to make, so we are fuzzing the response.
+  Status<void> MessageReceive(Message* message) {
+    // Create a randomized MessageInfo struct.
+    MessageInfo info;
+    eventfd_t wakeup_val = 0;
+    info.pid = _fdp->ConsumeIntegral<int>();
+    info.tid = _fdp->ConsumeIntegral<int>();
+    info.cid = _fdp->ConsumeIntegral<int>();
+    info.mid = _fdp->ConsumeIntegral<int>();
+    info.euid = _fdp->ConsumeIntegral<int>();
+    info.egid = _fdp->ConsumeIntegral<int>();
+    info.op = _fdp->ConsumeIntegral<int32_t>();
+    info.flags = _fdp->ConsumeIntegral<uint32_t>();
+    info.service = _service;
+    info.channel = _channel.get();
+    info.send_len = _fdp->ConsumeIntegral<size_t>();
+    info.recv_len = _fdp->ConsumeIntegral<size_t>();
+    info.fd_count = _fdp->ConsumeIntegral<size_t>();
+    if (_fdp->remaining_bytes() >= 32) {
+      std::vector<uint8_t> impulse_vec = _fdp->ConsumeBytes<uint8_t>(32);
+      memcpy(info.impulse, impulse_vec.data(), 32);
+    }
+
+    *message = Message(info);
+    eventfd_read(_epoll_fd, &wakeup_val);
+
+    return Status<void>();
+  }
+
+  // Returns a tag that uniquely identifies a specific underlying IPC
+  // transport.
+  uint32_t GetIpcTag() const { return 0; }
+
+  // Close a channel, signaling the client file object and freeing the channel
+  // id. Once closed, the client side of the channel always returns the error
+  // ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE.
+  Status<void> CloseChannel(int channel_id) {
+    UNUSED(channel_id);
+    return Status<void>();
+  }
+
+  // Update the event bits for the given channel (given by id), using the
+  // given clear and set masks.
+  Status<void> ModifyChannelEvents(int channel_id, int clear_mask,
+                                   int set_mask) {
+    UNUSED(channel_id);
+    UNUSED(clear_mask);
+    UNUSED(set_mask);
+    return Status<void>();
+  }
+
+  // Create a new channel and push it as a file descriptor to the process
+  // sending the |message|. |flags| may be set to O_NONBLOCK and/or
+  // O_CLOEXEC to control the initial behavior of the new file descriptor (the
+  // sending process may change these later using fcntl()). The internal
+  // Channel instance associated with this channel is set to |channel|,
+  // which may be nullptr. The new channel id allocated for this channel is
+  // returned in |channel_id|, which may also be nullptr if not needed.
+  Status<RemoteChannelHandle> PushChannel(Message* message, int flags,
+                                          Channel* channel, int* channel_id) {
+    UNUSED(message);
+    UNUSED(flags);
+    UNUSED(channel);
+    UNUSED(channel_id);
+    return Status<RemoteChannelHandle>();
+  }
+
+  // Check whether the |ref| is a reference to a channel to the service
+  // represented by the |endpoint|. If the channel reference in question is
+  // valid, the Channel object is returned in |channel| when non-nullptr and
+  // the channel ID is returned through the Status object.
+  Status<int> CheckChannel(const Message* message, ChannelReference ref,
+                           Channel** channel) {
+    UNUSED(message);
+    UNUSED(ref);
+    UNUSED(channel);
+    return Status<int>();
+  }
+
+  // Replies to the message with a return code.
+  Status<void> MessageReply(Message* message, int return_code) {
+    UNUSED(message);
+    UNUSED(return_code);
+    return Status<void>();
+  }
+
+  // Replies to the message with a file descriptor.
+  Status<void> MessageReplyFd(Message* message, unsigned int push_fd) {
+    UNUSED(message);
+    UNUSED(push_fd);
+    return Status<void>();
+  }
+
+  // Replies to the message with a local channel handle.
+  Status<void> MessageReplyChannelHandle(Message* message,
+                                         const LocalChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<void>();
+  }
+
+  // Replies to the message with a borrowed local channel handle.
+  Status<void> MessageReplyChannelHandle(Message* message,
+                                         const BorrowedChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<void>();
+  }
+
+  // Replies to the message with a remote channel handle.
+  Status<void> MessageReplyChannelHandle(Message* message,
+                                         const RemoteChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<void>();
+  }
+
+  // Reads message data into an array of memory buffers.
+  Status<size_t> ReadMessageData(Message* message, const iovec* vector,
+                                 size_t vector_length) {
+    UNUSED(message);
+    UNUSED(vector);
+    UNUSED(vector_length);
+    return Status<size_t>();
+  }
+
+  // Sends reply data for message.
+  Status<size_t> WriteMessageData(Message* message, const iovec* vector,
+                                  size_t vector_length) {
+    UNUSED(message);
+    UNUSED(vector);
+    UNUSED(vector_length);
+    return Status<size_t>();
+  }
+
+  // Records a file descriptor into the message buffer and returns the
+  // remapped reference to be sent to the remote process.
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const LocalHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<FileReference>();
+  }
+
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const BorrowedHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<FileReference>();
+  }
+
+  Status<FileReference> PushFileHandle(Message* message,
+                                       const RemoteHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<FileReference>();
+  }
+
+  Status<ChannelReference> PushChannelHandle(Message* message,
+                                             const LocalChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<ChannelReference>();
+  }
+
+  Status<ChannelReference> PushChannelHandle(
+      Message* message, const BorrowedChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<ChannelReference>();
+  }
+
+  Status<ChannelReference> PushChannelHandle(
+      Message* message, const RemoteChannelHandle& handle) {
+    UNUSED(message);
+    UNUSED(handle);
+    return Status<ChannelReference>();
+  }
+
+  // Obtains a file descriptor/channel handle from a message for the given
+  // reference.
+  LocalHandle GetFileHandle(Message* message, FileReference ref) const {
+    UNUSED(message);
+    UNUSED(ref);
+    return LocalHandle();
+  }
+
+  LocalChannelHandle GetChannelHandle(Message* message,
+                                      ChannelReference ref) const {
+    UNUSED(message);
+    UNUSED(ref);
+    return LocalChannelHandle();
+  }
+
+  // Transport-specific message state management.
+  void* AllocateMessageState() { return nullptr; }
+
+  void FreeMessageState(void* state) { UNUSED(state); }
+
+  // Cancels the endpoint, unblocking any receiver threads waiting for a
+  // message.
+  Status<void> Cancel() { return Status<void>(); }
+
+ private:
+  FuzzedDataProvider* _fdp;
+  std::shared_ptr<Channel> _channel;
+  Service* _service;
+  int _epoll_fd;
+};
+
+#endif  // LEV_FUZZERS_LIBPDX_HELPERS_H_
diff --git a/libs/vr/libpdx/fuzz/message_fuzzer.cpp b/libs/vr/libpdx/fuzz/message_fuzzer.cpp
new file mode 100644
index 0000000..b627045
--- /dev/null
+++ b/libs/vr/libpdx/fuzz/message_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          brian.balling@leviathansecurity.com
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <helpers.h>
+#include <pdx/client_channel.h>
+#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/eventfd.h>
+#include <thread>
+
+using namespace android::pdx;
+
+// Fuzzer for Message object functions.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+  FuzzEndpoint* endpoint = new FuzzEndpoint(&fdp);
+  std::shared_ptr<Service> service(
+      new Service("FuzzService", std::unique_ptr<Endpoint>(endpoint)));
+  std::shared_ptr<Channel> channel(nullptr);
+
+  // Generate a random Message object to call functions in.
+  MessageInfo info;
+  info.pid = fdp.ConsumeIntegral<int>();
+  info.tid = fdp.ConsumeIntegral<int>();
+  info.cid = fdp.ConsumeIntegral<int>();
+  info.mid = fdp.ConsumeIntegral<int>();
+  info.euid = fdp.ConsumeIntegral<int>();
+  info.egid = fdp.ConsumeIntegral<int>();
+  info.op = fdp.ConsumeIntegral<int32_t>();
+  info.flags = fdp.ConsumeIntegral<uint32_t>();
+  info.service = service.get();
+  info.channel = channel.get();
+  info.send_len = fdp.ConsumeIntegral<size_t>();
+  info.recv_len = fdp.ConsumeIntegral<size_t>();
+  info.fd_count = fdp.ConsumeIntegral<size_t>();
+  if (fdp.remaining_bytes() >= 32) {
+    std::vector<uint8_t> impulse_vec = fdp.ConsumeBytes<uint8_t>(32);
+    memcpy(info.impulse, impulse_vec.data(), 32);
+  }
+
+  Message message = Message(info);
+
+  // A bunch of getters that probably won't do much, but might as well
+  // get coverage, while we are here.
+  message.GetProcessId();
+  message.GetThreadId();
+  message.GetEffectiveUserId();
+  message.GetEffectiveGroupId();
+  message.GetChannelId();
+  message.GetMessageId();
+  message.GetOp();
+  message.GetFlags();
+  message.GetSendLength();
+  message.GetReceiveLength();
+  message.GetFileDescriptorCount();
+  message.ImpulseEnd();
+  message.replied();
+  message.IsChannelExpired();
+  message.IsServiceExpired();
+  message.GetState();
+  message.GetState();
+
+  // Some misc. functions.
+  unsigned int fd = fdp.ConsumeIntegral<unsigned int>();
+  int clear_mask = fdp.ConsumeIntegral<int>();
+  int set_mask = fdp.ConsumeIntegral<int>();
+  Status<void> status = {};
+  message.ModifyChannelEvents(clear_mask, set_mask);
+
+  // Fuzz the handle functions.
+  LocalHandle l_handle = {};
+  BorrowedHandle b_handle = {};
+  RemoteHandle r_handle = {};
+  LocalChannelHandle lc_handle = {};
+  BorrowedChannelHandle bc_handle = {};
+  RemoteChannelHandle rc_handle = {};
+  FileReference f_ref = fdp.ConsumeIntegral<int32_t>();
+  ChannelReference c_ref = fdp.ConsumeIntegral<int32_t>();
+
+  // These don't actually modify any state in the Message or params.
+  // They can be called in any order.
+  message.PushFileHandle(b_handle);
+  message.PushFileHandle(r_handle);
+  message.PushChannelHandle(lc_handle);
+  message.PushChannelHandle(bc_handle);
+  message.PushChannelHandle(rc_handle);
+  message.GetFileHandle(f_ref, &l_handle);
+  message.GetChannelHandle(c_ref, &lc_handle);
+
+  // Can only reply once, pick at random.
+  switch (fdp.ConsumeIntegral<uint8_t>()) {
+    case 0:
+      message.ReplyFileDescriptor(fd);
+      break;
+    case 1:
+      message.Reply(status);
+      break;
+    case 2:
+      message.Reply(l_handle);
+      break;
+    case 3:
+      message.Reply(b_handle);
+      break;
+    case 4:
+      message.Reply(r_handle);
+      break;
+    case 5:
+      message.Reply(lc_handle);
+      break;
+    case 6:
+      message.Reply(bc_handle);
+      break;
+    case 7:
+      message.Reply(rc_handle);
+  }
+
+  // Fuzz the channel functions.
+  int flags = fdp.ConsumeIntegral<int>();
+  int channel_id = 0;
+  message.PushChannel(flags, channel, &channel_id);
+  message.CheckChannel(service.get(), c_ref, &channel);
+  message.CheckChannel(c_ref, &channel);
+  message.PushChannel(service.get(), flags, channel, &channel_id);
+  size_t iovec_size = sizeof(iovec);
+  struct iovec* iovecs = nullptr;
+
+  // Fuzz the read/write functions. Needs at least one iovec, plus one byte.
+  if (fdp.remaining_bytes() >= iovec_size + 1) {
+    std::vector<uint8_t> tmp_vec = fdp.ConsumeBytes<uint8_t>(iovec_size);
+    struct iovec* vector = reinterpret_cast<struct iovec*>(tmp_vec.data());
+    std::vector<uint8_t> tmp_buf =
+        fdp.ConsumeBytes<uint8_t>(fdp.remaining_bytes());
+    void* buf = reinterpret_cast<void*>(tmp_buf.data());
+    size_t buf_size = fdp.ConsumeIntegral<size_t>();
+
+    // Capping num_vecs to 1024 so it doesn't allocate too much memory.
+    size_t num_vecs = fdp.ConsumeIntegralInRange<size_t>(0, 1024);
+
+    if (num_vecs > 0)
+      iovecs = new struct iovec[num_vecs];
+    for (size_t i = 0; i < num_vecs; i++) {
+      iovecs[i] = *vector;
+    }
+
+    message.ReadAll(vector, buf_size);
+    message.WriteAll(buf, buf_size);
+    message.ReadVectorAll(vector, num_vecs);
+    message.WriteVectorAll(vector, num_vecs);
+    message.ReadVector(vector, buf_size);
+    message.WriteVector(vector, buf_size);
+  }
+
+  if (iovecs != nullptr)
+    delete[] iovecs;
+  return 0;
+}
diff --git a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
new file mode 100644
index 0000000..f5c5a5a
--- /dev/null
+++ b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          brian.balling@leviathansecurity.com
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <pdx/rpc/argument_encoder.h>
+#include <pdx/rpc/array_wrapper.h>
+#include <pdx/rpc/default_initialization_allocator.h>
+#include <pdx/rpc/payload.h>
+#include <pdx/rpc/serializable.h>
+#include <pdx/rpc/serialization.h>
+#include <pdx/rpc/string_wrapper.h>
+#include <pdx/utility.h>
+
+using namespace android::pdx;
+using namespace android::pdx::rpc;
+
+struct FuzzType {
+  int a;
+  float b;
+  std::string c;
+
+  FuzzType() {}
+  FuzzType(int a, float b, const std::string& c) : a(a), b(b), c(c) {}
+
+ private:
+  PDX_SERIALIZABLE_MEMBERS(FuzzType, a, b, c);
+};
+
+// Fuzzer for Serialization operations, this is mostly just lifted from the
+// existing test cases to use fuzzed values as inputs.
+void FuzzSerializeDeserialize(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload result;
+
+  // Currently, only fuzzing subset of types. In the future, may want
+  // to add more difficult to generate types like array, map, enum, etc...
+  bool b_val = fdp.ConsumeBool();
+  uint8_t u8_val = fdp.ConsumeIntegral<uint8_t>();
+  uint16_t u16_val = fdp.ConsumeIntegral<uint16_t>();
+  uint32_t u32_val = fdp.ConsumeIntegral<uint32_t>();
+  uint64_t u64_val = fdp.ConsumeIntegral<uint64_t>();
+  int8_t i8_val = fdp.ConsumeIntegral<int8_t>();
+  int16_t i16_val = fdp.ConsumeIntegral<uint16_t>();
+  int32_t i32_val = fdp.ConsumeIntegral<uint32_t>();
+  int64_t i64_val = fdp.ConsumeIntegral<uint64_t>();
+  float f_val = fdp.ConsumeFloatingPoint<float>();
+  double d_val = fdp.ConsumeFloatingPoint<double>();
+  std::string s_val = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+  std::vector<uint8_t> vec_val =
+      fdp.ConsumeBytes<uint8_t>(fdp.remaining_bytes());
+  FuzzType t1_val{reinterpret_cast<int>(i32_val), f_val, s_val};
+
+  // Types need to be individually fuzzed because code path changes depending
+  // on which type is being serialized/deserialized.
+  Serialize(b_val, &result);
+  Deserialize(&b_val, &result);
+  Serialize(u8_val, &result);
+  Deserialize(&u8_val, &result);
+  Serialize(u16_val, &result);
+  Deserialize(&u16_val, &result);
+  Serialize(u32_val, &result);
+  Deserialize(&u32_val, &result);
+  Serialize(u64_val, &result);
+  Deserialize(&u64_val, &result);
+  Serialize(i8_val, &result);
+  Deserialize(&i8_val, &result);
+  Serialize(i16_val, &result);
+  Deserialize(&i16_val, &result);
+  Serialize(i32_val, &result);
+  Deserialize(&i32_val, &result);
+  Serialize(i64_val, &result);
+  Deserialize(&i64_val, &result);
+  Serialize(f_val, &result);
+  Deserialize(&f_val, &result);
+  Serialize(d_val, &result);
+  Deserialize(&d_val, &result);
+  Serialize(s_val, &result);
+  Deserialize(&s_val, &result);
+  Serialize(WrapString(s_val), &result);
+  Deserialize(&s_val, &result);
+  Serialize(vec_val, &result);
+  Deserialize(&vec_val, &result);
+  Serialize(t1_val, &result);
+  Deserialize(&t1_val, &result);
+}
+
+void FuzzDeserializeUint8(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_UINT8, fdp.ConsumeIntegral<uint8_t>()};
+  std::uint8_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint16(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_UINT16, fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  std::uint16_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint32(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_UINT32, fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  std::uint32_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeUint64(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {
+      ENCODING_TYPE_UINT64,           fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>()};
+  std::uint64_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt8(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_INT8, fdp.ConsumeIntegral<uint8_t>()};
+  std::int8_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt16(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_INT16, fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  std::int16_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt32(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_INT32, fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  std::int32_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeInt64(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_INT64,
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  std::int64_t result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFloat32(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_FLOAT32, fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  float floatResult;
+  Deserialize(&floatResult, &buffer);
+
+  buffer.Rewind();
+  double doubleResult;
+  Deserialize(&doubleResult, &buffer);
+}
+
+void FuzzDeserializeFloat64(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {
+      ENCODING_TYPE_FLOAT64,          fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>(), fdp.ConsumeIntegral<uint8_t>(),
+      fdp.ConsumeIntegral<uint8_t>()};
+  double result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFixstr(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  std::string s_val = fdp.ConsumeRemainingBytesAsString();
+  Payload buffer = {ENCODING_TYPE_FIXSTR_MAX};
+  for (std::string::iterator iter = s_val.begin(); iter != s_val.end();
+       iter++) {
+    buffer.Append(1, *iter);
+  }
+  std::string result;
+  Deserialize(&result, &buffer);
+}
+
+void FuzzDeserializeFixmap(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_FIXMAP_MAX};
+  // Fill the map with the fuzzed data, not attempting to
+  // make a valid map
+  while (fdp.remaining_bytes() > 0) {
+    buffer.Append(1, fdp.ConsumeIntegral<uint8_t>());
+  }
+
+  std::map<std::uint32_t, std::uint32_t> result;
+  Deserialize(&result, &buffer);
+
+  buffer.Rewind();
+  std::unordered_map<std::uint32_t, std::uint32_t> unorderedResult;
+  Deserialize(&unorderedResult, &buffer);
+}
+
+void FuzzDeserializeVariant(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  Payload buffer = {ENCODING_TYPE_INT16,
+                    ENCODING_TYPE_FLOAT32,
+                    ENCODING_TYPE_FIXSTR_MAX,
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>(),
+                    fdp.ConsumeIntegral<uint8_t>()};
+  // Add the rest of the data as a string
+  std::string s_val = fdp.ConsumeRemainingBytesAsString();
+  for (std::string::iterator iter = s_val.begin(); iter != s_val.end();
+       iter++) {
+    buffer.Append(1, *iter);
+  }
+  Variant<int, float, std::string> result;
+  Deserialize(&result, &buffer);
+}
+
+// Attempts to deserialize fuzzed data as various types
+void FuzzDeserialize(const uint8_t* data, size_t size) {
+  FuzzDeserializeUint8(data, size);
+  FuzzDeserializeUint16(data, size);
+  FuzzDeserializeUint32(data, size);
+  FuzzDeserializeUint64(data, size);
+  FuzzDeserializeInt8(data, size);
+  FuzzDeserializeInt16(data, size);
+  FuzzDeserializeInt32(data, size);
+  FuzzDeserializeInt64(data, size);
+  FuzzDeserializeFloat32(data, size);
+  FuzzDeserializeFloat64(data, size);
+  FuzzDeserializeFixstr(data, size);
+  FuzzDeserializeFixmap(data, size);
+  FuzzDeserializeVariant(data, size);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  FuzzSerializeDeserialize(data, size);
+  FuzzDeserialize(data, size);
+
+  return 0;
+}
diff --git a/libs/vr/libpdx/fuzz/service_dispatcher_fuzzer.cpp b/libs/vr/libpdx/fuzz/service_dispatcher_fuzzer.cpp
new file mode 100644
index 0000000..3a3bfd9
--- /dev/null
+++ b/libs/vr/libpdx/fuzz/service_dispatcher_fuzzer.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          brian.balling@leviathansecurity.com
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <helpers.h>
+#include <pdx/client_channel.h>
+#include <pdx/service.h>
+#include <pdx/service_dispatcher.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/eventfd.h>
+#include <thread>
+
+using namespace android::pdx;
+
+// Dispatch fuzzer entry point. This fuzzer creates a ServiceDispatcher
+// and creates an endpoint that returns fuzzed messages that are passed
+// to the ReceiveAndDispatch and DispatchLoop functions.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  eventfd_t wakeup_val = 1;
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+  // Endpoint is only used to be immediately wrapped as a unique_ptr,
+  // so it is ok to be using a raw ptr and new here without freeing.
+  FuzzEndpoint* endpoint = new FuzzEndpoint(&fdp);
+  std::unique_ptr<ServiceDispatcher> dispatcher = ServiceDispatcher::Create();
+  std::shared_ptr<Channel> channel(nullptr);
+  std::shared_ptr<Client> client(nullptr);
+  std::shared_ptr<Service> service(
+      new Service("FuzzService", std::unique_ptr<Endpoint>(endpoint)));
+
+  service->SetChannel(0, std::shared_ptr<Channel>(channel));
+  dispatcher->AddService(service);
+
+  // Dispatcher blocks, so needs to run in its own thread.
+  std::thread run_dispatcher([&]() {
+    uint8_t opt = 0;
+
+    // Right now the only operations block, so the while loop is pointless
+    // but leaving it in, just in case that ever changes.
+    while (fdp.remaining_bytes() > sizeof(MessageInfo)) {
+      opt = fdp.ConsumeIntegral<uint8_t>() % dispatcher_operations.size();
+      dispatcher_operations[opt](dispatcher, &fdp);
+    }
+  });
+
+  // Continuously wake up the epoll so the dispatcher can run.
+  while (fdp.remaining_bytes() > sizeof(MessageInfo)) {
+    eventfd_write(endpoint->epoll_fd(), wakeup_val);
+  }
+
+  // Cleanup the dispatcher and thread.
+  dispatcher->SetCanceled(true);
+  if (run_dispatcher.joinable())
+    run_dispatcher.join();
+  dispatcher->RemoveService(service);
+
+  return 0;
+}
diff --git a/libs/vr/libpdx/private/pdx/rpc/macros.h b/libs/vr/libpdx/private/pdx/rpc/macros.h
index aeae9d3..99325b5 100644
--- a/libs/vr/libpdx/private/pdx/rpc/macros.h
+++ b/libs/vr/libpdx/private/pdx/rpc/macros.h
@@ -28,7 +28,7 @@
 // Clears any remaining contents wrapped in parentheses.
 #define _PDX_CLEAR(...)
 
-// Introduces a first dummy argument and _PDX_CLEAR as second argument.
+// Introduces a first stub argument and _PDX_CLEAR as second argument.
 #define _PDX_CLEAR_IF_LAST() _, _PDX_CLEAR
 
 // Returns the first argument of a list.
@@ -45,7 +45,7 @@
 // Returns next_func if the next element is not (), or _PDX_CLEAR
 // otherwise.
 //
-// _PDX_CLEAR_IF_LAST inserts an extra first dummy argument if peek is ().
+// _PDX_CLEAR_IF_LAST inserts an extra first stub argument if peek is ().
 #define _PDX_NEXT_FUNC(next_element, next_func) \
   _PDX_EXPAND_NEXT_FUNC(_PDX_CLEAR_IF_LAST next_element, next_func)
 
diff --git a/libs/vr/libpdx/service_dispatcher.cpp b/libs/vr/libpdx/service_dispatcher.cpp
index b112fa3..ba0d69c 100644
--- a/libs/vr/libpdx/service_dispatcher.cpp
+++ b/libs/vr/libpdx/service_dispatcher.cpp
@@ -92,9 +92,9 @@
   if (thread_count_ > 0)
     return -EBUSY;
 
-  epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
+  epoll_event ee;  // See BUGS in man 2 epoll_ctl.
   if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, service->endpoint()->epoll_fd(),
-                &dummy) < 0) {
+                &ee) < 0) {
     ALOGE("Failed to remove service from dispatcher because: %s\n",
           strerror(errno));
     return -errno;
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 1ce9c99..b3534de 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -45,6 +45,7 @@
 
 cc_binary {
     name: "pdx_tool",
+    system_ext_specific: true,
     defaults: ["pdx_default_transport_compiler_defaults"],
     srcs: [
         "pdx_tool.cpp",
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 9bc70ea..810eb19 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -334,8 +334,8 @@
 
   int channel_fd = iter->second.data_fd.Get();
   Status<void> status;
-  epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_fd, &dummy) < 0) {
+  epoll_event ee;  // See BUGS in man 2 epoll_ctl.
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, channel_fd, &ee) < 0) {
     status.SetError(errno);
     ALOGE(
         "Endpoint::CloseChannelLocked: Failed to remove channel from endpoint: "
diff --git a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
index 1cf5f17..0d5eb80 100644
--- a/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
+++ b/libs/vr/libvrflinger/epoll_event_dispatcher.cpp
@@ -68,8 +68,8 @@
   ALOGD_IF(TRACE, "EpollEventDispatcher::RemoveEventHandler: fd=%d", fd);
   std::lock_guard<std::mutex> lock(lock_);
 
-  epoll_event dummy;  // See BUGS in man 2 epoll_ctl.
-  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, fd, &dummy) < 0) {
+  epoll_event ee;  // See BUGS in man 2 epoll_ctl.
+  if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_DEL, fd, &ee) < 0) {
     const int error = errno;
     ALOGE("Failed to remove fd from epoll set because: %s", strerror(error));
     return pdx::ErrorStatus(error);
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index b771538..70f303b 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -47,7 +47,6 @@
 namespace {
 
 const char kDvrPerformanceProperty[] = "sys.dvr.performance";
-const char kDvrStandaloneProperty[] = "ro.boot.vr";
 
 const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
 
@@ -159,8 +158,6 @@
     return false;
   }
 
-  is_standalone_device_ = property_get_bool(kDvrStandaloneProperty, false);
-
   request_display_callback_ = request_display_callback;
 
   primary_display_ = GetDisplayParams(composer, primary_display_id, true);
@@ -206,8 +203,6 @@
     return;
   boot_finished_ = true;
   post_thread_wait_.notify_one();
-  if (is_standalone_device_)
-    request_display_callback_(true);
 }
 
 // Update the post thread quiescent state based on idle and suspended inputs.
@@ -267,17 +262,11 @@
   layers_.clear();
 
   // Phones create a new composer client on resume and destroy it on pause.
-  // Standalones only create the composer client once and then use SetPowerMode
-  // to control the screen on pause/resume.
-  if (!is_standalone_device_) {
-    if (composer_callback_ != nullptr) {
-      composer_callback_->SetVsyncService(nullptr);
-      composer_callback_ = nullptr;
-    }
-    composer_.reset(nullptr);
-  } else {
-    EnableDisplay(*target_display_, false);
+  if (composer_callback_ != nullptr) {
+    composer_callback_->SetVsyncService(nullptr);
+    composer_callback_ = nullptr;
   }
+  composer_.reset(nullptr);
 
   // Trigger target-specific performance mode change.
   property_set(kDvrPerformanceProperty, "idle");
@@ -588,7 +577,7 @@
     surfaces_changed_ = true;
   }
 
-  if (request_display_callback_ && !is_standalone_device_)
+  if (request_display_callback_)
     request_display_callback_(!display_idle);
 
   // Set idle state based on whether there are any surfaces to handle.
@@ -773,28 +762,6 @@
 
   VsyncEyeOffsets vsync_eye_offsets = get_vsync_eye_offsets();
 
-  if (is_standalone_device_) {
-    // First, wait until boot finishes.
-    std::unique_lock<std::mutex> lock(post_thread_mutex_);
-    if (PostThreadCondWait(lock, -1, [this] { return boot_finished_; })) {
-      return;
-    }
-
-    // Then, wait until we're either leaving the quiescent state, or the boot
-    // finished display off timeout expires.
-    if (PostThreadCondWait(lock, kBootFinishedDisplayOffTimeoutSec,
-                           [this] { return !post_thread_quiescent_; })) {
-      return;
-    }
-
-    LOG_ALWAYS_FATAL_IF(post_thread_state_ & PostThreadState::Suspended,
-                        "Vr flinger should own the display by now.");
-    post_thread_resumed_ = true;
-    post_thread_ready_.notify_all();
-    if (!composer_)
-      CreateComposer();
-  }
-
   while (1) {
     ATRACE_NAME("HardwareComposer::PostThread");
 
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index efd6d1d..ac44f74 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -43,9 +43,6 @@
 // completed.
 constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50);
 
-// How long to wait for a device that boots to VR to have vr flinger ready.
-constexpr auto kBootVrFlingerWaitTimeout = std::chrono::seconds(30);
-
 // A Binder connection to surface flinger.
 class SurfaceFlingerConnection {
  public:
@@ -153,11 +150,6 @@
     return;
   }
 
-  // This test doesn't apply to standalone vr devices.
-  if (property_get_bool("ro.boot.vr", false)) {
-    return;
-  }
-
   auto surface_flinger_connection = SurfaceFlingerConnection::Create();
   ASSERT_NE(surface_flinger_connection, nullptr);
 
@@ -230,31 +222,5 @@
       SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
 }
 
-// This test runs only on devices that boot to vr. Such a device should boot to
-// a state where vr flinger is running, and the test verifies this after a
-// delay.
-TEST(BootVrFlingerTest, BootsToVrFlinger) {
-  // Exit if we are not running on a device that boots to vr.
-  if (!property_get_bool("ro.boot.vr", false)) {
-    return;
-  }
-
-  auto surface_flinger_connection = SurfaceFlingerConnection::Create();
-  ASSERT_NE(surface_flinger_connection, nullptr);
-
-  // Verify that vr flinger is enabled.
-  ASSERT_TRUE(surface_flinger_connection->IsAlive());
-  auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
-  ASSERT_TRUE(vr_flinger_active.has_value());
-
-  bool active_value = vr_flinger_active.value();
-  if (!active_value) {
-    // Try again, but delay up to 30 seconds.
-    ASSERT_EQ(surface_flinger_connection->WaitForVrFlingerTimed(true,
-        kVrFlingerSwitchPollInterval, kBootVrFlingerWaitTimeout),
-        SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
-  }
-}
-
 }  // namespace dvr
 }  // namespace android
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 9ca8b0b..48abdce 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,36 +52,17 @@
     license: "include/KHR/NOTICE",
 }
 
-llndk_library {
-    name: "libEGL",
-    symbol_file: "libs/libEGL.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv1_CM",
-    symbol_file: "libs/libGLESv1_CM.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv2",
-    symbol_file: "libs/libGLESv2.map.txt",
-    export_include_dirs: ["include"],
-}
-
-llndk_library {
-    name: "libGLESv3",
-    symbol_file: "libs/libGLESv3.map.txt",
-    export_include_dirs: ["include"],
-}
-
 cc_library_headers {
     name: "gl_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
 }
 
+llndk_headers {
+    name: "gl_llndk_headers",
+    export_include_dirs: ["include"],
+}
+
 subdirs = [
     "*",
 ]
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index e8d3684..ed2ed83 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -133,6 +133,7 @@
 cc_library_shared {
     name: "libEGL",
     defaults: ["egl_libs_defaults"],
+    llndk_stubs: "libEGL.llndk",
     srcs: [
         "EGL/egl_tls.cpp",
         "EGL/egl_cache.cpp",
@@ -198,6 +199,7 @@
 cc_library_shared {
     name: "libGLESv1_CM",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv1_CM.llndk",
     srcs: ["GLES_CM/gl.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv1\""],
     version_script: "libGLESv1_CM.map.txt",
@@ -209,6 +211,7 @@
 cc_library_shared {
     name: "libGLESv2",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv2.llndk",
     srcs: ["GLES2/gl2.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv2\""],
 
@@ -223,6 +226,31 @@
 cc_library_shared {
     name: "libGLESv3",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv3.llndk",
     srcs: ["GLES2/gl2.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv3\""],
 }
+
+llndk_library {
+    name: "libEGL.llndk",
+    symbol_file: "libEGL.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv1_CM.llndk",
+    symbol_file: "libGLESv1_CM.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv2.llndk",
+    symbol_file: "libGLESv2.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
+
+llndk_library {
+    name: "libGLESv3.llndk",
+    symbol_file: "libGLESv3.map.txt",
+    export_llndk_headers: ["gl_llndk_headers"],
+}
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index 74fb019..a27c09f 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -78,12 +78,12 @@
         return;
     }
 
-    std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
-    CacheEntry dummyEntry(dummyKey, nullptr);
+    std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
+    CacheEntry cacheEntry(cacheKey, nullptr);
 
     while (true) {
-        auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
-        if (index == mCacheEntries.end() || dummyEntry < *index) {
+        auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
+        if (index == mCacheEntries.end() || cacheEntry < *index) {
             // Create a new cache entry.
             std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true));
             std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
@@ -138,10 +138,10 @@
                 keySize, mMaxKeySize);
         return 0;
     }
-    std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
-    CacheEntry dummyEntry(dummyKey, nullptr);
-    auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
-    if (index == mCacheEntries.end() || dummyEntry < *index) {
+    std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
+    CacheEntry cacheEntry(cacheKey, nullptr);
+    auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
+    if (index == mCacheEntries.end() || cacheEntry < *index) {
         ALOGV("get: no cache entry found for key of size %zu", keySize);
         return 0;
     }
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index cc42ac7..751f3be 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -17,11 +17,13 @@
 #include "FileBlobCache.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
-#include <log/log.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
+#include <log/log.h>
 
 // Cache file header
 static const char* cacheFileMagic = "EGL$";
@@ -68,7 +70,7 @@
             return;
         }
 
-        // Sanity check the size before trying to mmap it.
+        // Check the size before trying to mmap it.
         size_t fileSize = statBuf.st_size;
         if (fileSize > mMaxTotalSize * 2) {
             ALOGE("cache file is too large: %#" PRIx64,
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index 97dc0f1..f82c2a4 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -29,9 +29,13 @@
 #include <graphicsenv/GraphicsEnv.h>
 #include <time.h>
 #include <log/log.h>
+#include <vndksupport/linker.h>
 
 namespace angle {
 
+constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so";
+constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW;
+
 static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr;
 static ResetDisplayPlatformFunc angleResetDisplayPlatform = nullptr;
 
@@ -101,11 +105,22 @@
 bool initializeAnglePlatform(EGLDisplay dpy) {
     // Since we're inside libEGL, use dlsym to lookup fptr for ANGLEGetDisplayPlatform
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
-    const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE,
-            .library_namespace = ns,
-    };
-    void* so = android_dlopen_ext("libGLESv2_angle.so", RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+    void* so = nullptr;
+    if (ns) {
+        const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = ns,
+        };
+        so = android_dlopen_ext(kAngleEs2Lib, kAngleDlFlags, &dlextinfo);
+    } else {
+        // If we are here, ANGLE is loaded as built-in gl driver in the sphal.
+        so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags);
+    }
+    if (!so) {
+        ALOGE("%s failed to dlopen %s!", __FUNCTION__, kAngleEs2Lib);
+        return false;
+    }
+
     angleGetDisplayPlatform =
             reinterpret_cast<GetDisplayPlatformFunc>(dlsym(so, "ANGLEGetDisplayPlatform"));
 
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index 510226d..bbd786d 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -138,7 +138,7 @@
     };
     EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -148,7 +148,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -258,7 +258,7 @@
     EXPECT_EQ(components[2], 8);
     EXPECT_EQ(components[3], 8);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -268,7 +268,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
     EGLint winAttrs[] = {
@@ -306,7 +306,7 @@
 
     get8BitConfig(config);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -316,7 +316,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
     EGLint winAttrs[] = {
@@ -398,7 +398,7 @@
     EXPECT_EQ(components[2], 10);
     EXPECT_EQ(components[3], 2);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -408,7 +408,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
     EGLint winAttrs[] = {
@@ -570,7 +570,7 @@
 
     ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -580,7 +580,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -622,7 +622,7 @@
 
     ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -632,7 +632,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
     std::vector<EGLint> winAttrs;
@@ -705,7 +705,7 @@
     EXPECT_GE(components[2], 16);
     EXPECT_GE(components[3], 16);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -714,7 +714,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -734,7 +734,7 @@
 
     ASSERT_TRUE(hasEglExtension(mEglDisplay, "EGL_KHR_no_config_context"));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -809,7 +809,7 @@
     EXPECT_EQ(components[2], 10);
     EXPECT_EQ(components[3], 2);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -819,7 +819,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -835,7 +835,7 @@
 
     ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -845,7 +845,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -882,7 +882,7 @@
     ASSERT_EQ(EGL_UNSIGNED_TRUE, success);
     ASSERT_EQ(1, numConfigs);
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -892,7 +892,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -913,7 +913,7 @@
 
     ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -923,7 +923,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
@@ -953,7 +953,7 @@
 
     ASSERT_NO_FATAL_FAILURE(get8BitConfig(config));
 
-    struct DummyConsumer : public BnConsumerListener {
+    struct MockConsumer : public BnConsumerListener {
         void onFrameAvailable(const BufferItem& /* item */) override {}
         void onBuffersReleased() override {}
         void onSidebandStreamChanged() override {}
@@ -963,7 +963,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    consumer->consumerConnect(new DummyConsumer, false);
+    consumer->consumerConnect(new MockConsumer, false);
     sp<Surface> mSTC = new Surface(producer);
     sp<ANativeWindow> mANW = mSTC;
 
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
index 65f89b1..8d4323f 100644
--- a/opengl/tests/gl2_jni/Android.bp
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -17,6 +17,7 @@
         "-Werror",
         "-Wno-error=unused-parameter",
     ],
+    header_libs: ["jni_headers"],
     srcs: ["jni/gl_code.cpp"],
     shared_libs: [
         "liblog",
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
index 5bec336..0cb129a 100644
--- a/opengl/tests/gl_jni/Android.bp
+++ b/opengl/tests/gl_jni/Android.bp
@@ -19,6 +19,7 @@
         "-Werror",
         "-Wno-error=unused-parameter",
     ],
+    header_libs: ["jni_headers"],
     srcs: ["jni/gl_code.cpp"],
     shared_libs: [
         "liblog",
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
index cf899ac..66afb6a 100644
--- a/opengl/tests/gl_perfapp/Android.bp
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -17,6 +17,7 @@
         "-Werror",
         "-Wno-error=unused-parameter",
     ],
+    header_libs: ["jni_headers"],
     srcs: ["jni/gl_code.cpp"],
     shared_libs: [
         "liblog",
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
index 2432566..1006d44 100644
--- a/opengl/tests/gldual/Android.bp
+++ b/opengl/tests/gldual/Android.bp
@@ -20,6 +20,7 @@
         "-Werror",
         "-Wno-error=unused-parameter",
     ],
+    header_libs: ["jni_headers"],
     srcs: ["jni/gl_code.cpp"],
     shared_libs: [
         "liblog",
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 41fcf1b..7fd9c3a 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -1,11 +1,23 @@
 #!/bin/bash
 set -u
 set -e
+
+if [ -z "$ANDROID_BUILD_TOP" ] ; then
+    echo "ANDROID_BUILD_TOP is not set, did you run lunch?"
+    exit 1
+fi
+
+# Avoid spewing files in any location other than the intended one.
+if [ ! -x "$PWD/gen" ] ; then
+    echo "Run this script from its parent directory".
+    exit 1
+fi
+
 rm -rf out generated
 
 mkdir out
 
-# Create dummy Java files for Android APIs that are used by the code we generate.
+# Create stub Java files for Android APIs that are used by the code we generate.
 # This allows us to test the generated code without building the rest of Android.
 
 mkdir -p out/javax/microedition/khronos/opengles
@@ -92,7 +104,7 @@
 
 # Add UnsupportedAppUsage.java to known sources.
 mkdir -p out/android/compat/annotation
-cp ../../../../../tools/platform-compat/annotation/src/java/android/compat/annotation/UnsupportedAppUsage.java out/android/compat/annotation
+cp ${ANDROID_BUILD_TOP}/tools/platform-compat/java/android/compat/annotation/UnsupportedAppUsage.java out/android/compat/annotation
 
 pushd out > /dev/null
 mkdir classes
@@ -153,23 +165,23 @@
     fi
 }
 
-compareGenerated ../../../../base/core/jni generated/C com_google_android_gles_jni_GLImpl.cpp
-compareGenerated ../../../../base/opengl/java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java
+compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/core/jni generated/C com_google_android_gles_jni_GLImpl.cpp
+compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/opengl/java/com/google/android/gles_jni generated/com/google/android/gles_jni GLImpl.java
 
 for x in GL.java GL10.java GL10Ext.java GL11.java GL11Ext.java GL11ExtensionPack.java
 do
-    compareGenerated ../../../../base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x
+    compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/opengl/java/javax/microedition/khronos/opengles generated/javax/microedition/khronos/opengles $x
 done
 
 for x in EGL14 EGL15 EGLExt GLES10 GLES10Ext GLES11 GLES11Ext GLES20 GLES30 GLES31 GLES31Ext GLES32
 do
-    compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
-    compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp
+    compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/opengl/java/android/opengl generated/android/opengl ${x}.java
+    compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/core/jni generated/C android_opengl_${x}.cpp
 done
 
 for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface EGLImage EGLSync
 do
-    compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java
+    compareGenerated ${ANDROID_BUILD_TOP}/frameworks/base/opengl/java/android/opengl generated/android/opengl ${x}.java
 done
 
 if [ $KEEP_GENERATED == "0" ] ; then
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9c80212..59ef3c8 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -15,6 +15,7 @@
  */
 
 import java.io.PrintStream;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -201,6 +202,33 @@
         out.println(iii + ");");
     }
 
+    // Function to automatically generate properly formatted function calls that
+    // comply with clang format rules
+    public static String formatFunctionCall(String indent, String functionCall) {
+        final int MAXLEN = 100;
+        String tokens[] = functionCall.split("\\(|\\)", 2);
+        String params[] = tokens[1].split(",\\s*");
+        String formatted = indent + tokens[0] + "(";
+        char[] chars = new char[indent.length() + tokens[0].length() + 1];
+        Arrays.fill(chars, ' ');
+        String multiIndent = new String(chars);
+        ArrayList<String> lines = new ArrayList<String>();
+        for(int i = 0; i < params.length; i++) {
+            String terminator = ((i == params.length - 1) ? "" : ",");
+            if(indent.length() + formatted.length() + params[i].length() > MAXLEN) {
+                lines.add(formatted);
+                if (!indent.equals(multiIndent)) {
+                    indent = multiIndent;
+                }
+                formatted = indent + params[i] + terminator;
+            } else {
+              formatted += (i == 0 ? "" : " ") + params[i] + terminator;
+            }
+        }
+        lines.add(formatted);
+        return String.join("\n", lines);
+    }
+
     void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
             String iii) {
         printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
@@ -1538,14 +1566,19 @@
                                         "_exception ? JNI_ABORT : 0" : "0")) +
                                 ");");
                         } else {
-                            out.println(indent + indent +
+                            String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
+                                "_" + cfunc.getArgName(cIndex) + "BufferOffset";
+                            String typeCast = "(char *)" + cfunc.getArgName(cIndex);
+                            String withOffset = "(void *)(" + typeCast + " - " + bufferOffset + ")";
+                            String releasePointerCall = (
                                 "releasePointer(_env, " + array + ", " +
-                                cfunc.getArgName(cIndex) +
+                                withOffset +
                                 ", " +
                                 (cfunc.getArgType(cIndex).isConst() ?
                                     "JNI_FALSE" : (emitExceptionCheck ?
                                         "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
                                 ");");
+                            out.println(formatFunctionCall(indent + indent, releasePointerCall));
                         }
                         out.println(indent + "}");
                     }
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index 9932556..951ecff 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -21,8 +21,8 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
-import android.view.SurfaceView;
 import android.view.SurfaceHolder;
+import android.view.SurfaceView;
 
 /**
  * EGL 1.4
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index 93203fd..b2ea041 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -20,7 +20,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 34cb3e1..6dffac5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -20,7 +20,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index b3b0690..be8b3e3 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -20,7 +20,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index e763b4e..d84a693 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -1,5 +1,5 @@
 #include <jni.h>
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 #include <assert.h>
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index c12efc3..9cab1d6 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -20,7 +20,7 @@
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 #include "jni.h"
-#include <nativehelper/JNIHelp.h>
+#include <nativehelper/JNIPlatformHelp.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/misc.h>
 
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index afcc3eb..32c9d7d 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -19,6 +19,7 @@
 package com.google.android.gles_jni;
 
 import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.Build;
@@ -26,6 +27,7 @@
 import android.util.Log;
 
 import java.nio.Buffer;
+
 import javax.microedition.khronos.opengles.GL10;
 import javax.microedition.khronos.opengles.GL10Ext;
 import javax.microedition.khronos.opengles.GL11;
@@ -55,6 +57,7 @@
     private boolean have_OES_framebuffer_object;
     private boolean have_OES_texture_cube_map;
 
+    @UnsupportedAppUsage
     public GLImpl() {
     }
 
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 6eed24a..9a9bca1 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -21,6 +21,8 @@
         "libbinder",
         "libcutils",
         "libgfxstats",
+        "libgpumem",
+        "libgpumemtracer",
         "libgraphicsenv",
         "liblog",
         "libutils",
@@ -42,11 +44,11 @@
     defaults: ["libgpuservice_defaults"],
     cflags: [
         "-fvisibility=hidden",
-        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
     },
+    whole_program_vtables: true, // Requires ThinLTO
 }
 
 filegroup {
@@ -85,6 +87,10 @@
     name: "gpuservice",
     defaults: ["libgpuservice_binary"],
     init_rc: ["gpuservice.rc"],
+    required: [
+        "bpfloader",
+        "gpu_mem.o",
+    ],
     srcs: [":gpuservice_binary_sources"],
     shared_libs: [
         "libgpuservice",
diff --git a/services/gpuservice/CleanSpec.mk b/services/gpuservice/CleanSpec.mk
new file mode 100644
index 0000000..482fc6d
--- /dev/null
+++ b/services/gpuservice/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Remove gpu_mem.o
+$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/frameworks/native/services/gpuservice/bpf)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpu_mem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpu_mem.o_gpu_mem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpu_mem.o)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpu_mem.o-timestamp)
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 81b0a46..52d5d4f 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -24,13 +24,16 @@
 #include <binder/Parcel.h>
 #include <binder/PermissionCache.h>
 #include <cutils/properties.h>
+#include <gpumem/GpuMem.h>
 #include <gpustats/GpuStats.h>
 #include <private/android_filesystem_config.h>
+#include <tracing/GpuMemTracer.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
-
 #include <vkjson.h>
 
+#include <thread>
+
 namespace android {
 
 using base::StringAppendF;
@@ -45,7 +48,16 @@
 
 const char* const GpuService::SERVICE_NAME = "gpu";
 
-GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){};
+GpuService::GpuService()
+      : mGpuMem(std::make_shared<GpuMem>()),
+        mGpuStats(std::make_unique<GpuStats>()),
+        mGpuMemTracer(std::make_unique<GpuMemTracer>()) {
+    std::thread asyncInitThread([this]() {
+        mGpuMem->initialize();
+        mGpuMemTracer->initialize(mGpuMem);
+    });
+    asyncInitThread.detach();
+};
 
 void GpuService::setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
@@ -110,6 +122,7 @@
     } else {
         bool dumpAll = true;
         bool dumpDriverInfo = false;
+        bool dumpMem = false;
         bool dumpStats = false;
         size_t numArgs = args.size();
 
@@ -119,15 +132,21 @@
                     dumpStats = true;
                 } else if (args[index] == String16("--gpudriverinfo")) {
                     dumpDriverInfo = true;
+                } else if (args[index] == String16("--gpumem")) {
+                    dumpMem = true;
                 }
             }
-            dumpAll = !(dumpDriverInfo || dumpStats);
+            dumpAll = !(dumpDriverInfo || dumpMem || dumpStats);
         }
 
         if (dumpAll || dumpDriverInfo) {
             dumpGameDriverInfo(&result);
             result.append("\n");
         }
+        if (dumpAll || dumpMem) {
+            mGpuMem->dump(args, &result);
+            result.append("\n");
+        }
         if (dumpAll || dumpStats) {
             mGpuStats->dump(args, &result);
             result.append("\n");
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index d1c3aab..409084b 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -28,7 +28,9 @@
 
 namespace android {
 
+class GpuMem;
 class GpuStats;
+class GpuMemTracer;
 
 class GpuService : public BnGpuService, public PriorityDumper {
 public:
@@ -74,7 +76,9 @@
     /*
      * Attributes
      */
+    std::shared_ptr<GpuMem> mGpuMem;
     std::unique_ptr<GpuStats> mGpuStats;
+    std::unique_ptr<GpuMemTracer> mGpuMemTracer;
     std::mutex mLock;
     std::string mDeveloperDriverPath;
 };
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
new file mode 100644
index 0000000..b875814
--- /dev/null
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -0,0 +1,22 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+bpf {
+    name: "gpu_mem.o",
+    srcs: ["gpu_mem.c"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
new file mode 100644
index 0000000..c75213b
--- /dev/null
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bpf_helpers.h>
+
+/*
+ * On Android the number of active processes using gpu is limited.
+ * So this is assumed to be true: SUM(num_procs_using_gpu[i]) <= 1024
+ */
+#define GPU_MEM_TOTAL_MAP_SIZE 1024
+
+/*
+ * This map maintains the global and per process gpu memory total counters.
+ *
+ * The KEY is ((gpu_id << 32) | pid) while VAL is the size in bytes.
+ * Use HASH type here since key is not int.
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ */
+DEFINE_BPF_MAP_GRO(gpu_mem_total_map, HASH, uint64_t, uint64_t, GPU_MEM_TOTAL_MAP_SIZE,
+                   AID_GRAPHICS);
+
+/* This struct aligns with the fields offsets of the raw tracepoint format */
+struct gpu_mem_total_args {
+    uint64_t ignore;
+    /* Actual fields start at offset 8 */
+    uint32_t gpu_id;
+    uint32_t pid;
+    uint64_t size;
+};
+
+/*
+ * This program parses the gpu_mem/gpu_mem_total tracepoint's data into
+ * {KEY, VAL} pair used to update the corresponding bpf map.
+ *
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ * Upon seeing size 0, the corresponding KEY needs to be cleaned up.
+ */
+DEFINE_BPF_PROG("tracepoint/gpu_mem/gpu_mem_total", AID_ROOT, AID_GRAPHICS, tp_gpu_mem_total)
+(struct gpu_mem_total_args* args) {
+    uint64_t key = 0;
+    uint64_t cur_val = 0;
+    uint64_t* prev_val = NULL;
+
+    /* The upper 32 bits are for gpu_id while the lower is the pid */
+    key = ((uint64_t)args->gpu_id << 32) | args->pid;
+    cur_val = args->size;
+
+    if (!cur_val) {
+        bpf_gpu_mem_total_map_delete_elem(&key);
+        return 0;
+    }
+
+    prev_val = bpf_gpu_mem_total_map_lookup_elem(&key);
+    if (prev_val) {
+        *prev_val = cur_val;
+    } else {
+        bpf_gpu_mem_total_map_update_elem(&key, &cur_val, BPF_NOEXIST);
+    }
+    return 0;
+}
+
+char _license[] SEC("license") = "Apache 2.0";
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
new file mode 100644
index 0000000..b2230b6
--- /dev/null
+++ b/services/gpuservice/gpumem/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libgpumem",
+    srcs: [
+        "GpuMem.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        "libbase",
+        "libbpf_android",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
new file mode 100644
index 0000000..3aa862f
--- /dev/null
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuMem"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "gpumem/GpuMem.h"
+
+#include <android-base/stringprintf.h>
+#include <libbpf.h>
+#include <libbpf_android.h>
+#include <log/log.h>
+#include <unistd.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+using base::StringAppendF;
+
+GpuMem::~GpuMem() {
+    bpf_detach_tracepoint(kGpuMemTraceGroup, kGpuMemTotalTracepoint);
+}
+
+void GpuMem::initialize() {
+    // Make sure bpf programs are loaded
+    bpf::waitForProgsLoaded();
+
+    errno = 0;
+    int fd = bpf::retrieveProgram(kGpuMemTotalProgPath);
+    if (fd < 0) {
+        ALOGE("Failed to retrieve pinned program from %s [%d(%s)]", kGpuMemTotalProgPath, errno,
+              strerror(errno));
+        return;
+    }
+
+    // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
+    errno = 0;
+    int count = 0;
+    while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
+        if (++count > kGpuWaitTimeout) {
+            ALOGE("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", kGpuMemTraceGroup,
+                  kGpuMemTotalTracepoint, errno, strerror(errno));
+            return;
+        }
+        // Retry until GPU driver loaded or timeout.
+        sleep(1);
+    }
+
+    // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
+    errno = 0;
+    auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
+    if (!map.isValid()) {
+        ALOGE("Failed to create bpf map from %s [%d(%s)]", kGpuMemTotalMapPath, errno,
+              strerror(errno));
+        return;
+    }
+    setGpuMemTotalMap(map);
+
+    mInitialized.store(true);
+}
+
+void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+    mGpuMemTotalMap = std::move(map);
+}
+
+// Dump the snapshots of global and per process memory usage on all gpus
+void GpuMem::dump(const Vector<String16>& /* args */, std::string* result) {
+    ATRACE_CALL();
+
+    if (!mInitialized.load() || !mGpuMemTotalMap.isValid()) {
+        result->append("Failed to initialize GPU memory eBPF\n");
+        return;
+    }
+
+    auto res = mGpuMemTotalMap.getFirstKey();
+    if (!res.ok()) {
+        result->append("GPU memory total usage map is empty\n");
+        return;
+    }
+    uint64_t key = res.value();
+    // unordered_map<gpu_id, vector<pair<pid, size>>>
+    std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, uint64_t>>> dumpMap;
+    while (true) {
+        uint32_t gpu_id = key >> 32;
+        uint32_t pid = key;
+
+        res = mGpuMemTotalMap.readValue(key);
+        if (!res.ok()) break;
+        uint64_t size = res.value();
+
+        dumpMap[gpu_id].emplace_back(pid, size);
+
+        res = mGpuMemTotalMap.getNextKey(key);
+        if (!res.ok()) break;
+        key = res.value();
+    }
+
+    for (auto& gpu : dumpMap) {
+        if (gpu.second.empty()) continue;
+        StringAppendF(result, "Memory snapshot for GPU %u:\n", gpu.first);
+
+        std::sort(gpu.second.begin(), gpu.second.end(),
+                  [](auto& l, auto& r) { return l.first < r.first; });
+
+        int i = 0;
+        if (gpu.second[0].first != 0) {
+            StringAppendF(result, "Global total: N/A\n");
+        } else {
+            StringAppendF(result, "Global total: %" PRIu64 "\n", gpu.second[0].second);
+            i++;
+        }
+        for (; i < gpu.second.size(); i++) {
+            StringAppendF(result, "Proc %u total: %" PRIu64 "\n", gpu.second[i].first,
+                          gpu.second[i].second);
+        }
+    }
+}
+
+void GpuMem::traverseGpuMemTotals(const std::function<void(int64_t ts, uint32_t gpuId, uint32_t pid,
+                                                           uint64_t size)>& callback) {
+    auto res = mGpuMemTotalMap.getFirstKey();
+    if (!res.ok()) return;
+    uint64_t key = res.value();
+    while (true) {
+        uint32_t gpu_id = key >> 32;
+        uint32_t pid = key;
+
+        res = mGpuMemTotalMap.readValue(key);
+        if (!res.ok()) break;
+        uint64_t size = res.value();
+
+        callback(systemTime(), gpu_id, pid, size);
+        res = mGpuMemTotalMap.getNextKey(key);
+        if (!res.ok()) break;
+        key = res.value();
+    }
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
new file mode 100644
index 0000000..de691e2
--- /dev/null
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include <functional>
+
+namespace android {
+
+class GpuMem {
+public:
+    GpuMem() = default;
+    ~GpuMem();
+
+    // initialize eBPF program and map
+    void initialize();
+    // dumpsys interface
+    void dump(const Vector<String16>& args, std::string* result);
+    bool isInitialized() { return mInitialized.load(); }
+
+    // Traverse the gpu memory total map to feed the callback function.
+    void traverseGpuMemTotals(const std::function<void(int64_t ts, uint32_t gpuId, uint32_t pid,
+                                                       uint64_t size)>& callback);
+
+private:
+    // Friend class for testing.
+    friend class TestableGpuMem;
+
+    // set gpu memory total map
+    void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map);
+
+    // indicate whether ebpf has been initialized
+    std::atomic<bool> mInitialized = false;
+    // bpf map for GPU memory total data
+    android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap;
+
+    // gpu memory tracepoint event category
+    static constexpr char kGpuMemTraceGroup[] = "gpu_mem";
+    // gpu memory total tracepoint
+    static constexpr char kGpuMemTotalTracepoint[] = "gpu_mem_total";
+    // pinned gpu memory total bpf c program path in bpf sysfs
+    static constexpr char kGpuMemTotalProgPath[] =
+            "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
+    // pinned gpu memory total bpf map path in bpf sysfs
+    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+    // 30 seconds timeout for trying to attach bpf program to tracepoint
+    static constexpr int kGpuWaitTimeout = 30;
+};
+
+} // namespace android
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 538506d..9606daa 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -19,18 +19,30 @@
         address: true,
     },
     srcs: [
+        "GpuMemTest.cpp",
+        "GpuMemTracerTest.cpp",
         "GpuStatsTest.cpp",
     ],
     shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
         "libcutils",
         "libgfxstats",
+        "libgpumem",
+        "libgpumemtracer",
         "libgraphicsenv",
         "liblog",
+        "libprotobuf-cpp-lite",
+        "libprotoutil",
         "libstatslog",
         "libstatspull",
         "libutils",
     ],
     static_libs: [
         "libgmock",
+        "libperfetto_client_experimental",
+        "perfetto_trace_protos",
     ],
+    require_root: true,
 }
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
index 66f51c7..72976a8 100644
--- a/services/gpuservice/tests/unittests/AndroidTest.xml
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -18,6 +18,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <option name="test-suite-tag" value="apct" />
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
new file mode 100644
index 0000000..e916221
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "gpuservice_unittest"
+
+#include <android-base/stringprintf.h>
+#include <bpf/BpfMap.h>
+#include <gmock/gmock.h>
+#include <gpumem/GpuMem.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include "TestableGpuMem.h"
+
+namespace android {
+namespace {
+
+using base::StringPrintf;
+using testing::HasSubstr;
+
+constexpr uint32_t TEST_MAP_SIZE = 10;
+constexpr uint64_t TEST_GLOBAL_KEY = 0;
+constexpr uint64_t TEST_GLOBAL_VAL = 123;
+constexpr uint64_t TEST_PROC_KEY_1 = 1;
+constexpr uint64_t TEST_PROC_VAL_1 = 234;
+constexpr uint64_t TEST_PROC_KEY_2 = 4294967298; // (1 << 32) + 2
+constexpr uint64_t TEST_PROC_VAL_2 = 345;
+constexpr uint32_t TEST_KEY_MASK = 0x1 | 0x2 | 0x4;
+constexpr uint32_t TEST_KEY_COUNT = 3;
+
+class GpuMemTest : public testing::Test {
+public:
+    GpuMemTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    ~GpuMemTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void SetUp() override {
+        bpf::setrlimitForTest();
+
+        mGpuMem = std::make_unique<GpuMem>();
+        mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+        mTestableGpuMem.setInitialized();
+        errno = 0;
+        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
+                                                   BPF_F_NO_PREALLOC);
+
+        EXPECT_EQ(0, errno);
+        EXPECT_LE(0, mTestMap.getMap().get());
+        EXPECT_TRUE(mTestMap.isValid());
+    }
+
+    std::string dumpsys() {
+        std::string result;
+        Vector<String16> args;
+        mGpuMem->dump(args, &result);
+        return result;
+    }
+
+    std::unique_ptr<GpuMem> mGpuMem;
+    TestableGpuMem mTestableGpuMem;
+    bpf::BpfMap<uint64_t, uint64_t> mTestMap;
+};
+
+TEST_F(GpuMemTest, validGpuMemTotalBpfPaths) {
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
+              "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total");
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map");
+}
+
+TEST_F(GpuMemTest, bpfInitializationFailed) {
+    EXPECT_EQ(dumpsys(), "Failed to initialize GPU memory eBPF\n");
+}
+
+TEST_F(GpuMemTest, gpuMemTotalMapEmpty) {
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+
+    EXPECT_EQ(dumpsys(), "GPU memory total usage map is empty\n");
+}
+
+TEST_F(GpuMemTest, globalMemTotal) {
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+
+    EXPECT_THAT(dumpsys(), HasSubstr(StringPrintf("Global total: %" PRIu64 "\n", TEST_GLOBAL_VAL)));
+}
+
+TEST_F(GpuMemTest, missingGlobalMemTotal) {
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+
+    EXPECT_THAT(dumpsys(), HasSubstr("Global total: N/A"));
+}
+
+TEST_F(GpuMemTest, procMemTotal) {
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+
+    EXPECT_THAT(dumpsys(),
+                HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
+                                       (uint32_t)(TEST_PROC_KEY_1 >> 32))));
+    EXPECT_THAT(dumpsys(),
+                HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_1,
+                                       TEST_PROC_VAL_1)));
+    EXPECT_THAT(dumpsys(),
+                HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
+                                       (uint32_t)(TEST_PROC_KEY_2 >> 32))));
+    EXPECT_THAT(dumpsys(),
+                HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_2,
+                                       TEST_PROC_VAL_2)));
+}
+
+TEST_F(GpuMemTest, traverseGpuMemTotals) {
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+
+    static uint32_t sMask = 0;
+    static uint32_t sCount = 0;
+    mGpuMem->traverseGpuMemTotals([](int64_t, uint32_t gpuId, uint32_t pid, uint64_t size) {
+        const uint64_t key = ((uint64_t)gpuId << 32) | pid;
+        switch (key) {
+            case TEST_GLOBAL_KEY:
+                EXPECT_EQ(size, TEST_GLOBAL_VAL);
+                sMask |= 0x1;
+                break;
+            case TEST_PROC_KEY_1:
+                EXPECT_EQ(size, TEST_PROC_VAL_1);
+                sMask |= 0x2;
+                break;
+            case TEST_PROC_KEY_2:
+                EXPECT_EQ(size, TEST_PROC_VAL_2);
+                sMask |= 0x4;
+                break;
+        }
+        sCount++;
+    });
+
+    EXPECT_EQ(sMask, TEST_KEY_MASK);
+    EXPECT_EQ(sCount, TEST_KEY_COUNT);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
new file mode 100644
index 0000000..d76f039
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "gpuservice_unittest"
+
+#include <bpf/BpfMap.h>
+#include <gpumem/GpuMem.h>
+#include <gtest/gtest.h>
+#include <perfetto/trace/trace.pb.h>
+#include <tracing/GpuMemTracer.h>
+
+#include "TestableGpuMem.h"
+
+namespace android {
+
+constexpr uint32_t TEST_MAP_SIZE = 10;
+constexpr uint64_t TEST_GLOBAL_KEY = 0;
+constexpr uint32_t TEST_GLOBAL_PID = 0;
+constexpr uint64_t TEST_GLOBAL_VAL = 123;
+constexpr uint32_t TEST_GLOBAL_GPU_ID = 0;
+constexpr uint64_t TEST_PROC_KEY_1 = 1;
+constexpr uint32_t TEST_PROC_PID_1 = 1;
+constexpr uint64_t TEST_PROC_VAL_1 = 234;
+constexpr uint32_t TEST_PROC_1_GPU_ID = 0;
+constexpr uint64_t TEST_PROC_KEY_2 = 4294967298; // (1 << 32) + 2
+constexpr uint32_t TEST_PROC_PID_2 = 2;
+constexpr uint64_t TEST_PROC_VAL_2 = 345;
+constexpr uint32_t TEST_PROC_2_GPU_ID = 1;
+
+class GpuMemTracerTest : public testing::Test {
+public:
+    GpuMemTracerTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    ~GpuMemTracerTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void SetUp() override {
+        bpf::setrlimitForTest();
+
+        mGpuMem = std::make_shared<GpuMem>();
+        mGpuMemTracer = std::make_unique<GpuMemTracer>();
+        mGpuMemTracer->initializeForTest(mGpuMem);
+        mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+
+        errno = 0;
+        mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
+                                                   BPF_F_NO_PREALLOC);
+
+        EXPECT_EQ(0, errno);
+        EXPECT_LE(0, mTestMap.getMap().get());
+        EXPECT_TRUE(mTestMap.isValid());
+    }
+
+    int getTracerThreadCount() { return mGpuMemTracer->tracerThreadCount; }
+
+    std::vector<perfetto::protos::TracePacket> readGpuMemTotalPacketsBlocking(
+            perfetto::TracingSession* tracingSession) {
+        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+        perfetto::protos::Trace trace;
+        trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()));
+
+        std::vector<perfetto::protos::TracePacket> packets;
+        for (const auto& packet : trace.packet()) {
+            if (!packet.has_gpu_mem_total_event()) {
+                continue;
+            }
+            packets.emplace_back(packet);
+        }
+        return packets;
+    }
+
+    std::shared_ptr<GpuMem> mGpuMem;
+    TestableGpuMem mTestableGpuMem;
+    std::unique_ptr<GpuMemTracer> mGpuMemTracer;
+    bpf::BpfMap<uint64_t, uint64_t> mTestMap;
+};
+
+static constexpr uint64_t getSizeForPid(uint32_t pid) {
+    switch (pid) {
+        case TEST_GLOBAL_PID:
+            return TEST_GLOBAL_VAL;
+        case TEST_PROC_PID_1:
+            return TEST_PROC_VAL_1;
+        case TEST_PROC_PID_2:
+            return TEST_PROC_VAL_2;
+    }
+    return 0;
+}
+
+static constexpr uint32_t getGpuIdForPid(uint32_t pid) {
+    switch (pid) {
+        case TEST_GLOBAL_PID:
+            return TEST_GLOBAL_GPU_ID;
+        case TEST_PROC_PID_1:
+            return TEST_PROC_1_GPU_ID;
+        case TEST_PROC_PID_2:
+            return TEST_PROC_2_GPU_ID;
+    }
+    return 0;
+}
+
+TEST_F(GpuMemTracerTest, traceInitialCountersAfterGpuMemInitialize) {
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
+    ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
+    mTestableGpuMem.setGpuMemTotalMap(mTestMap);
+    mTestableGpuMem.setInitialized();
+
+    // Only 1 tracer thread should be existing for test.
+    EXPECT_EQ(getTracerThreadCount(), 1);
+    auto tracingSession = mGpuMemTracer->getTracingSessionForTest();
+
+    tracingSession->StartBlocking();
+    // Sleep for a short time to let the tracer thread finish its work
+    sleep(1);
+    tracingSession->StopBlocking();
+
+    // The test tracer thread should have finished its execution by now.
+    EXPECT_EQ(getTracerThreadCount(), 0);
+
+    auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 3);
+
+    const auto& packet0 = packets[0];
+    ASSERT_TRUE(packet0.has_timestamp());
+    ASSERT_TRUE(packet0.has_gpu_mem_total_event());
+    const auto& gpuMemEvent0 = packet0.gpu_mem_total_event();
+    ASSERT_TRUE(gpuMemEvent0.has_pid());
+    const auto& pid0 = gpuMemEvent0.pid();
+    ASSERT_TRUE(gpuMemEvent0.has_size());
+    EXPECT_EQ(gpuMemEvent0.size(), getSizeForPid(pid0));
+    ASSERT_TRUE(gpuMemEvent0.has_gpu_id());
+    EXPECT_EQ(gpuMemEvent0.gpu_id(), getGpuIdForPid(pid0));
+
+    const auto& packet1 = packets[1];
+    ASSERT_TRUE(packet1.has_timestamp());
+    ASSERT_TRUE(packet1.has_gpu_mem_total_event());
+    const auto& gpuMemEvent1 = packet1.gpu_mem_total_event();
+    ASSERT_TRUE(gpuMemEvent1.has_pid());
+    const auto& pid1 = gpuMemEvent1.pid();
+    ASSERT_TRUE(gpuMemEvent1.has_size());
+    EXPECT_EQ(gpuMemEvent1.size(), getSizeForPid(pid1));
+    ASSERT_TRUE(gpuMemEvent1.has_gpu_id());
+    EXPECT_EQ(gpuMemEvent1.gpu_id(), getGpuIdForPid(pid1));
+
+    const auto& packet2 = packets[2];
+    ASSERT_TRUE(packet2.has_timestamp());
+    ASSERT_TRUE(packet2.has_gpu_mem_total_event());
+    const auto& gpuMemEvent2 = packet2.gpu_mem_total_event();
+    ASSERT_TRUE(gpuMemEvent2.has_pid());
+    const auto& pid2 = gpuMemEvent2.pid();
+    ASSERT_TRUE(gpuMemEvent2.has_size());
+    EXPECT_EQ(gpuMemEvent2.size(), getSizeForPid(pid2));
+    ASSERT_TRUE(gpuMemEvent2.has_gpu_id());
+    EXPECT_EQ(gpuMemEvent2.gpu_id(), getGpuIdForPid(pid2));
+}
+
+TEST_F(GpuMemTracerTest, noTracingWithoutGpuMemInitialize) {
+    // Only 1 tracer thread should be existing for test.
+    EXPECT_EQ(getTracerThreadCount(), 1);
+
+    auto tracingSession = mGpuMemTracer->getTracingSessionForTest();
+
+    tracingSession->StartBlocking();
+    // Sleep for a short time to let the tracer thread finish its work
+    sleep(1);
+    tracingSession->StopBlocking();
+
+    // The test tracer thread should have finished its execution by now.
+    EXPECT_EQ(getTracerThreadCount(), 0);
+
+    auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 0);
+}
+} // namespace android
diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h
new file mode 100644
index 0000000..6c8becb
--- /dev/null
+++ b/services/gpuservice/tests/unittests/TestableGpuMem.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <gpumem/GpuMem.h>
+
+namespace android {
+
+class TestableGpuMem {
+public:
+    TestableGpuMem() = default;
+    explicit TestableGpuMem(GpuMem *gpuMem) : mGpuMem(gpuMem) {}
+
+    void setInitialized() { mGpuMem->mInitialized.store(true); }
+
+    void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+        mGpuMem->setGpuMemTotalMap(map);
+    }
+
+    std::string getGpuMemTraceGroup() { return mGpuMem->kGpuMemTraceGroup; }
+
+    std::string getGpuMemTotalTracepoint() { return mGpuMem->kGpuMemTotalTracepoint; }
+
+    std::string getGpuMemTotalProgPath() { return mGpuMem->kGpuMemTotalProgPath; }
+
+    std::string getGpuMemTotalMapPath() { return mGpuMem->kGpuMemTotalMapPath; }
+
+private:
+    GpuMem *mGpuMem;
+};
+
+} // namespace android
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
new file mode 100644
index 0000000..919fed3
--- /dev/null
+++ b/services/gpuservice/tracing/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libgpumemtracer",
+    srcs: [
+        "GpuMemTracer.cpp",
+    ],
+    shared_libs: [
+        "libgpumem",
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "libperfetto_client_experimental",
+    ],
+    export_include_dirs: ["include"],
+    export_static_lib_headers: [
+        "libperfetto_client_experimental",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
new file mode 100644
index 0000000..44a30ea
--- /dev/null
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuMemTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "tracing/GpuMemTracer.h"
+
+#include <gpumem/GpuMem.h>
+#include <perfetto/trace/android/gpu_mem_event.pbzero.h>
+#include <unistd.h>
+
+#include <thread>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::GpuMemTracer::GpuMemDataSource);
+
+namespace android {
+
+std::mutex GpuMemTracer::sTraceMutex;
+std::condition_variable GpuMemTracer::sCondition;
+bool GpuMemTracer::sTraceStarted;
+
+void GpuMemTracer::initialize(std::shared_ptr<GpuMem> gpuMem) {
+    if (!gpuMem->isInitialized()) {
+        ALOGE("Cannot initialize GpuMemTracer before GpuMem");
+        return;
+    }
+    mGpuMem = gpuMem;
+    perfetto::TracingInitArgs args;
+    args.backends = perfetto::kSystemBackend;
+    perfetto::Tracing::Initialize(args);
+    registerDataSource();
+    std::thread tracerThread(&GpuMemTracer::threadLoop, this, true);
+    pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread");
+    tracerThread.detach();
+    tracerThreadCount++;
+}
+
+void GpuMemTracer::initializeForTest(std::shared_ptr<GpuMem> gpuMem) {
+    mGpuMem = gpuMem;
+    perfetto::TracingInitArgs args;
+    args.backends = perfetto::kInProcessBackend;
+    perfetto::Tracing::Initialize(args);
+    registerDataSource();
+    std::thread tracerThread(&GpuMemTracer::threadLoop, this, false);
+    pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThreadForTest");
+    tracerThread.detach();
+    tracerThreadCount++;
+}
+
+// Each tracing session can be used for a single block of Start -> Stop.
+std::unique_ptr<perfetto::TracingSession> GpuMemTracer::getTracingSessionForTest() {
+    perfetto::TraceConfig cfg;
+    cfg.set_duration_ms(500);
+    cfg.add_buffers()->set_size_kb(1024);
+    auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+    ds_cfg->set_name(GpuMemTracer::kGpuMemDataSource);
+
+    auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+    tracingSession->Setup(cfg);
+    return tracingSession;
+}
+
+void GpuMemTracer::registerDataSource() {
+    perfetto::DataSourceDescriptor dsd;
+    dsd.set_name(kGpuMemDataSource);
+    GpuMemDataSource::Register(dsd);
+}
+
+void GpuMemTracer::threadLoop(bool infiniteLoop) {
+    do {
+        {
+            std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            while (!sTraceStarted) {
+                sCondition.wait(lock);
+            }
+        }
+        traceInitialCounters();
+        {
+            std::lock_guard<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            sTraceStarted = false;
+        }
+    } while (infiniteLoop);
+
+    // Thread loop is exiting. Reduce the tracerThreadCount to reflect the number of active threads
+    // in the wait loop.
+    tracerThreadCount--;
+}
+
+void GpuMemTracer::traceInitialCounters() {
+    if (!mGpuMem->isInitialized()) {
+        // This should never happen.
+        ALOGE("Cannot trace without GpuMem initialization");
+        return;
+    }
+    mGpuMem->traverseGpuMemTotals([](int64_t ts, uint32_t gpuId, uint32_t pid, uint64_t size) {
+        GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) {
+            auto packet = ctx.NewTracePacket();
+            packet->set_timestamp(ts);
+            auto* event = packet->set_gpu_mem_total_event();
+            event->set_gpu_id(gpuId);
+            event->set_pid(pid);
+            event->set_size(size);
+        });
+    });
+    // Flush the TraceContext. The last packet in the above loop will go
+    // missing without this flush.
+    GpuMemDataSource::Trace([](GpuMemDataSource::TraceContext ctx) { ctx.Flush(); });
+}
+
+} // namespace android
diff --git a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
new file mode 100644
index 0000000..ae871f1
--- /dev/null
+++ b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <perfetto/tracing.h>
+
+#include <mutex>
+
+namespace perfetto::protos {
+class TracePacket;
+}
+
+namespace android {
+
+class GpuMem;
+
+class GpuMemTracer {
+public:
+    class GpuMemDataSource : public perfetto::DataSource<GpuMemDataSource> {
+        virtual void OnSetup(const SetupArgs&) override{};
+        virtual void OnStart(const StartArgs&) override {
+            std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            sTraceStarted = true;
+            sCondition.notify_all();
+        }
+        virtual void OnStop(const StopArgs&) override{};
+    };
+
+    ~GpuMemTracer() = default;
+
+    // Sets up the perfetto tracing backend and data source.
+    void initialize(std::shared_ptr<GpuMem>);
+    // Registers the data source with the perfetto backend. Called as part of initialize()
+    // and should not be called manually outside of tests. Public to allow for substituting a
+    // perfetto::kInProcessBackend in tests.
+    void registerDataSource();
+
+    // TODO(b/175904796): Refactor gpuservice lib to include perfetto lib and move the test
+    // functions into the unittests.
+    // Functions only used for testing with in-process backend. These functions require the static
+    // perfetto lib to be linked. If the tests have a perfetto linked, while libgpumemtracer.so also
+    // has one linked, they will both use different static states maintained in perfetto. Since the
+    // static perfetto states are not shared, tracing sessions created in the unit test are not
+    // recognized by GpuMemTracer. As a result, we cannot use any of the perfetto functions from
+    // this class, which defeats the purpose of the unit test. To solve this, we restrict all
+    // tracing functionality to this class, while the unit test validates the data.
+    // Sets up the perfetto in-process backend and calls into registerDataSource.
+    void initializeForTest(std::shared_ptr<GpuMem>);
+    // Creates a tracing session with in process backend, for testing.
+    std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest();
+    // Read and filter the gpu memory packets from the created trace.
+    std::vector<perfetto::protos::TracePacket> readGpuMemTotalPacketsForTestBlocking(
+            perfetto::TracingSession* tracingSession);
+
+    static constexpr char kGpuMemDataSource[] = "android.gpu.memory";
+    static std::condition_variable sCondition;
+    static std::mutex sTraceMutex;
+    static bool sTraceStarted;
+
+private:
+    // Friend class for testing
+    friend class GpuMemTracerTest;
+
+    void threadLoop(bool infiniteLoop);
+    void traceInitialCounters();
+    std::shared_ptr<GpuMem> mGpuMem;
+    // Count of how many tracer threads are currently active. Useful for testing.
+    std::atomic<int32_t> tracerThreadCount = 0;
+};
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fe016af..2517060 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -482,6 +482,33 @@
 }
 
 /**
+ * Raise ANR if there is no focused window.
+ * Before the ANR is raised, do a final state check:
+ * 1. The currently focused application must be the same one we are waiting for.
+ * 2. Ensure we still don't have a focused window.
+ */
+void InputDispatcher::processNoFocusedWindowAnrLocked() {
+    // Check if the application that we are waiting for is still focused.
+    sp<InputApplicationHandle> focusedApplication =
+            getValueByKey(mFocusedApplicationHandlesByDisplay, mAwaitedApplicationDisplayId);
+    if (focusedApplication == nullptr ||
+        focusedApplication->getApplicationToken() !=
+                mAwaitedFocusedApplication->getApplicationToken()) {
+        // Unexpected because we should have reset the ANR timer when focused application changed
+        ALOGE("Waited for a focused window, but focused application has already changed to %s",
+              focusedApplication->getName().c_str());
+        return; // The focused application has changed.
+    }
+
+    const sp<InputWindowHandle>& focusedWindowHandle =
+            getFocusedWindowHandleLocked(mAwaitedApplicationDisplayId);
+    if (focusedWindowHandle != nullptr) {
+        return; // We now have a focused window. No need for ANR.
+    }
+    onAnrLocked(mAwaitedFocusedApplication);
+}
+
+/**
  * Check if any of the connections' wait queues have events that are too old.
  * If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
  * Return the time at which we should wake up next.
@@ -492,8 +519,9 @@
     // Check if we are waiting for a focused window to appear. Raise ANR if waited too long
     if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
         if (currentTime >= *mNoFocusedWindowTimeoutTime) {
-            onAnrLocked(mAwaitedFocusedApplication);
+            processNoFocusedWindowAnrLocked();
             mAwaitedFocusedApplication.clear();
+            mNoFocusedWindowTimeoutTime = std::nullopt;
             return LONG_LONG_MIN;
         } else {
             // Keep waiting
@@ -518,7 +546,7 @@
     connection->responsive = false;
     // Stop waking up for this unresponsive connection
     mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
-    onAnrLocked(connection);
+    onAnrLocked(*connection);
     return LONG_LONG_MIN;
 }
 
@@ -1477,6 +1505,7 @@
                     DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());
             mNoFocusedWindowTimeoutTime = currentTime + timeout;
             mAwaitedFocusedApplication = focusedApplicationHandle;
+            mAwaitedApplicationDisplayId = displayId;
             ALOGW("Waiting because no window has focus but %s may eventually add a "
                   "window when it finishes starting up. Will wait for %" PRId64 "ms",
                   mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));
@@ -3567,6 +3596,10 @@
     return getValueByKey(mWindowHandlesByDisplay, displayId);
 }
 
+sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
+    return getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+}
+
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
         const sp<IBinder>& windowHandleToken) const {
     if (windowHandleToken == nullptr) {
@@ -4542,12 +4575,12 @@
     postCommandLocked(std::move(commandEntry));
 }
 
-void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
+void InputDispatcher::onAnrLocked(const Connection& connection) {
     // Since we are allowing the policy to extend the timeout, maybe the waitQueue
     // is already healthy again. Don't raise ANR in this situation
-    if (connection->waitQueue.empty()) {
+    if (connection.waitQueue.empty()) {
         ALOGI("Not raising ANR because the connection %s has recovered",
-              connection->inputChannel->getName().c_str());
+              connection.inputChannel->getName().c_str());
         return;
     }
     /**
@@ -4558,21 +4591,21 @@
      * processes the events linearly. So providing information about the oldest entry seems to be
      * most useful.
      */
-    DispatchEntry* oldestEntry = *connection->waitQueue.begin();
+    DispatchEntry* oldestEntry = *connection.waitQueue.begin();
     const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
     std::string reason =
             android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
-                                        connection->inputChannel->getName().c_str(),
+                                        connection.inputChannel->getName().c_str(),
                                         ns2ms(currentWait),
                                         oldestEntry->eventEntry->getDescription().c_str());
 
-    updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
+    updateLastAnrStateLocked(getWindowHandleLocked(connection.inputChannel->getConnectionToken()),
                              reason);
 
     std::unique_ptr<CommandEntry> commandEntry =
             std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
     commandEntry->inputApplicationHandle = nullptr;
-    commandEntry->inputChannel = connection->inputChannel;
+    commandEntry->inputChannel = connection.inputChannel;
     commandEntry->reason = std::move(reason);
     postCommandLocked(std::move(commandEntry));
 }
@@ -4672,15 +4705,15 @@
 void InputDispatcher::extendAnrTimeoutsLocked(const sp<InputApplicationHandle>& application,
                                               const sp<IBinder>& connectionToken,
                                               nsecs_t timeoutExtension) {
+    if (connectionToken == nullptr && application != nullptr) {
+        // The ANR happened because there's no focused window
+        mNoFocusedWindowTimeoutTime = now() + timeoutExtension;
+        mAwaitedFocusedApplication = application;
+    }
+
     sp<Connection> connection = getConnectionLocked(connectionToken);
     if (connection == nullptr) {
-        if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) {
-            // Maybe ANR happened because there's no focused window?
-            mNoFocusedWindowTimeoutTime = now() + timeoutExtension;
-            mAwaitedFocusedApplication = application;
-        } else {
-            // It's also possible that the connection already disappeared. No action necessary.
-        }
+        // It's possible that the connection already disappeared. No action necessary.
         return;
     }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e679c6b..31fad1f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -300,6 +300,7 @@
             REQUIRES(mLock);
     sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
             REQUIRES(mLock);
+    sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock);
     sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
 
@@ -366,6 +367,11 @@
      * Used to raise an ANR when we have no focused window.
      */
     sp<InputApplicationHandle> mAwaitedFocusedApplication GUARDED_BY(mLock);
+    /**
+     * The displayId that the focused application is associated with.
+     */
+    int32_t mAwaitedApplicationDisplayId GUARDED_BY(mLock);
+    void processNoFocusedWindowAnrLocked() REQUIRES(mLock);
 
     // Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
     // AnrTracker must be kept in-sync with all responsive connection.waitQueues.
@@ -489,7 +495,7 @@
             REQUIRES(mLock);
     void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
                               const sp<InputWindowHandle>& newFocus) REQUIRES(mLock);
-    void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
+    void onAnrLocked(const Connection& connection) REQUIRES(mLock);
     void onAnrLocked(const sp<InputApplicationHandle>& application) REQUIRES(mLock);
     void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
             REQUIRES(mLock);
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index cbe0190..b56f356 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -21,6 +21,7 @@
         "InputHost.cpp",
     ],
 
+    header_libs: ["jni_headers"],
     shared_libs: [
         "libbinder",
         "libcrypto",
@@ -42,6 +43,7 @@
         //-fvisibility=hidden
     ],
 
+    export_header_lib_headers: ["jni_headers"],
     export_include_dirs: ["."],
 }
 
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 683c05d..c9001b0 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -29,8 +29,8 @@
 
 #include <hardware/input.h>
 #include <input/InputDevice.h>
+#include <input/PropertyMap.h>
 #include <utils/Log.h>
-#include <utils/PropertyMap.h>
 #include <utils/String8.h>
 
 #define INDENT2 "    "
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index f8d5351..0fa8787 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -335,7 +335,8 @@
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0;
 
     /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
+    virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(
+            int32_t deviceId) = 0;
 
     /* Notifies the input reader policy that some input devices have changed
      * and provides information about all current input devices.
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index 194c665..85d7247 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -33,7 +33,7 @@
  * The pointer controller is responsible for providing synchronization and for tracking
  * display orientation changes if needed.
  */
-class PointerControllerInterface : public virtual RefBase {
+class PointerControllerInterface {
 protected:
     PointerControllerInterface() { }
     virtual ~PointerControllerInterface() { }
@@ -59,11 +59,11 @@
     /* Gets the absolute location of the pointer. */
     virtual void getPosition(float* outX, float* outY) const = 0;
 
-    enum Transition {
+    enum class Transition {
         // Fade/unfade immediately.
-        TRANSITION_IMMEDIATE,
+        IMMEDIATE,
         // Fade/unfade gradually.
-        TRANSITION_GRADUAL,
+        GRADUAL,
     };
 
     /* Fades the pointer out now. */
@@ -75,11 +75,11 @@
      * wants to ensure that the pointer becomes visible again. */
     virtual void unfade(Transition transition) = 0;
 
-    enum Presentation {
+    enum class Presentation {
         // Show the mouse pointer.
-        PRESENTATION_POINTER,
+        POINTER,
         // Show spots and a spot anchor in place of the mouse pointer.
-        PRESENTATION_SPOT,
+        SPOT,
     };
 
     /* Sets the mode of the pointer controller. */
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 657a134..06e3743 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -390,8 +390,9 @@
     }
 }
 
-sp<PointerControllerInterface> InputReader::getPointerControllerLocked(int32_t deviceId) {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+std::shared_ptr<PointerControllerInterface> InputReader::getPointerControllerLocked(
+        int32_t deviceId) {
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller == nullptr) {
         controller = mPolicy->obtainPointerController(deviceId);
         mPointerController = controller;
@@ -401,7 +402,7 @@
 }
 
 void InputReader::updatePointerDisplayLocked() {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller == nullptr) {
         return;
     }
@@ -424,9 +425,9 @@
 }
 
 void InputReader::fadePointerLocked() {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller != nullptr) {
-        controller->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+        controller->fade(PointerControllerInterface::Transition::GRADUAL);
     }
 }
 
@@ -725,7 +726,8 @@
     mReader->fadePointerLocked();
 }
 
-sp<PointerControllerInterface> InputReader::ContextImpl::getPointerController(int32_t deviceId) {
+std::shared_ptr<PointerControllerInterface> InputReader::ContextImpl::getPointerController(
+        int32_t deviceId) {
     // lock is already held by the input loop
     return mReader->getPointerControllerLocked(deviceId);
 }
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index c17f3a1..f5451d7 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -24,6 +24,7 @@
 #include <input/KeyCharacterMap.h>
 #include <input/KeyLayoutMap.h>
 #include <input/Keyboard.h>
+#include <input/PropertyMap.h>
 #include <input/VirtualKeyMap.h>
 #include <utils/BitSet.h>
 #include <utils/Errors.h>
@@ -31,7 +32,6 @@
 #include <utils/List.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
-#include <utils/PropertyMap.h>
 
 #include <linux/input.h>
 #include <sys/epoll.h>
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 71313fc..7c17102 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -19,8 +19,8 @@
 
 #include <input/DisplayViewport.h>
 #include <input/InputDevice.h>
+#include <input/PropertyMap.h>
 #include <stdint.h>
-#include <utils/PropertyMap.h>
 
 #include <optional>
 #include <unordered_map>
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 693ec30..108b9c2 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -17,19 +17,20 @@
 #ifndef _UI_INPUTREADER_INPUT_READER_H
 #define _UI_INPUTREADER_INPUT_READER_H
 
+#include <PointerControllerInterface.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
 #include "EventHub.h"
 #include "InputListener.h"
 #include "InputReaderBase.h"
 #include "InputReaderContext.h"
 #include "InputThread.h"
 
-#include <PointerControllerInterface.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-
-#include <unordered_map>
-#include <vector>
-
 namespace android {
 
 class InputDevice;
@@ -104,7 +105,8 @@
         virtual void disableVirtualKeysUntil(nsecs_t time) override;
         virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override;
         virtual void fadePointer() override;
-        virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) override;
+        virtual std::shared_ptr<PointerControllerInterface> getPointerController(
+                int32_t deviceId) override;
         virtual void requestTimeoutAtTime(nsecs_t when) override;
         virtual int32_t bumpGeneration() override;
         virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override;
@@ -160,8 +162,8 @@
     void dispatchExternalStylusState(const StylusState& state);
 
     // The PointerController that is shared among all the input devices that need it.
-    wp<PointerControllerInterface> mPointerController;
-    sp<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
+    std::weak_ptr<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
     void updatePointerDisplayLocked();
     void fadePointerLocked();
 
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 85701e4..ffb8d8c 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -46,7 +46,7 @@
     virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0;
 
     virtual void fadePointer() = 0;
-    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) = 0;
+    virtual std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) = 0;
 
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
     virtual int32_t bumpGeneration() = 0;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 887ab53..55c1a1d 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -20,6 +20,7 @@
 
 #include "CursorButtonAccumulator.h"
 #include "CursorScrollAccumulator.h"
+#include "PointerControllerInterface.h"
 #include "TouchCursorInputMapperCommon.h"
 
 namespace android {
@@ -79,6 +80,10 @@
     } else {
         info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f);
         info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale,
+                             0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale,
+                             0.0f);
     }
     info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
 
@@ -154,7 +159,7 @@
                 mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
                 mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
                 // Keep PointerController around in order to preserve the pointer position.
-                mPointerController->fade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+                mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
             } else {
                 ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
             }
@@ -311,12 +316,12 @@
 
     mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
-    int32_t displayId;
+    int32_t displayId = ADISPLAY_ID_NONE;
     float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     if (mSource == AINPUT_SOURCE_MOUSE) {
         if (moved || scrolled || buttonsChanged) {
-            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+            mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
 
             if (moved) {
                 mPointerController->move(deltaX, deltaY);
@@ -326,7 +331,7 @@
                 mPointerController->setButtonState(currentButtonState);
             }
 
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+            mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
         }
 
         mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
@@ -335,10 +340,12 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
         displayId = mPointerController->getDisplayId();
-    } else {
+    } else if (mSource == AINPUT_SOURCE_MOUSE_RELATIVE) {
+        // Pointer capture mode
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
-        displayId = ADISPLAY_ID_NONE;
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
     }
 
     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index f65ac39..05bbb26 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -106,7 +106,7 @@
 
     int32_t mOrientation;
 
-    sp<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> mPointerController;
 
     int32_t mButtonState;
     nsecs_t mDownTime;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 43bd9f1..0440f49 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -236,6 +236,20 @@
     mMultiTouchMotionAccumulator.process(rawEvent);
 }
 
+std::optional<int32_t> MultiTouchInputMapper::getActiveBitId(
+        const MultiTouchMotionAccumulator::Slot& inSlot) {
+    if (mHavePointerIds) {
+        int32_t trackingId = inSlot.getTrackingId();
+        for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
+            int32_t n = idBits.clearFirstMarkedBit();
+            if (mPointerTrackingIdMap[n] == trackingId) {
+                return std::make_optional(n);
+            }
+        }
+    }
+    return std::nullopt;
+}
+
 void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
     size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
     size_t outCount = 0;
@@ -250,10 +264,9 @@
         }
 
         if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) {
-            if (!mCurrentMotionAborted) {
-                ALOGI("Canceling touch gesture from device %s because the palm event was detected",
-                      getDeviceName().c_str());
-                cancelTouch(when);
+            std::optional<int32_t> id = getActiveBitId(*inSlot);
+            if (id) {
+                outState->rawPointerData.canceledIdBits.markBit(id.value());
             }
             continue;
         }
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 89ef41d..ea6f207 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -92,17 +92,19 @@
 class MultiTouchInputMapper : public TouchInputMapper {
 public:
     explicit MultiTouchInputMapper(InputDeviceContext& deviceContext);
-    virtual ~MultiTouchInputMapper();
+    ~MultiTouchInputMapper() override;
 
-    virtual void reset(nsecs_t when) override;
-    virtual void process(const RawEvent* rawEvent) override;
+    void reset(nsecs_t when) override;
+    void process(const RawEvent* rawEvent) override;
 
 protected:
-    virtual void syncTouch(nsecs_t when, RawState* outState);
-    virtual void configureRawPointerAxes();
-    virtual bool hasStylus() const;
+    void syncTouch(nsecs_t when, RawState* outState) override;
+    void configureRawPointerAxes() override;
+    bool hasStylus() const override;
 
 private:
+    // If the slot is in use, return the bit id. Return std::nullopt otherwise.
+    std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot);
     MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
 
     // Specifies the pointer id bits that are in use, and their associated tracking id.
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
index f5befb3..9cb3f67 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
@@ -25,15 +25,15 @@
 class SingleTouchInputMapper : public TouchInputMapper {
 public:
     explicit SingleTouchInputMapper(InputDeviceContext& deviceContext);
-    virtual ~SingleTouchInputMapper();
+    ~SingleTouchInputMapper() override;
 
-    virtual void reset(nsecs_t when) override;
-    virtual void process(const RawEvent* rawEvent) override;
+    void reset(nsecs_t when) override;
+    void process(const RawEvent* rawEvent) override;
 
 protected:
-    virtual void syncTouch(nsecs_t when, RawState* outState);
-    virtual void configureRawPointerAxes();
-    virtual bool hasStylus() const;
+    void syncTouch(nsecs_t when, RawState* outState) override;
+    void configureRawPointerAxes() override;
+    bool hasStylus() const override;
 
 private:
     SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 2a3e263..a86443d 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -17,12 +17,13 @@
 #ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 #define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 
+#include <input/DisplayViewport.h>
+#include <stdint.h>
+
 #include "EventHub.h"
 #include "InputListener.h"
 #include "InputReaderContext.h"
 
-#include <stdint.h>
-
 namespace android {
 
 // --- Static Definitions ---
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 99a572a..cbdb1d0 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+// clang-format off
 #include "../Macros.h"
+// clang-format on
 
 #include "TouchInputMapper.h"
 
@@ -102,6 +104,7 @@
     pointerCount = other.pointerCount;
     hoveringIdBits = other.hoveringIdBits;
     touchingIdBits = other.touchingIdBits;
+    canceledIdBits = other.canceledIdBits;
 
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointers[i] = other.pointers[i];
@@ -138,12 +141,15 @@
     pointerCount = 0;
     hoveringIdBits.clear();
     touchingIdBits.clear();
+    canceledIdBits.clear();
+    validIdBits.clear();
 }
 
 void CookedPointerData::copyFrom(const CookedPointerData& other) {
     pointerCount = other.pointerCount;
     hoveringIdBits = other.hoveringIdBits;
     touchingIdBits = other.touchingIdBits;
+    validIdBits = other.validIdBits;
 
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
@@ -159,7 +165,7 @@
 TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext)
       : InputMapper(deviceContext),
         mSource(0),
-        mDeviceMode(DEVICE_MODE_DISABLED),
+        mDeviceMode(DeviceMode::DISABLED),
         mRawSurfaceWidth(-1),
         mRawSurfaceHeight(-1),
         mSurfaceLeft(0),
@@ -179,11 +185,25 @@
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    if (mDeviceMode != DEVICE_MODE_DISABLED) {
+    if (mDeviceMode != DeviceMode::DISABLED) {
         info->addMotionRange(mOrientedRanges.x);
         info->addMotionRange(mOrientedRanges.y);
         info->addMotionRange(mOrientedRanges.pressure);
 
+        if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
+            // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
+            //
+            // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
+            // motion, i.e. the hardware dimensions, as the finger could move completely across the
+            // touchpad in one sample cycle.
+            const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
+            const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
+            info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat,
+                                 x.fuzz, x.resolution);
+            info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat,
+                                 y.fuzz, y.resolution);
+        }
+
         if (mOrientedRanges.haveSize) {
             info->addMotionRange(mOrientedRanges.size);
         }
@@ -218,7 +238,7 @@
             info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
                                  0.0f);
         }
-        if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
+        if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
             const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
             const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
             info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
@@ -284,12 +304,14 @@
         const PointerProperties& pointerProperties =
                 mLastCookedState.cookedPointerData.pointerProperties[i];
         const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
-        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
-                                     "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, "
-                                     "toolMinor=%0.3f, "
+        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, dx=%0.3f, dy=%0.3f, "
+                                     "pressure=%0.3f, touchMajor=%0.3f, touchMinor=%0.3f, "
+                                     "toolMajor=%0.3f, toolMinor=%0.3f, "
                                      "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
                                      "toolType=%d, isHovering=%s\n",
                              i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(),
+                             pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+                             pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y),
                              pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
                              pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
                              pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
@@ -311,7 +333,7 @@
     dump += INDENT3 "External Stylus State:\n";
     dumpStylusState(dump, mExternalStylusState);
 
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
+    if (mDeviceMode == DeviceMode::POINTER) {
         dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
         dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale);
         dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale);
@@ -323,15 +345,15 @@
 
 const char* TouchInputMapper::modeToString(DeviceMode deviceMode) {
     switch (deviceMode) {
-        case DEVICE_MODE_DISABLED:
+        case DeviceMode::DISABLED:
             return "disabled";
-        case DEVICE_MODE_DIRECT:
+        case DeviceMode::DIRECT:
             return "direct";
-        case DEVICE_MODE_UNSCALED:
+        case DeviceMode::UNSCALED:
             return "unscaled";
-        case DEVICE_MODE_NAVIGATION:
+        case DeviceMode::NAVIGATION:
             return "navigation";
-        case DEVICE_MODE_POINTER:
+        case DeviceMode::POINTER:
             return "pointer";
     }
     return "unknown";
@@ -375,6 +397,7 @@
     if (!changes ||
         (changes &
          (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
+          InputReaderConfiguration::CHANGE_POINTER_CAPTURE |
           InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
           InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
           InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
@@ -406,16 +429,16 @@
     // multitouch.  The spot-based presentation relies on being able to accurately
     // locate two or more fingers on the touch pad.
     mParameters.gestureMode = getDeviceContext().hasInputProperty(INPUT_PROP_SEMI_MT)
-            ? Parameters::GESTURE_MODE_SINGLE_TOUCH
-            : Parameters::GESTURE_MODE_MULTI_TOUCH;
+            ? Parameters::GestureMode::SINGLE_TOUCH
+            : Parameters::GestureMode::MULTI_TOUCH;
 
     String8 gestureModeString;
     if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"),
                                                              gestureModeString)) {
         if (gestureModeString == "single-touch") {
-            mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH;
+            mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
         } else if (gestureModeString == "multi-touch") {
-            mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH;
+            mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
         } else if (gestureModeString != "default") {
             ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
         }
@@ -423,18 +446,18 @@
 
     if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
         // The device is a touch screen.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+        mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
     } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
         // The device is a pointing device like a track pad.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+        mParameters.deviceType = Parameters::DeviceType::POINTER;
     } else if (getDeviceContext().hasRelativeAxis(REL_X) ||
                getDeviceContext().hasRelativeAxis(REL_Y)) {
         // The device is a cursor device with a touch pad attached.
         // By default don't use the touch pad to move the pointer.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+        mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
     } else {
         // The device is a touch pad of unknown purpose.
-        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+        mParameters.deviceType = Parameters::DeviceType::POINTER;
     }
 
     mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
@@ -443,29 +466,29 @@
     if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"),
                                                              deviceTypeString)) {
         if (deviceTypeString == "touchScreen") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+            mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
         } else if (deviceTypeString == "touchPad") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+            mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
         } else if (deviceTypeString == "touchNavigation") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
+            mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
         } else if (deviceTypeString == "pointer") {
-            mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+            mParameters.deviceType = Parameters::DeviceType::POINTER;
         } else if (deviceTypeString != "default") {
             ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
         }
     }
 
-    mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+    mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
     getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
                                                          mParameters.orientationAware);
 
     mParameters.hasAssociatedDisplay = false;
     mParameters.associatedDisplayIsExternal = false;
     if (mParameters.orientationAware ||
-        mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN ||
-        mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+        mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN ||
+        mParameters.deviceType == Parameters::DeviceType::POINTER) {
         mParameters.hasAssociatedDisplay = true;
-        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+        if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
             mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
             String8 uniqueDisplayId;
             getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"),
@@ -488,10 +511,10 @@
     dump += INDENT3 "Parameters:\n";
 
     switch (mParameters.gestureMode) {
-        case Parameters::GESTURE_MODE_SINGLE_TOUCH:
+        case Parameters::GestureMode::SINGLE_TOUCH:
             dump += INDENT4 "GestureMode: single-touch\n";
             break;
-        case Parameters::GESTURE_MODE_MULTI_TOUCH:
+        case Parameters::GestureMode::MULTI_TOUCH:
             dump += INDENT4 "GestureMode: multi-touch\n";
             break;
         default:
@@ -499,16 +522,16 @@
     }
 
     switch (mParameters.deviceType) {
-        case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+        case Parameters::DeviceType::TOUCH_SCREEN:
             dump += INDENT4 "DeviceType: touchScreen\n";
             break;
-        case Parameters::DEVICE_TYPE_TOUCH_PAD:
+        case Parameters::DeviceType::TOUCH_PAD:
             dump += INDENT4 "DeviceType: touchPad\n";
             break;
-        case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
+        case Parameters::DeviceType::TOUCH_NAVIGATION:
             dump += INDENT4 "DeviceType: touchNavigation\n";
             break;
-        case Parameters::DEVICE_TYPE_POINTER:
+        case Parameters::DeviceType::POINTER:
             dump += INDENT4 "DeviceType: pointer\n";
             break;
         default:
@@ -558,14 +581,14 @@
  * 4. Otherwise, use a non-display viewport.
  */
 std::optional<DisplayViewport> TouchInputMapper::findViewport() {
-    if (mParameters.hasAssociatedDisplay) {
+    if (mParameters.hasAssociatedDisplay && mDeviceMode != DeviceMode::UNSCALED) {
         const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
         if (displayPort) {
             // Find the viewport that contains the same port
             return getDeviceContext().getAssociatedViewport();
         }
 
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
+        if (mDeviceMode == DeviceMode::POINTER) {
             std::optional<DisplayViewport> viewport =
                     mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
             if (viewport) {
@@ -610,34 +633,34 @@
 }
 
 void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
-    int32_t oldDeviceMode = mDeviceMode;
+    DeviceMode oldDeviceMode = mDeviceMode;
 
     resolveExternalStylusPresence();
 
     // Determine device mode.
-    if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER &&
-        mConfig.pointerGesturesEnabled) {
+    if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
+        mConfig.pointerGesturesEnabled && !mConfig.pointerCapture) {
         mSource = AINPUT_SOURCE_MOUSE;
-        mDeviceMode = DEVICE_MODE_POINTER;
+        mDeviceMode = DeviceMode::POINTER;
         if (hasStylus()) {
             mSource |= AINPUT_SOURCE_STYLUS;
         }
-    } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN &&
+    } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
                mParameters.hasAssociatedDisplay) {
         mSource = AINPUT_SOURCE_TOUCHSCREEN;
-        mDeviceMode = DEVICE_MODE_DIRECT;
+        mDeviceMode = DeviceMode::DIRECT;
         if (hasStylus()) {
             mSource |= AINPUT_SOURCE_STYLUS;
         }
         if (hasExternalStylus()) {
             mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
         }
-    } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
+    } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
         mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
-        mDeviceMode = DEVICE_MODE_NAVIGATION;
+        mDeviceMode = DeviceMode::NAVIGATION;
     } else {
         mSource = AINPUT_SOURCE_TOUCHPAD;
-        mDeviceMode = DEVICE_MODE_UNSCALED;
+        mDeviceMode = DeviceMode::UNSCALED;
     }
 
     // Ensure we have valid X and Y axes.
@@ -645,7 +668,7 @@
         ALOGW("Touch device '%s' did not report support for X or Y axis!  "
               "The device will be inoperable.",
               getDeviceName().c_str());
-        mDeviceMode = DEVICE_MODE_DISABLED;
+        mDeviceMode = DeviceMode::DISABLED;
         return;
     }
 
@@ -656,7 +679,7 @@
               "display.  The device will be inoperable until the display size "
               "becomes available.",
               getDeviceName().c_str());
-        mDeviceMode = DEVICE_MODE_DISABLED;
+        mDeviceMode = DeviceMode::DISABLED;
         return;
     }
 
@@ -668,7 +691,7 @@
     if (viewportChanged) {
         mViewport = *newViewport;
 
-        if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
+        if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
             // Convert rotated viewport to natural surface coordinates.
             int32_t naturalLogicalWidth, naturalLogicalHeight;
             int32_t naturalPhysicalWidth, naturalPhysicalHeight;
@@ -758,14 +781,19 @@
         mOrientedRanges.clear();
     }
 
-    // Create pointer controller if needed.
-    if (mDeviceMode == DEVICE_MODE_POINTER ||
-        (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
+    // Create pointer controller if needed, and keep it around if Pointer Capture is enabled to
+    // preserve the cursor position.
+    if (mDeviceMode == DeviceMode::POINTER ||
+        (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches) ||
+        (mParameters.deviceType == Parameters::DeviceType::POINTER && mConfig.pointerCapture)) {
         if (mPointerController == nullptr) {
             mPointerController = getContext()->getPointerController(getDeviceId());
         }
+        if (mConfig.pointerCapture) {
+            mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
+        }
     } else {
-        mPointerController.clear();
+        mPointerController.reset();
     }
 
     if (viewportChanged || deviceModeChanged) {
@@ -798,7 +826,7 @@
         float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
 
         // Size factors.
-        if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
+        if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
             if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
                 mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
             } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
@@ -847,8 +875,8 @@
         // Pressure factors.
         mPressureScale = 0;
         float pressureMax = 1.0;
-        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL ||
-            mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
+        if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
+            mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
             if (mCalibration.havePressureScale) {
                 mPressureScale = mCalibration.pressureScale;
                 pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
@@ -901,9 +929,9 @@
             mOrientedRanges.orientation.fuzz = 0;
             mOrientedRanges.orientation.resolution = 0;
         } else if (mCalibration.orientationCalibration !=
-                   Calibration::ORIENTATION_CALIBRATION_NONE) {
+                   Calibration::OrientationCalibration::NONE) {
             if (mCalibration.orientationCalibration ==
-                Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
+                Calibration::OrientationCalibration::INTERPOLATED) {
                 if (mRawPointerAxes.orientation.valid) {
                     if (mRawPointerAxes.orientation.maxValue > 0) {
                         mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
@@ -928,8 +956,8 @@
 
         // Distance
         mDistanceScale = 0;
-        if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
-            if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) {
+        if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
+            if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
                 if (mCalibration.haveDistanceScale) {
                     mDistanceScale = mCalibration.distanceScale;
                 } else {
@@ -991,7 +1019,7 @@
         // Location
         updateAffineTransformation();
 
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
+        if (mDeviceMode == DeviceMode::POINTER) {
             // Compute pointer gesture detection parameters.
             float rawDiagonal = hypotf(rawWidth, rawHeight);
             float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
@@ -1112,19 +1140,19 @@
     Calibration& out = mCalibration;
 
     // Size
-    out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
+    out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
     String8 sizeCalibrationString;
     if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
         if (sizeCalibrationString == "none") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+            out.sizeCalibration = Calibration::SizeCalibration::NONE;
         } else if (sizeCalibrationString == "geometric") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
+            out.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
         } else if (sizeCalibrationString == "diameter") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
+            out.sizeCalibration = Calibration::SizeCalibration::DIAMETER;
         } else if (sizeCalibrationString == "box") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
+            out.sizeCalibration = Calibration::SizeCalibration::BOX;
         } else if (sizeCalibrationString == "area") {
-            out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
+            out.sizeCalibration = Calibration::SizeCalibration::AREA;
         } else if (sizeCalibrationString != "default") {
             ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
         }
@@ -1135,15 +1163,15 @@
     out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed);
 
     // Pressure
-    out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
+    out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
     String8 pressureCalibrationString;
     if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
         if (pressureCalibrationString == "none") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+            out.pressureCalibration = Calibration::PressureCalibration::NONE;
         } else if (pressureCalibrationString == "physical") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
+            out.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
         } else if (pressureCalibrationString == "amplitude") {
-            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
+            out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
         } else if (pressureCalibrationString != "default") {
             ALOGW("Invalid value for touch.pressure.calibration: '%s'",
                   pressureCalibrationString.string());
@@ -1153,15 +1181,15 @@
     out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale);
 
     // Orientation
-    out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
+    out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
     String8 orientationCalibrationString;
     if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
         if (orientationCalibrationString == "none") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+            out.orientationCalibration = Calibration::OrientationCalibration::NONE;
         } else if (orientationCalibrationString == "interpolated") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+            out.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
         } else if (orientationCalibrationString == "vector") {
-            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
+            out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
         } else if (orientationCalibrationString != "default") {
             ALOGW("Invalid value for touch.orientation.calibration: '%s'",
                   orientationCalibrationString.string());
@@ -1169,13 +1197,13 @@
     }
 
     // Distance
-    out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
+    out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
     String8 distanceCalibrationString;
     if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
         if (distanceCalibrationString == "none") {
-            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+            out.distanceCalibration = Calibration::DistanceCalibration::NONE;
         } else if (distanceCalibrationString == "scaled") {
-            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+            out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
         } else if (distanceCalibrationString != "default") {
             ALOGW("Invalid value for touch.distance.calibration: '%s'",
                   distanceCalibrationString.string());
@@ -1184,13 +1212,13 @@
 
     out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale);
 
-    out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
+    out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
     String8 coverageCalibrationString;
     if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
         if (coverageCalibrationString == "none") {
-            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
+            out.coverageCalibration = Calibration::CoverageCalibration::NONE;
         } else if (coverageCalibrationString == "box") {
-            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
+            out.coverageCalibration = Calibration::CoverageCalibration::BOX;
         } else if (coverageCalibrationString != "default") {
             ALOGW("Invalid value for touch.coverage.calibration: '%s'",
                   coverageCalibrationString.string());
@@ -1201,43 +1229,43 @@
 void TouchInputMapper::resolveCalibration() {
     // Size
     if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
-        if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
-            mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
+        if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DEFAULT) {
+            mCalibration.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
         }
     } else {
-        mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+        mCalibration.sizeCalibration = Calibration::SizeCalibration::NONE;
     }
 
     // Pressure
     if (mRawPointerAxes.pressure.valid) {
-        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
-            mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
+        if (mCalibration.pressureCalibration == Calibration::PressureCalibration::DEFAULT) {
+            mCalibration.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
         }
     } else {
-        mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+        mCalibration.pressureCalibration = Calibration::PressureCalibration::NONE;
     }
 
     // Orientation
     if (mRawPointerAxes.orientation.valid) {
-        if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
-            mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+        if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::DEFAULT) {
+            mCalibration.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
         }
     } else {
-        mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+        mCalibration.orientationCalibration = Calibration::OrientationCalibration::NONE;
     }
 
     // Distance
     if (mRawPointerAxes.distance.valid) {
-        if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
-            mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+        if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::DEFAULT) {
+            mCalibration.distanceCalibration = Calibration::DistanceCalibration::SCALED;
         }
     } else {
-        mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+        mCalibration.distanceCalibration = Calibration::DistanceCalibration::NONE;
     }
 
     // Coverage
-    if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
-        mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
+    if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::DEFAULT) {
+        mCalibration.coverageCalibration = Calibration::CoverageCalibration::NONE;
     }
 }
 
@@ -1246,19 +1274,19 @@
 
     // Size
     switch (mCalibration.sizeCalibration) {
-        case Calibration::SIZE_CALIBRATION_NONE:
+        case Calibration::SizeCalibration::NONE:
             dump += INDENT4 "touch.size.calibration: none\n";
             break;
-        case Calibration::SIZE_CALIBRATION_GEOMETRIC:
+        case Calibration::SizeCalibration::GEOMETRIC:
             dump += INDENT4 "touch.size.calibration: geometric\n";
             break;
-        case Calibration::SIZE_CALIBRATION_DIAMETER:
+        case Calibration::SizeCalibration::DIAMETER:
             dump += INDENT4 "touch.size.calibration: diameter\n";
             break;
-        case Calibration::SIZE_CALIBRATION_BOX:
+        case Calibration::SizeCalibration::BOX:
             dump += INDENT4 "touch.size.calibration: box\n";
             break;
-        case Calibration::SIZE_CALIBRATION_AREA:
+        case Calibration::SizeCalibration::AREA:
             dump += INDENT4 "touch.size.calibration: area\n";
             break;
         default:
@@ -1280,13 +1308,13 @@
 
     // Pressure
     switch (mCalibration.pressureCalibration) {
-        case Calibration::PRESSURE_CALIBRATION_NONE:
+        case Calibration::PressureCalibration::NONE:
             dump += INDENT4 "touch.pressure.calibration: none\n";
             break;
-        case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+        case Calibration::PressureCalibration::PHYSICAL:
             dump += INDENT4 "touch.pressure.calibration: physical\n";
             break;
-        case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+        case Calibration::PressureCalibration::AMPLITUDE:
             dump += INDENT4 "touch.pressure.calibration: amplitude\n";
             break;
         default:
@@ -1299,13 +1327,13 @@
 
     // Orientation
     switch (mCalibration.orientationCalibration) {
-        case Calibration::ORIENTATION_CALIBRATION_NONE:
+        case Calibration::OrientationCalibration::NONE:
             dump += INDENT4 "touch.orientation.calibration: none\n";
             break;
-        case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+        case Calibration::OrientationCalibration::INTERPOLATED:
             dump += INDENT4 "touch.orientation.calibration: interpolated\n";
             break;
-        case Calibration::ORIENTATION_CALIBRATION_VECTOR:
+        case Calibration::OrientationCalibration::VECTOR:
             dump += INDENT4 "touch.orientation.calibration: vector\n";
             break;
         default:
@@ -1314,10 +1342,10 @@
 
     // Distance
     switch (mCalibration.distanceCalibration) {
-        case Calibration::DISTANCE_CALIBRATION_NONE:
+        case Calibration::DistanceCalibration::NONE:
             dump += INDENT4 "touch.distance.calibration: none\n";
             break;
-        case Calibration::DISTANCE_CALIBRATION_SCALED:
+        case Calibration::DistanceCalibration::SCALED:
             dump += INDENT4 "touch.distance.calibration: scaled\n";
             break;
         default:
@@ -1329,10 +1357,10 @@
     }
 
     switch (mCalibration.coverageCalibration) {
-        case Calibration::COVERAGE_CALIBRATION_NONE:
+        case Calibration::CoverageCalibration::NONE:
             dump += INDENT4 "touch.coverage.calibration: none\n";
             break;
-        case Calibration::COVERAGE_CALIBRATION_BOX:
+        case Calibration::CoverageCalibration::BOX:
             dump += INDENT4 "touch.coverage.calibration: box\n";
             break;
         default:
@@ -1370,7 +1398,7 @@
     mCurrentCookedState.clear();
     mLastRawState.clear();
     mLastCookedState.clear();
-    mPointerUsage = POINTER_USAGE_NONE;
+    mPointerUsage = PointerUsage::NONE;
     mSentHoverEnter = false;
     mHavePointerIds = false;
     mCurrentMotionAborted = false;
@@ -1383,7 +1411,7 @@
     resetExternalStylus();
 
     if (mPointerController != nullptr) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+        mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
         mPointerController->clearSpots();
     }
 
@@ -1442,17 +1470,18 @@
 
 #if DEBUG_RAW_EVENTS
     ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
-          "hovering ids 0x%08x -> 0x%08x",
+          "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x",
           last->rawPointerData.pointerCount, next->rawPointerData.pointerCount,
           last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value,
-          last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);
+          last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value,
+          next->rawPointerData.canceledIdBits.value);
 #endif
 
     processRawTouches(false /*timeout*/);
 }
 
 void TouchInputMapper::processRawTouches(bool timeout) {
-    if (mDeviceMode == DEVICE_MODE_DISABLED) {
+    if (mDeviceMode == DeviceMode::DISABLED) {
         // Drop all input if the device is disabled.
         mCurrentRawState.clear();
         mRawStatesPending.clear();
@@ -1517,7 +1546,7 @@
     bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
     if (initialDown || buttonsPressed) {
         // If this is a touch screen, hide the pointer on an initial down.
-        if (mDeviceMode == DEVICE_MODE_DIRECT) {
+        if (mDeviceMode == DeviceMode::DIRECT) {
             getContext()->fadePointer();
         }
 
@@ -1546,7 +1575,7 @@
                          mCurrentCookedState.buttonState);
 
     // Dispatch the touches either directly or by translation through a pointer on screen.
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
+    if (mDeviceMode == DeviceMode::POINTER) {
         for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {
             uint32_t id = idBits.clearFirstMarkedBit();
             const RawPointerData::Pointer& pointer =
@@ -1576,21 +1605,21 @@
         if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
             mCurrentCookedState.mouseIdBits.clear();
             mCurrentCookedState.fingerIdBits.clear();
-            pointerUsage = POINTER_USAGE_STYLUS;
+            pointerUsage = PointerUsage::STYLUS;
         } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
             mCurrentCookedState.fingerIdBits.clear();
-            pointerUsage = POINTER_USAGE_MOUSE;
+            pointerUsage = PointerUsage::MOUSE;
         } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
                    isPointerDown(mCurrentRawState.buttonState)) {
-            pointerUsage = POINTER_USAGE_GESTURES;
+            pointerUsage = PointerUsage::GESTURES;
         }
 
         dispatchPointerUsage(when, policyFlags, pointerUsage);
     } else {
-        if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches &&
+        if (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches &&
             mPointerController != nullptr) {
-            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
-            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+            mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
+            mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
 
             mPointerController->setButtonState(mCurrentRawState.buttonState);
             mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
@@ -1627,7 +1656,7 @@
 }
 
 void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
-    if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
+    if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
         mCurrentRawState.buttonState |= mExternalStylusState.buttons;
     }
 }
@@ -1654,7 +1683,7 @@
 }
 
 bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
-    if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
+    if (mDeviceMode != DeviceMode::DIRECT || !hasExternalStylus()) {
         return false;
     }
 
@@ -1697,11 +1726,11 @@
 }
 
 void TouchInputMapper::timeoutExpired(nsecs_t when) {
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
-        if (mPointerUsage == POINTER_USAGE_GESTURES) {
+    if (mDeviceMode == DeviceMode::POINTER) {
+        if (mPointerUsage == PointerUsage::GESTURES) {
             dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
         }
-    } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
+    } else if (mDeviceMode == DeviceMode::DIRECT) {
         if (mExternalStylusFusionTimeout < when) {
             processRawTouches(true /*timeout*/);
         } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
@@ -1770,7 +1799,8 @@
         // Pointer just went down.  Check for virtual key press or off-screen touches.
         uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
         const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
-        if (!isPointInsideSurface(pointer.x, pointer.y)) {
+        // Exclude unscaled device for inside surface checking.
+        if (!isPointInsideSurface(pointer.x, pointer.y) && mDeviceMode != DeviceMode::UNSCALED) {
             // If exactly one pointer went down, check for virtual key hit.
             // Otherwise we will drop the entire stroke.
             if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
@@ -1890,14 +1920,15 @@
         // Dispatch pointer up events.
         while (!upIdBits.isEmpty()) {
             uint32_t upId = upIdBits.clearFirstMarkedBit();
-
-            dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
-                           metaState, buttonState, 0,
+            bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);
+            dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0,
+                           isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0,
                            mLastCookedState.cookedPointerData.pointerProperties,
                            mLastCookedState.cookedPointerData.pointerCoords,
                            mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
                            mOrientedXPrecision, mOrientedYPrecision, mDownTime);
             dispatchedIdBits.clearBit(upId);
+            mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
         }
 
         // Dispatch move events if any of the remaining pointers moved from their old locations.
@@ -2023,6 +2054,8 @@
             mCurrentRawState.rawPointerData.hoveringIdBits;
     mCurrentCookedState.cookedPointerData.touchingIdBits =
             mCurrentRawState.rawPointerData.touchingIdBits;
+    mCurrentCookedState.cookedPointerData.canceledIdBits =
+            mCurrentRawState.rawPointerData.canceledIdBits;
 
     if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
         mCurrentCookedState.buttonState = 0;
@@ -2038,10 +2071,10 @@
         // Size
         float touchMajor, touchMinor, toolMajor, toolMinor, size;
         switch (mCalibration.sizeCalibration) {
-            case Calibration::SIZE_CALIBRATION_GEOMETRIC:
-            case Calibration::SIZE_CALIBRATION_DIAMETER:
-            case Calibration::SIZE_CALIBRATION_BOX:
-            case Calibration::SIZE_CALIBRATION_AREA:
+            case Calibration::SizeCalibration::GEOMETRIC:
+            case Calibration::SizeCalibration::DIAMETER:
+            case Calibration::SizeCalibration::BOX:
+            case Calibration::SizeCalibration::AREA:
                 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
                     touchMajor = in.touchMajor;
                     touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
@@ -2083,17 +2116,17 @@
                     }
                 }
 
-                if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {
+                if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
                     touchMajor *= mGeometricScale;
                     touchMinor *= mGeometricScale;
                     toolMajor *= mGeometricScale;
                     toolMinor *= mGeometricScale;
-                } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {
+                } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::AREA) {
                     touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
                     touchMinor = touchMajor;
                     toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
                     toolMinor = toolMajor;
-                } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {
+                } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DIAMETER) {
                     touchMinor = touchMajor;
                     toolMinor = toolMajor;
                 }
@@ -2116,8 +2149,8 @@
         // Pressure
         float pressure;
         switch (mCalibration.pressureCalibration) {
-            case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-            case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+            case Calibration::PressureCalibration::PHYSICAL:
+            case Calibration::PressureCalibration::AMPLITUDE:
                 pressure = in.pressure * mPressureScale;
                 break;
             default:
@@ -2137,10 +2170,10 @@
             tilt = 0;
 
             switch (mCalibration.orientationCalibration) {
-                case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+                case Calibration::OrientationCalibration::INTERPOLATED:
                     orientation = in.orientation * mOrientationScale;
                     break;
-                case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
+                case Calibration::OrientationCalibration::VECTOR: {
                     int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
                     int32_t c2 = signExtendNybble(in.orientation & 0x0f);
                     if (c1 != 0 || c2 != 0) {
@@ -2164,7 +2197,7 @@
         // Distance
         float distance;
         switch (mCalibration.distanceCalibration) {
-            case Calibration::DISTANCE_CALIBRATION_SCALED:
+            case Calibration::DistanceCalibration::SCALED:
                 distance = in.distance * mDistanceScale;
                 break;
             default:
@@ -2174,7 +2207,7 @@
         // Coverage
         int32_t rawLeft, rawTop, rawRight, rawBottom;
         switch (mCalibration.coverageCalibration) {
-            case Calibration::COVERAGE_CALIBRATION_BOX:
+            case Calibration::CoverageCalibration::BOX:
                 rawLeft = (in.toolMinor & 0xffff0000) >> 16;
                 rawRight = in.toolMinor & 0x0000ffff;
                 rawBottom = in.toolMajor & 0x0000ffff;
@@ -2251,7 +2284,7 @@
         out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
         out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
         out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
-        if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
+        if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
             out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
             out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
             out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
@@ -2261,15 +2294,26 @@
             out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
         }
 
+        // Write output relative fields if applicable.
+        uint32_t id = in.id;
+        if (mSource == AINPUT_SOURCE_TOUCHPAD &&
+            mLastCookedState.cookedPointerData.hasPointerCoordsForId(id)) {
+            const PointerCoords& p = mLastCookedState.cookedPointerData.pointerCoordsForId(id);
+            float dx = xTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_X);
+            float dy = yTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_Y);
+            out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
+            out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
+        }
+
         // Write output properties.
         PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i];
-        uint32_t id = in.id;
         properties.clear();
         properties.id = id;
         properties.toolType = in.toolType;
 
-        // Write id index.
+        // Write id index and mark id as valid.
         mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
+        mCurrentCookedState.cookedPointerData.validIdBits.markBit(id);
     }
 }
 
@@ -2281,36 +2325,36 @@
     }
 
     switch (mPointerUsage) {
-        case POINTER_USAGE_GESTURES:
+        case PointerUsage::GESTURES:
             dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
             break;
-        case POINTER_USAGE_STYLUS:
+        case PointerUsage::STYLUS:
             dispatchPointerStylus(when, policyFlags);
             break;
-        case POINTER_USAGE_MOUSE:
+        case PointerUsage::MOUSE:
             dispatchPointerMouse(when, policyFlags);
             break;
-        default:
+        case PointerUsage::NONE:
             break;
     }
 }
 
 void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
     switch (mPointerUsage) {
-        case POINTER_USAGE_GESTURES:
+        case PointerUsage::GESTURES:
             abortPointerGestures(when, policyFlags);
             break;
-        case POINTER_USAGE_STYLUS:
+        case PointerUsage::STYLUS:
             abortPointerStylus(when, policyFlags);
             break;
-        case POINTER_USAGE_MOUSE:
+        case PointerUsage::MOUSE:
             abortPointerMouse(when, policyFlags);
             break;
-        default:
+        case PointerUsage::NONE:
             break;
     }
 
-    mPointerUsage = POINTER_USAGE_NONE;
+    mPointerUsage = PointerUsage::NONE;
 }
 
 void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) {
@@ -2326,49 +2370,49 @@
     }
 
     // Update the pointer presentation and spots.
-    if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
-        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+    if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
+        mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
         if (finishPreviousGesture || cancelPreviousGesture) {
             mPointerController->clearSpots();
         }
 
-        if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+        if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
             mPointerController->setSpots(mPointerGesture.currentGestureCoords,
                                          mPointerGesture.currentGestureIdToIndex,
                                          mPointerGesture.currentGestureIdBits,
                                          mPointerController->getDisplayId());
         }
     } else {
-        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+        mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
     }
 
     // Show or hide the pointer if needed.
     switch (mPointerGesture.currentGestureMode) {
-        case PointerGesture::NEUTRAL:
-        case PointerGesture::QUIET:
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH &&
-                mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) {
+        case PointerGesture::Mode::NEUTRAL:
+        case PointerGesture::Mode::QUIET:
+            if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH &&
+                mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) {
                 // Remind the user of where the pointer is after finishing a gesture with spots.
-                mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
+                mPointerController->unfade(PointerControllerInterface::Transition::GRADUAL);
             }
             break;
-        case PointerGesture::TAP:
-        case PointerGesture::TAP_DRAG:
-        case PointerGesture::BUTTON_CLICK_OR_DRAG:
-        case PointerGesture::HOVER:
-        case PointerGesture::PRESS:
-        case PointerGesture::SWIPE:
+        case PointerGesture::Mode::TAP:
+        case PointerGesture::Mode::TAP_DRAG:
+        case PointerGesture::Mode::BUTTON_CLICK_OR_DRAG:
+        case PointerGesture::Mode::HOVER:
+        case PointerGesture::Mode::PRESS:
+        case PointerGesture::Mode::SWIPE:
             // Unfade the pointer when the current gesture manipulates the
             // area directly under the pointer.
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+            mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
             break;
-        case PointerGesture::FREEFORM:
+        case PointerGesture::Mode::FREEFORM:
             // Fade the pointer when the current gesture manipulates a different
             // area and there are spots to guide the user experience.
-            if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
-                mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+            if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
+                mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
             } else {
-                mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+                mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
             }
             break;
     }
@@ -2379,12 +2423,12 @@
 
     // Update last coordinates of pointers that have moved so that we observe the new
     // pointer positions at the same time as other pointers that have just gone up.
-    bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP ||
-            mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG ||
-            mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG ||
-            mPointerGesture.currentGestureMode == PointerGesture::PRESS ||
-            mPointerGesture.currentGestureMode == PointerGesture::SWIPE ||
-            mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
+    bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::BUTTON_CLICK_OR_DRAG ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM;
     bool moveNeeded = false;
     if (down && !cancelPreviousGesture && !finishPreviousGesture &&
         !mPointerGesture.lastGestureIdBits.isEmpty() &&
@@ -2467,7 +2511,7 @@
     }
 
     // Send motion events for hover.
-    if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
+    if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) {
         dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                        buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
                        mPointerGesture.currentGestureProperties,
@@ -2537,7 +2581,7 @@
 
     // Remove any current spots.
     if (mPointerController != nullptr) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+        mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
         mPointerController->clearSpots();
     }
 }
@@ -2553,7 +2597,7 @@
         ALOGD("Gestures: Processing timeout");
 #endif
 
-        if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+        if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
             if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
                 // The tap/drag timeout has not yet expired.
                 getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime +
@@ -2566,7 +2610,7 @@
                 *outFinishPreviousGesture = true;
 
                 mPointerGesture.activeGestureId = -1;
-                mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+                mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
                 mPointerGesture.currentGestureIdBits.clear();
 
                 mPointerVelocityControl.reset();
@@ -2598,9 +2642,9 @@
 
     // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
     // to NEUTRAL, then we should not generate tap event.
-    if (mPointerGesture.lastGestureMode != PointerGesture::HOVER &&
-        mPointerGesture.lastGestureMode != PointerGesture::TAP &&
-        mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
+    if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER &&
+        mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP &&
+        mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP_DRAG) {
         mPointerGesture.resetTap();
     }
 
@@ -2633,15 +2677,16 @@
     } else {
         isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
         if (!isQuietTime) {
-            if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS ||
-                 mPointerGesture.lastGestureMode == PointerGesture::SWIPE ||
-                 mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) &&
+            if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::PRESS ||
+                 mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE ||
+                 mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) &&
                 currentFingerCount < 2) {
                 // Enter quiet time when exiting swipe or freeform state.
                 // This is to prevent accidentally entering the hover state and flinging the
                 // pointer when finishing a swipe and there is still one pointer left onscreen.
                 isQuietTime = true;
-            } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG &&
+            } else if (mPointerGesture.lastGestureMode ==
+                               PointerGesture::Mode::BUTTON_CLICK_OR_DRAG &&
                        currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) {
                 // Enter quiet time when releasing the button and there are still two or more
                 // fingers down.  This may indicate that one finger was used to press the button
@@ -2661,12 +2706,12 @@
         ALOGD("Gestures: QUIET for next %0.3fms",
               (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
 #endif
-        if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
+        if (mPointerGesture.lastGestureMode != PointerGesture::Mode::QUIET) {
             *outFinishPreviousGesture = true;
         }
 
         mPointerGesture.activeGestureId = -1;
-        mPointerGesture.currentGestureMode = PointerGesture::QUIET;
+        mPointerGesture.currentGestureMode = PointerGesture::Mode::QUIET;
         mPointerGesture.currentGestureIdBits.clear();
 
         mPointerVelocityControl.reset();
@@ -2690,7 +2735,7 @@
               activeTouchId, currentFingerCount);
 #endif
         // Reset state when just starting.
-        if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
+        if (mPointerGesture.lastGestureMode != PointerGesture::Mode::BUTTON_CLICK_OR_DRAG) {
             *outFinishPreviousGesture = true;
             mPointerGesture.activeGestureId = 0;
         }
@@ -2744,7 +2789,7 @@
         float x, y;
         mPointerController->getPosition(&x, &y);
 
-        mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
+        mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
         mPointerGesture.currentGestureIdBits.clear();
         mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
         mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -2757,15 +2802,15 @@
         mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
     } else if (currentFingerCount == 0) {
         // Case 3. No fingers down and button is not pressed. (NEUTRAL)
-        if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
+        if (mPointerGesture.lastGestureMode != PointerGesture::Mode::NEUTRAL) {
             *outFinishPreviousGesture = true;
         }
 
         // Watch for taps coming out of HOVER or TAP_DRAG mode.
         // Checking for taps after TAP_DRAG allows us to detect double-taps.
         bool tapped = false;
-        if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER ||
-             mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) &&
+        if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::HOVER ||
+             mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
             lastFingerCount == 1) {
             if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
                 float x, y;
@@ -2781,7 +2826,7 @@
                                                        mConfig.pointerGestureTapDragInterval);
 
                     mPointerGesture.activeGestureId = 0;
-                    mPointerGesture.currentGestureMode = PointerGesture::TAP;
+                    mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP;
                     mPointerGesture.currentGestureIdBits.clear();
                     mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
                     mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -2824,7 +2869,7 @@
             ALOGD("Gestures: NEUTRAL");
 #endif
             mPointerGesture.activeGestureId = -1;
-            mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+            mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
             mPointerGesture.currentGestureIdBits.clear();
         }
     } else if (currentFingerCount == 1) {
@@ -2834,14 +2879,14 @@
         // When in TAP_DRAG, emit MOVE events at the pointer location.
         ALOG_ASSERT(activeTouchId >= 0);
 
-        mPointerGesture.currentGestureMode = PointerGesture::HOVER;
-        if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+        mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
+        if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
             if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
                 float x, y;
                 mPointerController->getPosition(&x, &y);
                 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
                     fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
-                    mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+                    mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
                 } else {
 #if DEBUG_GESTURES
                     ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
@@ -2854,8 +2899,8 @@
                       (when - mPointerGesture.tapUpTime) * 0.000001f);
 #endif
             }
-        } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
-            mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+        } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) {
+            mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
         }
 
         float deltaX = 0, deltaY = 0;
@@ -2878,7 +2923,7 @@
         }
 
         bool down;
-        if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
+        if (mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG) {
 #if DEBUG_GESTURES
             ALOGD("Gestures: TAP_DRAG");
 #endif
@@ -2887,7 +2932,7 @@
 #if DEBUG_GESTURES
             ALOGD("Gestures: HOVER");
 #endif
-            if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
+            if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER) {
                 *outFinishPreviousGesture = true;
             }
             mPointerGesture.activeGestureId = 0;
@@ -2933,9 +2978,9 @@
 
         bool settled = when >=
                 mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval;
-        if (mPointerGesture.lastGestureMode != PointerGesture::PRESS &&
-            mPointerGesture.lastGestureMode != PointerGesture::SWIPE &&
-            mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+        if (mPointerGesture.lastGestureMode != PointerGesture::Mode::PRESS &&
+            mPointerGesture.lastGestureMode != PointerGesture::Mode::SWIPE &&
+            mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
             *outFinishPreviousGesture = true;
         } else if (!settled && currentFingerCount > lastFingerCount) {
             // Additional pointers have gone down but not yet settled.
@@ -2953,7 +2998,7 @@
         }
 
         if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
-            mPointerGesture.currentGestureMode = PointerGesture::PRESS;
+            mPointerGesture.currentGestureMode = PointerGesture::Mode::PRESS;
             mPointerGesture.activeGestureId = 0;
             mPointerGesture.referenceIdBits.clear();
             mPointerVelocityControl.reset();
@@ -3005,7 +3050,7 @@
         }
 
         // Consider transitions from PRESS to SWIPE or MULTITOUCH.
-        if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
+        if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS) {
             float dist[MAX_POINTER_ID + 1];
             int32_t distOverThreshold = 0;
             for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
@@ -3027,7 +3072,7 @@
                           currentFingerCount);
 #endif
                     *outCancelPreviousGesture = true;
-                    mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                    mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
                 } else {
                     // There are exactly two pointers.
                     BitSet32 idBits(mCurrentCookedState.fingerIdBits);
@@ -3046,7 +3091,7 @@
                               mutualDistance, mPointerGestureMaxSwipeWidth);
 #endif
                         *outCancelPreviousGesture = true;
-                        mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                        mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
                     } else {
                         // There are two pointers.  Wait for both pointers to start moving
                         // before deciding whether this is a SWIPE or FREEFORM gesture.
@@ -3077,7 +3122,7 @@
                                       mConfig.pointerGestureMultitouchMinDistance, cosine,
                                       mConfig.pointerGestureSwipeTransitionAngleCosine);
 #endif
-                                mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+                                mPointerGesture.currentGestureMode = PointerGesture::Mode::SWIPE;
                             } else {
                                 // Pointers are moving in different directions.  Switch to FREEFORM.
 #if DEBUG_GESTURES
@@ -3089,13 +3134,13 @@
                                       mConfig.pointerGestureSwipeTransitionAngleCosine);
 #endif
                                 *outCancelPreviousGesture = true;
-                                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                                mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
                             }
                         }
                     }
                 }
             }
-        } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+        } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
             // Switch from SWIPE to FREEFORM if additional pointers go down.
             // Cancel previous gesture.
             if (currentFingerCount > 2) {
@@ -3104,13 +3149,13 @@
                       currentFingerCount);
 #endif
                 *outCancelPreviousGesture = true;
-                mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+                mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
             }
         }
 
         // Move the reference points based on the overall group motion of the fingers
         // except in PRESS mode while waiting for a transition to occur.
-        if (mPointerGesture.currentGestureMode != PointerGesture::PRESS &&
+        if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS &&
             (commonDeltaX || commonDeltaY)) {
             for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
                 uint32_t id = idBits.clearFirstMarkedBit();
@@ -3133,8 +3178,8 @@
         }
 
         // Report gestures.
-        if (mPointerGesture.currentGestureMode == PointerGesture::PRESS ||
-            mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+        if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
+            mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
             // PRESS or SWIPE mode.
 #if DEBUG_GESTURES
             ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
@@ -3155,7 +3200,7 @@
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
                                                                  mPointerGesture.referenceGestureY);
             mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
-        } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+        } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
             // FREEFORM mode.
 #if DEBUG_GESTURES
             ALOGD("Gestures: FREEFORM activeTouchId=%d,"
@@ -3168,7 +3213,7 @@
 
             BitSet32 mappedTouchIdBits;
             BitSet32 usedGestureIdBits;
-            if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+            if (mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
                 // Initially, assign the active gesture id to the active touch point
                 // if there is one.  No other touch id bits are mapped yet.
                 if (!*outCancelPreviousGesture) {
@@ -3393,17 +3438,16 @@
 void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down,
                                              bool hovering) {
     int32_t metaState = getContext()->getGlobalMetaState();
-    int32_t displayId = mViewport.displayId;
 
     if (down || hovering) {
-        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+        mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
         mPointerController->clearSpots();
         mPointerController->setButtonState(mCurrentRawState.buttonState);
-        mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+        mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
     } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
-        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
+        mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
     }
-    displayId = mPointerController->getDisplayId();
+    int32_t displayId = mPointerController->getDisplayId();
 
     float xCursorPosition;
     float yCursorPosition;
@@ -3560,7 +3604,11 @@
         if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
             action = AMOTION_EVENT_ACTION_DOWN;
         } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
-            action = AMOTION_EVENT_ACTION_UP;
+            if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
+                action = AMOTION_EVENT_ACTION_CANCEL;
+            } else {
+                action = AMOTION_EVENT_ACTION_UP;
+            }
         } else {
             // Can't happen.
             ALOG_ASSERT(false);
@@ -3568,7 +3616,7 @@
     }
     float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
-    if (mDeviceMode == DEVICE_MODE_POINTER) {
+    if (mDeviceMode == DeviceMode::POINTER) {
         mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
     }
     const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
@@ -3625,6 +3673,9 @@
     const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
     const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
 
+    const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+    const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+
     // Rotate to surface coordinate.
     // 0 - no swap and reverse.
     // 90 - swap x/y and reverse y.
@@ -3636,16 +3687,16 @@
             y = yScaled + mYTranslate;
             break;
         case DISPLAY_ORIENTATION_90:
-            y = mSurfaceRight - xScaled;
+            y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
             x = yScaled + mYTranslate;
             break;
         case DISPLAY_ORIENTATION_180:
-            x = mSurfaceRight - xScaled;
-            y = mSurfaceBottom - yScaled;
+            x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
+            y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
             break;
         case DISPLAY_ORIENTATION_270:
             y = xScaled + mXTranslate;
-            x = mSurfaceBottom - yScaled;
+            x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
             break;
         default:
             assert(false);
@@ -3907,7 +3958,7 @@
 
 std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
     if (mParameters.hasAssociatedDisplay) {
-        if (mDeviceMode == DEVICE_MODE_POINTER) {
+        if (mDeviceMode == DeviceMode::POINTER) {
             return std::make_optional(mPointerController->getDisplayId());
         } else {
             return std::make_optional(mViewport.displayId);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 58bfc5c..df6581d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -17,6 +17,8 @@
 #ifndef _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
 #define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
 
+#include <stdint.h>
+
 #include "CursorButtonAccumulator.h"
 #include "CursorScrollAccumulator.h"
 #include "EventHub.h"
@@ -24,8 +26,6 @@
 #include "InputReaderBase.h"
 #include "TouchButtonAccumulator.h"
 
-#include <stdint.h>
-
 namespace android {
 
 /* Raw axis information from the driver. */
@@ -71,7 +71,7 @@
 
     uint32_t pointerCount;
     Pointer pointers[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
+    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits;
     uint32_t idToIndex[MAX_POINTER_ID + 1];
 
     RawPointerData();
@@ -90,6 +90,7 @@
     inline void clearIdBits() {
         hoveringIdBits.clear();
         touchingIdBits.clear();
+        canceledIdBits.clear();
     }
 
     inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; }
@@ -102,7 +103,7 @@
     uint32_t pointerCount;
     PointerProperties pointerProperties[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
-    BitSet32 hoveringIdBits, touchingIdBits;
+    BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits, validIdBits;
     uint32_t idToIndex[MAX_POINTER_ID + 1];
 
     CookedPointerData();
@@ -128,30 +129,31 @@
     inline bool isTouching(uint32_t pointerIndex) const {
         return touchingIdBits.hasBit(pointerProperties[pointerIndex].id);
     }
+
+    inline bool hasPointerCoordsForId(uint32_t id) const { return validIdBits.hasBit(id); }
 };
 
 class TouchInputMapper : public InputMapper {
 public:
     explicit TouchInputMapper(InputDeviceContext& deviceContext);
-    virtual ~TouchInputMapper();
+    ~TouchInputMapper() override;
 
-    virtual uint32_t getSources() override;
-    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
-    virtual void dump(std::string& dump) override;
-    virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
-                           uint32_t changes) override;
-    virtual void reset(nsecs_t when) override;
-    virtual void process(const RawEvent* rawEvent) override;
+    uint32_t getSources() override;
+    void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+    void dump(std::string& dump) override;
+    void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
+    void reset(nsecs_t when) override;
+    void process(const RawEvent* rawEvent) override;
 
-    virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
-    virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
-    virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
-                                       const int32_t* keyCodes, uint8_t* outFlags) override;
+    int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
+    int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
+    bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
+                               uint8_t* outFlags) override;
 
-    virtual void cancelTouch(nsecs_t when) override;
-    virtual void timeoutExpired(nsecs_t when) override;
-    virtual void updateExternalStylusState(const StylusState& state) override;
-    virtual std::optional<int32_t> getAssociatedDisplayId() override;
+    void cancelTouch(nsecs_t when) override;
+    void timeoutExpired(nsecs_t when) override;
+    void updateExternalStylusState(const StylusState& state) override;
+    std::optional<int32_t> getAssociatedDisplayId() override;
 
 protected:
     CursorButtonAccumulator mCursorButtonAccumulator;
@@ -177,12 +179,12 @@
     // Input sources and device mode.
     uint32_t mSource;
 
-    enum DeviceMode {
-        DEVICE_MODE_DISABLED,   // input is disabled
-        DEVICE_MODE_DIRECT,     // direct mapping (touchscreen)
-        DEVICE_MODE_UNSCALED,   // unscaled mapping (touchpad)
-        DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
-        DEVICE_MODE_POINTER,    // pointer mapping (pointer)
+    enum class DeviceMode {
+        DISABLED,   // input is disabled
+        DIRECT,     // direct mapping (touchscreen)
+        UNSCALED,   // unscaled mapping (touchpad)
+        NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
+        POINTER,    // pointer mapping (pointer)
     };
     DeviceMode mDeviceMode;
 
@@ -191,11 +193,11 @@
 
     // Immutable configuration parameters.
     struct Parameters {
-        enum DeviceType {
-            DEVICE_TYPE_TOUCH_SCREEN,
-            DEVICE_TYPE_TOUCH_PAD,
-            DEVICE_TYPE_TOUCH_NAVIGATION,
-            DEVICE_TYPE_POINTER,
+        enum class DeviceType {
+            TOUCH_SCREEN,
+            TOUCH_PAD,
+            TOUCH_NAVIGATION,
+            POINTER,
         };
 
         DeviceType deviceType;
@@ -205,9 +207,9 @@
         bool hasButtonUnderPad;
         std::string uniqueDisplayId;
 
-        enum GestureMode {
-            GESTURE_MODE_SINGLE_TOUCH,
-            GESTURE_MODE_MULTI_TOUCH,
+        enum class GestureMode {
+            SINGLE_TOUCH,
+            MULTI_TOUCH,
         };
         GestureMode gestureMode;
 
@@ -217,13 +219,13 @@
     // Immutable calibration parameters in parsed form.
     struct Calibration {
         // Size
-        enum SizeCalibration {
-            SIZE_CALIBRATION_DEFAULT,
-            SIZE_CALIBRATION_NONE,
-            SIZE_CALIBRATION_GEOMETRIC,
-            SIZE_CALIBRATION_DIAMETER,
-            SIZE_CALIBRATION_BOX,
-            SIZE_CALIBRATION_AREA,
+        enum class SizeCalibration {
+            DEFAULT,
+            NONE,
+            GEOMETRIC,
+            DIAMETER,
+            BOX,
+            AREA,
         };
 
         SizeCalibration sizeCalibration;
@@ -236,11 +238,11 @@
         bool sizeIsSummed;
 
         // Pressure
-        enum PressureCalibration {
-            PRESSURE_CALIBRATION_DEFAULT,
-            PRESSURE_CALIBRATION_NONE,
-            PRESSURE_CALIBRATION_PHYSICAL,
-            PRESSURE_CALIBRATION_AMPLITUDE,
+        enum class PressureCalibration {
+            DEFAULT,
+            NONE,
+            PHYSICAL,
+            AMPLITUDE,
         };
 
         PressureCalibration pressureCalibration;
@@ -248,30 +250,30 @@
         float pressureScale;
 
         // Orientation
-        enum OrientationCalibration {
-            ORIENTATION_CALIBRATION_DEFAULT,
-            ORIENTATION_CALIBRATION_NONE,
-            ORIENTATION_CALIBRATION_INTERPOLATED,
-            ORIENTATION_CALIBRATION_VECTOR,
+        enum class OrientationCalibration {
+            DEFAULT,
+            NONE,
+            INTERPOLATED,
+            VECTOR,
         };
 
         OrientationCalibration orientationCalibration;
 
         // Distance
-        enum DistanceCalibration {
-            DISTANCE_CALIBRATION_DEFAULT,
-            DISTANCE_CALIBRATION_NONE,
-            DISTANCE_CALIBRATION_SCALED,
+        enum class DistanceCalibration {
+            DEFAULT,
+            NONE,
+            SCALED,
         };
 
         DistanceCalibration distanceCalibration;
         bool haveDistanceScale;
         float distanceScale;
 
-        enum CoverageCalibration {
-            COVERAGE_CALIBRATION_DEFAULT,
-            COVERAGE_CALIBRATION_NONE,
-            COVERAGE_CALIBRATION_BOX,
+        enum class CoverageCalibration {
+            DEFAULT,
+            NONE,
+            BOX,
         };
 
         CoverageCalibration coverageCalibration;
@@ -376,7 +378,7 @@
     nsecs_t mDownTime;
 
     // The pointer controller, or null if the device is not a pointer.
-    sp<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> mPointerController;
 
     std::vector<VirtualKey> mVirtualKeys;
 
@@ -524,16 +526,16 @@
         uint64_t distance : 48; // squared distance
     };
 
-    enum PointerUsage {
-        POINTER_USAGE_NONE,
-        POINTER_USAGE_GESTURES,
-        POINTER_USAGE_STYLUS,
-        POINTER_USAGE_MOUSE,
+    enum class PointerUsage {
+        NONE,
+        GESTURES,
+        STYLUS,
+        MOUSE,
     };
     PointerUsage mPointerUsage;
 
     struct PointerGesture {
-        enum Mode {
+        enum class Mode {
             // No fingers, button is not pressed.
             // Nothing happening.
             NEUTRAL,
@@ -646,9 +648,9 @@
             firstTouchTime = LLONG_MIN;
             activeTouchId = -1;
             activeGestureId = -1;
-            currentGestureMode = NEUTRAL;
+            currentGestureMode = Mode::NEUTRAL;
             currentGestureIdBits.clear();
-            lastGestureMode = NEUTRAL;
+            lastGestureMode = Mode::NEUTRAL;
             lastGestureIdBits.clear();
             downTime = 0;
             velocityTracker.clear();
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1a133dc..668a7ab 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -150,6 +150,7 @@
         const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
         if (mAnrApplications.empty() || mAnrWindowTokens.empty()) {
             ADD_FAILURE() << "Did not receive ANR callback";
+            return {};
         }
         // Ensure that the ANR didn't get raised too early. We can't be too strict here because
         // the dispatcher started counting before this function was called
@@ -3031,4 +3032,64 @@
     mFocusedWindow->assertNoEvents();
 }
 
+/**
+ * If we have no focused window, and a key comes in, we start the ANR timer.
+ * The focused application should add a focused window before the timer runs out to prevent ANR.
+ *
+ * If the user touches another application during this time, the key should be dropped.
+ * Next, if a new focused window comes in, without toggling the focused application,
+ * then no ANR should occur.
+ *
+ * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
+ * but in some cases the policy may not update the focused application.
+ */
+TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
+    sp<FakeApplicationHandle> focusedApplication = new FakeApplicationHandle();
+    focusedApplication->setDispatchingTimeout(60ms);
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
+    // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
+    mFocusedWindow->setFocus(false);
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+    mFocusedWindow->consumeFocusEvent(false);
+
+    // Send a key. The ANR timer should start because there is no focused window.
+    // 'focusedApplication' will get blamed if this timer completes.
+    // Key will not be sent anywhere because we have no focused window. It will remain pending.
+    int32_t result =
+            injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
+                      INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result);
+
+    // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
+    // then the injected touches won't cause the focused event to get dropped.
+    // The dispatcher only checks for whether the queue should be pruned upon queueing.
+    // If we inject the touch right away and the ANR timer hasn't started, the touch event would
+    // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
+    // For this test, it means that the key would get delivered to the window once it becomes
+    // focused.
+    std::this_thread::sleep_for(10ms);
+
+    // Touch unfocused window. This should force the pending key to get dropped.
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {UNFOCUSED_WINDOW_LOCATION});
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // We do not consume the motion right away, because that would require dispatcher to first
+    // process (== drop) the key event, and by that time, ANR will be raised.
+    // Set the focused window first.
+    mFocusedWindow->setFocus(true);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+    mFocusedWindow->consumeFocusEvent(true);
+    // We do not call "setFocusedApplication" here, even though the newly focused window belongs
+    // to another application. This could be a bug / behaviour in the policy.
+
+    mUnfocusedWindow->consumeMotionDown();
+
+    ASSERT_TRUE(mDispatcher->waitForIdle());
+    // Should not ANR because we actually have a focused window. It was just added too slowly.
+    ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index c457a15..e9bb169 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -27,12 +27,13 @@
 #include <TestInputListener.h>
 #include <TouchInputMapper.h>
 #include <UinputDevice.h>
-
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
 #include <inttypes.h>
 #include <math.h>
 
+#include <memory>
+
 namespace android {
 
 using std::chrono_literals::operator""ms;
@@ -44,16 +45,24 @@
 static const nsecs_t ARBITRARY_TIME = 1234;
 
 // Arbitrary display properties.
-static const int32_t DISPLAY_ID = 0;
-static const int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
-static const int32_t DISPLAY_WIDTH = 480;
-static const int32_t DISPLAY_HEIGHT = 800;
-static const int32_t VIRTUAL_DISPLAY_ID = 1;
-static const int32_t VIRTUAL_DISPLAY_WIDTH = 400;
-static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
+static constexpr int32_t DISPLAY_ID = 0;
+static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static constexpr int32_t DISPLAY_WIDTH = 480;
+static constexpr int32_t DISPLAY_HEIGHT = 800;
+static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
+static constexpr int32_t VIRTUAL_DISPLAY_WIDTH = 400;
+static constexpr int32_t VIRTUAL_DISPLAY_HEIGHT = 500;
 static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1";
 static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
 
+static constexpr int32_t FIRST_SLOT = 0;
+static constexpr int32_t SECOND_SLOT = 1;
+static constexpr int32_t THIRD_SLOT = 2;
+static constexpr int32_t INVALID_TRACKING_ID = -1;
+static constexpr int32_t FIRST_TRACKING_ID = 0;
+static constexpr int32_t SECOND_TRACKING_ID = 1;
+static constexpr int32_t THIRD_TRACKING_ID = 2;
+
 // Error tolerance for floating point assertions.
 static const float EPSILON = 0.001f;
 
@@ -76,15 +85,14 @@
     int32_t mButtonState;
     int32_t mDisplayId;
 
-protected:
-    virtual ~FakePointerController() { }
-
 public:
     FakePointerController() :
         mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
         mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
     }
 
+    virtual ~FakePointerController() {}
+
     void setBounds(float minX, float minY, float maxX, float maxY) {
         mHaveBounds = true;
         mMinX = minX;
@@ -176,7 +184,7 @@
     std::condition_variable mDevicesChangedCondition;
 
     InputReaderConfiguration mConfig;
-    KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
+    std::unordered_map<int32_t, std::shared_ptr<FakePointerController>> mPointerControllers;
     std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
     bool mInputDevicesChanged GUARDED_BY(mLock){false};
     std::vector<DisplayViewport> mViewports;
@@ -256,8 +264,8 @@
 
     void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
 
-    void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
-        mPointerControllers.add(deviceId, controller);
+    void setPointerController(int32_t deviceId, std::shared_ptr<FakePointerController> controller) {
+        mPointerControllers.insert_or_assign(deviceId, std::move(controller));
     }
 
     const InputReaderConfiguration* getReaderConfiguration() const {
@@ -289,6 +297,8 @@
         mConfig.defaultPointerDisplayId = pointerDisplayId;
     }
 
+    float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
+
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
@@ -318,8 +328,8 @@
         *outConfig = mConfig;
     }
 
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
-        return mPointerControllers.valueFor(deviceId);
+    virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
+        return mPointerControllers[deviceId];
     }
 
     virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
@@ -847,7 +857,7 @@
     bool mUpdateGlobalMetaStateWasCalled;
     int32_t mGeneration;
     int32_t mNextId;
-    wp<PointerControllerInterface> mPointerController;
+    std::weak_ptr<PointerControllerInterface> mPointerController;
 
 public:
     FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
@@ -876,7 +886,7 @@
     }
 
     void updatePointerDisplay() {
-        sp<PointerControllerInterface> controller = mPointerController.promote();
+        std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
         if (controller != nullptr) {
             InputReaderConfiguration config;
             mPolicy->getReaderConfiguration(&config);
@@ -913,8 +923,8 @@
 
     virtual bool shouldDropVirtualKey(nsecs_t, int32_t, int32_t) { return false; }
 
-    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) {
-        sp<PointerControllerInterface> controller = mPointerController.promote();
+    virtual std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) {
+        std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
         if (controller == nullptr) {
             controller = mPolicy->obtainPointerController(deviceId);
             mPointerController = controller;
@@ -1873,10 +1883,6 @@
 // --- TouchProcessTest ---
 class TouchIntegrationTest : public InputReaderIntegrationTest {
 protected:
-    static const int32_t FIRST_SLOT = 0;
-    static const int32_t SECOND_SLOT = 1;
-    static const int32_t FIRST_TRACKING_ID = 0;
-    static const int32_t SECOND_TRACKING_ID = 1;
     const std::string UNIQUE_ID = "local:0";
 
     virtual void SetUp() override {
@@ -1947,9 +1953,9 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
     // ACTION_POINTER_UP (Second slot)
-    mDevice->sendUp();
+    mDevice->sendPointerUp();
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               args.action);
 
     // ACTION_UP
@@ -1964,11 +1970,13 @@
     const Point centerPoint = mDevice->getCenterPoint();
 
     // ACTION_DOWN
+    mDevice->sendSlot(FIRST_SLOT);
+    mDevice->sendTrackingId(FIRST_TRACKING_ID);
     mDevice->sendDown(centerPoint);
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
 
-    // ACTION_POINTER_DOWN (Second slot)
+    // ACTION_POINTER_DOWN (second slot)
     const Point secondPoint = centerPoint + Point(100, 100);
     mDevice->sendSlot(SECOND_SLOT);
     mDevice->sendTrackingId(SECOND_TRACKING_ID);
@@ -1977,26 +1985,31 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               args.action);
 
-    // ACTION_MOVE (Second slot)
+    // ACTION_MOVE (second slot)
     mDevice->sendMove(secondPoint + Point(1, 1));
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
-    // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event.
-    // Expect to receive ACTION_CANCEL, to abort the entire gesture.
+    // Send MT_TOOL_PALM (second slot), which indicates that the touch IC has determined this to be
+    // a palm event.
+    // Expect to receive the ACTION_POINTER_UP with cancel flag.
     mDevice->sendToolType(MT_TOOL_PALM);
     ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
-    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              args.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags);
 
-    // ACTION_POINTER_UP (Second slot)
-    mDevice->sendUp();
+    // Send up to second slot, expect first slot send moving.
+    mDevice->sendPointerUp();
+    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
 
-    // ACTION_UP
+    // Send ACTION_UP (first slot)
     mDevice->sendSlot(FIRST_SLOT);
     mDevice->sendUp();
 
-    // Expect no event received after abort the entire gesture.
-    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+    ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
 }
 
 // --- InputDeviceTest ---
@@ -2348,9 +2361,9 @@
         ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
     }
 
-    static void assertPosition(const sp<FakePointerController>& controller, float x, float y) {
+    static void assertPosition(const FakePointerController& controller, float x, float y) {
         float actualX, actualY;
-        controller->getPosition(&actualX, &actualY);
+        controller.getPosition(&actualX, &actualY);
         ASSERT_NEAR(x, actualX, 1);
         ASSERT_NEAR(y, actualY, 1);
     }
@@ -3021,12 +3034,12 @@
 protected:
     static const int32_t TRACKBALL_MOVEMENT_THRESHOLD;
 
-    sp<FakePointerController> mFakePointerController;
+    std::shared_ptr<FakePointerController> mFakePointerController;
 
     virtual void SetUp() override {
         InputMapperTest::SetUp();
 
-        mFakePointerController = new FakePointerController();
+        mFakePointerController = std::make_shared<FakePointerController>();
         mFakePolicy->setPointerController(mDevice->getId(), mFakePointerController);
     }
 
@@ -3682,7 +3695,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
 }
 
 TEST_F(CursorInputMapperTest, Process_PointerCapture) {
@@ -3710,7 +3723,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             10.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 100.0f, 200.0f));
 
     // Button press.
     process(mapper, ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
@@ -3749,7 +3762,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             30.0f, 40.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 100.0f, 200.0f));
 
     // Disable pointer capture and check that the device generation got bumped
     // and events are generated the usual way.
@@ -3770,7 +3783,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
 }
 
 TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
@@ -3798,7 +3811,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
     ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
 }
 
@@ -6806,7 +6819,8 @@
 
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
     // Setup for second display.
-    sp<FakePointerController> fakePointerController = new FakePointerController();
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
     fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
     fakePointerController->setPosition(100, 200);
     fakePointerController->setButtonState(0);
@@ -6866,7 +6880,8 @@
     device2->reset(ARBITRARY_TIME);
 
     // Setup PointerController.
-    sp<FakePointerController> fakePointerController = new FakePointerController();
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
     mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
     mFakePolicy->setPointerController(SECOND_DEVICE_ID, fakePointerController);
 
@@ -7057,10 +7072,10 @@
 }
 
 /**
- * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and
- * UP events should be ignored.
+ * Test single touch should be canceled when received the MT_TOOL_PALM event, and the following
+ * MOVE and UP events should be ignored.
  */
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
     prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7070,7 +7085,7 @@
 
     // default tool type is finger
     constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
-    processId(mapper, 1);
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x1, y1);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7084,19 +7099,19 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
 
     // Ignore the following MOVE and UP events if had detect a palm event.
-    processId(mapper, 1);
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x2, y2);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // finger up.
-    processId(mapper, -1);
+    processId(mapper, INVALID_TRACKING_ID);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 
     // new finger down
+    processId(mapper, FIRST_TRACKING_ID);
     processToolType(mapper, MT_TOOL_FINGER);
-    processId(mapper, 1);
     processPosition(mapper, x3, y3);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7105,11 +7120,10 @@
 }
 
 /**
- * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger,
- * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is
- * MT_TOOL_FINGER.
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the rest active fingers could still be allowed to receive the events
  */
-TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) {
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);
     prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
@@ -7118,8 +7132,8 @@
     NotifyMotionArgs motionArgs;
 
     // default tool type is finger
-    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
-    processId(mapper, 1);
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+    processId(mapper, FIRST_TRACKING_ID);
     processPosition(mapper, x1, y1);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7127,51 +7141,232 @@
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
 
     // Second finger down.
-    processSlot(mapper, 1);
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
     processPosition(mapper, x2, y2);
-    processId(mapper, 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType);
+
+    // If the tool type of the first finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // The following MOVE events of second finger should be processed.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 1, y2 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // First finger up. It used to be in palm mode, and we already generated ACTION_POINTER_UP for
+    // it. Second finger receive move.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // Second finger keeps moving.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 2, y2 + 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // Second finger up.
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event, if only 1 finger
+ * is active, it should send CANCEL after receiving the MT_TOOL_PALM event.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelWhenAllTouchIsPalm) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240;
+    // First finger down.
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // Second finger down.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
               motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
 
-    // If the tool type of the first pointer changes to MT_TOOL_PALM,
-    // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL.
-    processSlot(mapper, 0);
-    processId(mapper, 1);
+    // If the tool type of the first finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // Second finger keeps moving.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2 + 1, y2 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // second finger becomes palm, receive cancel due to only 1 finger is active.
+    processId(mapper, SECOND_TRACKING_ID);
     processToolType(mapper, MT_TOOL_PALM);
     processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
 
-    // Ignore the following MOVE and UP events if had detect a palm event.
-    processSlot(mapper, 1);
-    processId(mapper, 2);
+    // third finger down.
+    processSlot(mapper, THIRD_SLOT);
+    processId(mapper, THIRD_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_FINGER);
     processPosition(mapper, x3, y3);
     processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // second finger up.
-    processId(mapper, -1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // first finger move, but still in palm
-    processSlot(mapper, 0);
-    processId(mapper, 1);
-    processPosition(mapper, x1 - 1, y1 - 1);
-    processSync(mapper);
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
-
-    // second finger down, expect as new finger down.
-    processSlot(mapper, 1);
-    processId(mapper, 2);
-    processPosition(mapper, x2, y2);
-    processSync(mapper);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
     ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // third finger move
+    processId(mapper, THIRD_TRACKING_ID);
+    processPosition(mapper, x3 + 1, y3 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger up, third finger receive move.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // second finger up, third finger receive move.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // third finger up.
+    processSlot(mapper, THIRD_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+}
+
+/**
+ * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger,
+ * and the active finger could still be allowed to receive the events
+ */
+TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPointer) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT | TOOL_TYPE);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+
+    // default tool type is finger
+    constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220;
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1, y1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // Second finger down.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, SECOND_TRACKING_ID);
+    processPosition(mapper, x2, y2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType);
+
+    // If the tool type of the second finger changes to MT_TOOL_PALM,
+    // we expect to receive ACTION_POINTER_UP with cancel flag.
+    processId(mapper, SECOND_TRACKING_ID);
+    processToolType(mapper, MT_TOOL_PALM);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+              motionArgs.action);
+    ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
+
+    // The following MOVE event should be processed.
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1 + 1, y1 + 1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+    ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+    // second finger up.
+    processSlot(mapper, SECOND_SLOT);
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger keep moving
+    processSlot(mapper, FIRST_SLOT);
+    processId(mapper, FIRST_TRACKING_ID);
+    processPosition(mapper, x1 + 2, y1 + 2);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+
+    // first finger up.
+    processId(mapper, INVALID_TRACKING_ID);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+    ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
 }
 
 // --- MultiTouchInputMapperTest_ExternalDevice ---
@@ -7254,8 +7449,8 @@
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
-    void processPositionAndVerify(MultiTouchInputMapper& mapper, int32_t xInside, int32_t yInside,
-                                  int32_t xOutside, int32_t yOutside, int32_t xExpected,
+    void processPositionAndVerify(MultiTouchInputMapper& mapper, int32_t xOutside, int32_t yOutside,
+                                  int32_t xInside, int32_t yInside, int32_t xExpected,
                                   int32_t yExpected) {
         // touch on outside area should not work.
         processPosition(mapper, toRawX(xOutside), toRawY(yOutside));
@@ -7336,4 +7531,251 @@
     constexpr int32_t yExpected = (x + 1) - DISPLAY_WIDTH / 4;
     processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
 }
+
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    const int32_t x = 0;
+    const int32_t y = 0;
+
+    const int32_t xExpected = x;
+    const int32_t yExpected = y;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected, yExpected);
+
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+    // expect x/y = swap x/y then reverse y.
+    const int32_t xExpected90 = y;
+    const int32_t yExpected90 = DISPLAY_WIDTH - 1;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected90, yExpected90);
+
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_270);
+    // expect x/y = swap x/y then reverse x.
+    const int32_t xExpected270 = DISPLAY_HEIGHT - 1;
+    const int32_t yExpected270 = x;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected270, yExpected270);
+}
+
+TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) {
+    // we need a pointer controller for mouse mode of touchpad (start pointer at 0,0)
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
+    fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+    fakePointerController->setPosition(0, 0);
+    fakePointerController->setButtonState(0);
+
+    // prepare device and capture
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT);
+    mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+    mFakePolicy->setPointerCapture(true);
+    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    // captured touchpad should be a touchpad source
+    NotifyDeviceResetArgs resetArgs;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
+
+    InputDeviceInfo deviceInfo;
+    mDevice->getDeviceInfo(&deviceInfo);
+
+    const InputDeviceInfo::MotionRange* relRangeX =
+            deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
+    ASSERT_NE(relRangeX, nullptr);
+    ASSERT_EQ(relRangeX->min, -(RAW_X_MAX - RAW_X_MIN));
+    ASSERT_EQ(relRangeX->max, RAW_X_MAX - RAW_X_MIN);
+    const InputDeviceInfo::MotionRange* relRangeY =
+            deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
+    ASSERT_NE(relRangeY, nullptr);
+    ASSERT_EQ(relRangeY->min, -(RAW_Y_MAX - RAW_Y_MIN));
+    ASSERT_EQ(relRangeY->max, RAW_Y_MAX - RAW_Y_MIN);
+
+    // run captured pointer tests - note that this is unscaled, so input listener events should be
+    //                              identical to what the hardware sends (accounting for any
+    //                              calibration).
+    // FINGER 0 DOWN
+    processSlot(mapper, 0);
+    processId(mapper, 1);
+    processPosition(mapper, 100 + RAW_X_MIN, 100 + RAW_Y_MIN);
+    processKey(mapper, BTN_TOUCH, 1);
+    processSync(mapper);
+
+    // expect coord[0] to contain initial location of touch 0
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+    ASSERT_EQ(1U, args.pointerCount);
+    ASSERT_EQ(0, args.pointerProperties[0].id);
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, args.source);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // FINGER 1 DOWN
+    processSlot(mapper, 1);
+    processId(mapper, 2);
+    processPosition(mapper, 560 + RAW_X_MIN, 154 + RAW_Y_MIN);
+    processSync(mapper);
+
+    // expect coord[0] to contain previous location, coord[1] to contain new touch 1 location
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+            args.action);
+    ASSERT_EQ(2U, args.pointerCount);
+    ASSERT_EQ(0, args.pointerProperties[0].id);
+    ASSERT_EQ(1, args.pointerProperties[1].id);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[1], 560, 154, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // FINGER 1 MOVE
+    processPosition(mapper, 540 + RAW_X_MIN, 690 + RAW_Y_MIN);
+    processSync(mapper);
+
+    // expect coord[0] to contain previous location, coord[1] to contain new touch 1 location
+    // from move
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 100, 100, 1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[1], 540, 690, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // FINGER 0 MOVE
+    processSlot(mapper, 0);
+    processPosition(mapper, 50 + RAW_X_MIN, 800 + RAW_Y_MIN);
+    processSync(mapper);
+
+    // expect coord[0] to contain new touch 0 location, coord[1] to contain previous location
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 50, 800, 1, 0, 0, 0, 0, 0, 0, 0));
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[1], 540, 690, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // BUTTON DOWN
+    processKey(mapper, BTN_LEFT, 1);
+    processSync(mapper);
+
+    // touchinputmapper design sends a move before button press
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action);
+
+    // BUTTON UP
+    processKey(mapper, BTN_LEFT, 0);
+    processSync(mapper);
+
+    // touchinputmapper design sends a move after button release
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+
+    // FINGER 0 UP
+    processId(mapper, -1);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | 0x0000, args.action);
+
+    // FINGER 1 MOVE
+    processSlot(mapper, 1);
+    processPosition(mapper, 320 + RAW_X_MIN, 900 + RAW_Y_MIN);
+    processSync(mapper);
+
+    // expect coord[0] to contain new location of touch 1, and properties[0].id to contain 1
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+    ASSERT_EQ(1U, args.pointerCount);
+    ASSERT_EQ(1, args.pointerProperties[0].id);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 320, 900, 1, 0, 0, 0, 0, 0, 0, 0));
+
+    // FINGER 1 UP
+    processId(mapper, -1);
+    processKey(mapper, BTN_TOUCH, 0);
+    processSync(mapper);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
+
+    // non captured touchpad should be a mouse source
+    mFakePolicy->setPointerCapture(false);
+    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
+    ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
+}
+
+TEST_F(MultiTouchInputMapperTest, Process_UnCapturedTouchpadPointer) {
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
+    fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+    fakePointerController->setPosition(0, 0);
+    fakePointerController->setButtonState(0);
+
+    // prepare device and capture
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT);
+    mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
+    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+    // run uncaptured pointer tests - pushes out generic events
+    // FINGER 0 DOWN
+    processId(mapper, 3);
+    processPosition(mapper, 100, 100);
+    processKey(mapper, BTN_TOUCH, 1);
+    processSync(mapper);
+
+    // start at (100,100), cursor should be at (0,0) * scale
+    NotifyMotionArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+    ASSERT_NO_FATAL_FAILURE(
+            assertPointerCoords(args.pointerCoords[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+    // FINGER 0 MOVE
+    processPosition(mapper, 200, 200);
+    processSync(mapper);
+
+    // compute scaling to help with touch position checking
+    float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN);
+    float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+    float scale =
+            mFakePolicy->getPointerGestureMovementSpeedRatio() * displayDiagonal / rawDiagonal;
+
+    // translate from (100,100) -> (200,200), cursor should have changed to (100,100) * scale)
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+    ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 100 * scale, 100 * scale, 0,
+                                                0, 0, 0, 0, 0, 0, 0));
+}
+
+TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) {
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
+
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION | ID | SLOT);
+    mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
+    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+    mFakePolicy->setPointerCapture(false);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    // uncaptured touchpad should be a pointer device
+    ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
+
+    // captured touchpad should be a touchpad device
+    mFakePolicy->setPointerCapture(true);
+    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 0659511..7fec2c8 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -179,6 +179,11 @@
     injectEvent(EV_SYN, SYN_REPORT, 0);
 }
 
+void UinputTouchScreen::sendPointerUp() {
+    sendTrackingId(0xffffffff);
+    injectEvent(EV_SYN, SYN_REPORT, 0);
+}
+
 void UinputTouchScreen::sendUp() {
     sendTrackingId(0xffffffff);
     injectEvent(EV_KEY, BTN_TOUCH, 0);
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 22d1f63..01a557c 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -139,6 +139,7 @@
     void sendTrackingId(int32_t trackingId);
     void sendDown(const Point& point);
     void sendMove(const Point& point);
+    void sendPointerUp();
     void sendUp();
     void sendToolType(int32_t toolType);
 
diff --git a/services/sensorservice/hidl/Android.bp b/services/sensorservice/hidl/Android.bp
index d0c83d6..0e1af59 100644
--- a/services/sensorservice/hidl/Android.bp
+++ b/services/sensorservice/hidl/Android.bp
@@ -10,6 +10,7 @@
         "-Wall",
         "-Werror",
     ],
+    header_libs: ["jni_headers"],
     shared_libs: [
         "libbase",
         "libhidlbase",
@@ -24,6 +25,7 @@
     export_include_dirs: [
         "include/"
     ],
+    export_header_lib_headers: ["jni_headers"],
     local_include_dirs: [
         "include/sensorservicehidl/"
     ]
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index a790d0b..2734ee9 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -20,7 +20,6 @@
         "-DEGL_EGLEXT_PROTOTYPES",
     ],
     shared_libs: [
-        "android.frameworks.vr.composer@2.0",
         "android.hardware.configstore-utils",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
@@ -58,21 +57,12 @@
         "libutils",
         "libSurfaceFlingerProp",
     ],
-    // VrComposer is not used when building surfaceflinger for vendors
-    target: {
-        vendor: {
-            exclude_shared_libs: [
-                "android.frameworks.vr.composer@2.0",
-            ],
-        },
-    },
     static_libs: [
         "libcompositionengine",
         "libperfetto_client_experimental",
         "librenderengine",
         "libserviceutils",
         "libtrace_proto",
-        "libvrflinger",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
@@ -108,11 +98,11 @@
     defaults: ["libsurfaceflinger_defaults"],
     cflags: [
         "-fvisibility=hidden",
-        "-fwhole-program-vtables", // requires ThinLTO
     ],
     lto: {
         thin: true,
     },
+    whole_program_vtables: true, // Requires ThinLTO
     // TODO(b/131771163): Fix broken fuzzer support with LTO.
     sanitize: {
         fuzzer: false,
@@ -198,17 +188,6 @@
         // can be easily replaced.
         "SurfaceFlingerFactory.cpp",
     ],
-    cflags: [
-        "-DUSE_VR_COMPOSER=1",
-    ],
-    // VrComposer is not used when building surfaceflinger for vendors
-    target: {
-        vendor: {
-            cflags: [
-                "-DUSE_VR_COMPOSER=0",
-            ],
-        },
-    },
     logtags: ["EventLog/EventLogTags.logtags"],
 }
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f0b0200..df26a3d 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,14 @@
         if (!holes.isEmpty()) {
             targetSettings.clearRegion.orSelf(holes);
         }
-        return std::nullopt;
+
+        if (mSidebandStream != nullptr) {
+            // For surfaceview of tv sideband, there is no activeBuffer
+            // in bufferqueue, we need return LayerSettings.
+            return result;
+        } else {
+            return std::nullopt;
+        }
     }
     bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
             (isSecure() && !targetSettings.isSecure);
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b3b9fe5..4863297 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -6,7 +6,6 @@
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
     shared_libs: [
-        "android.frameworks.vr.composer@2.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
@@ -121,13 +120,6 @@
         //
         // You can either "make dist tests" before flashing, or set this
         // option to false temporarily.
-
-
-        // FIXME: ASAN build is broken for a while, but was not discovered
-        // since new PM silently suppressed ASAN. Temporarily turn off ASAN
-        // to unblock the compiler upgrade process.
-        // address: true,
-        // http://b/139747256
-        address: false,
+        address: true,
     },
 }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 8a9763b..77400eb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,7 +116,7 @@
     FloatRect geomLayerBounds;
 
     // length of the shadow in screen space
-    float shadowRadius;
+    float shadowRadius{0.f};
 
     /*
      * Geometry state
@@ -130,16 +130,6 @@
     Rect geomContentCrop;
     Rect geomCrop;
 
-    /*
-     * Extra metadata
-     */
-
-    // The type for this layer
-    int type{0};
-
-    // The appId for this layer
-    int appId{0};
-
     GenericLayerMetadataMap metadata;
 
     /*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 75394fa..d2b38d1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -110,7 +110,7 @@
     void dump(std::string& result) const;
 
     // Timestamp for when the layer is queued for client composition
-    nsecs_t clientCompositionTimestamp;
+    nsecs_t clientCompositionTimestamp{0};
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 02e3a45..1338538 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -75,10 +75,6 @@
     dumpVal(out, "alpha", alpha);
     dumpVal(out, "backgroundBlurRadius", backgroundBlurRadius);
 
-    out.append("\n      ");
-    dumpVal(out, "type", type);
-    dumpVal(out, "appId", appId);
-
     if (!metadata.empty()) {
         out.append("\n      metadata {");
         for (const auto& [key, entry] : metadata) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e8f54f5..d3247e1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -835,6 +835,8 @@
             needsProtected == renderEngine.isProtected()) {
             mRenderSurface->setProtected(needsProtected);
         }
+    } else if (!outputState.isSecure && renderEngine.isProtected()) {
+        renderEngine.useProtectedContext(false);
     }
 
     base::unique_fd fd;
@@ -952,7 +954,7 @@
     const bool useIdentityTransform = false;
     bool firstLayer = true;
     // Used when a layer clears part of the buffer.
-    Region dummyRegion;
+    Region stubRegion;
 
     for (auto* layer : getOutputLayersOrderedByZ()) {
         const auto& layerState = layer->getState();
@@ -991,7 +993,7 @@
                     layer->needsFiltering() || outputState.needsFiltering,
                     outputState.isSecure,
                     supportsProtectedContent,
-                    clientComposition ? clearRegion : dummyRegion,
+                    clientComposition ? clearRegion : stubRegion,
                     outputState.viewport,
                     outputDataspace,
                     realContentIsVisible,
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 1faf775..3aed7f5 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -402,13 +402,6 @@
               outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    if (auto error = hwcLayer->setInfo(static_cast<uint32_t>(outputIndependentState.type),
-                                       static_cast<uint32_t>(outputIndependentState.appId));
-        error != hal::Error::NONE) {
-        ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
-              to_string(error).c_str(), static_cast<int32_t>(error));
-    }
-
     for (const auto& [name, entry] : outputIndependentState.metadata) {
         if (auto error = hwcLayer->setLayerGenericMetadata(name, entry.mandatory, entry.value);
             error != hal::Error::NONE) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index d889d74..d5bf569 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -30,6 +30,7 @@
 namespace {
 
 using ::testing::_;
+using ::testing::DoAll;
 using ::testing::InSequence;
 using ::testing::Ref;
 using ::testing::Return;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 09f37fb..29fd4b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -159,6 +159,7 @@
         EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
index d21b97e..87911cc 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -66,7 +66,6 @@
     MOCK_METHOD1(setTransform, Error(hal::Transform));
     MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
     MOCK_METHOD1(setZOrder, Error(uint32_t));
-    MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
 
     MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
     MOCK_METHOD3(setLayerGenericMetadata,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 020f93a..c32ef11 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -676,8 +676,6 @@
     static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
             static_cast<Hwc2::IComposerClient::BlendMode>(41);
     static constexpr float kAlpha = 51.f;
-    static constexpr uint32_t kType = 61u;
-    static constexpr uint32_t kAppId = 62u;
     static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
     static constexpr int kSupportedPerFrameMetadata = 101;
     static constexpr int kExpectedHwcSlot = 0;
@@ -711,8 +709,6 @@
 
         mLayerFEState.blendMode = kBlendMode;
         mLayerFEState.alpha = kAlpha;
-        mLayerFEState.type = kType;
-        mLayerFEState.appId = kAppId;
         mLayerFEState.colorTransform = kColorTransform;
         mLayerFEState.color = kColor;
         mLayerFEState.surfaceDamage = kSurfaceDamage;
@@ -746,7 +742,6 @@
 
         EXPECT_CALL(*mHwcLayer, setBlendMode(kBlendMode)).WillOnce(Return(kError));
         EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError));
-        EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
     }
 
     void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 59ed72e..8f76afa 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2871,6 +2871,7 @@
     mOutput.mState.usesClientComposition = false;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
@@ -2883,6 +2884,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2892,6 +2894,7 @@
 
 TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFailsForClientComposition) {
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2904,6 +2907,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2914,6 +2918,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2936,6 +2941,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2963,6 +2969,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -2991,6 +2998,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3019,6 +3027,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3050,6 +3059,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
@@ -3072,6 +3082,7 @@
 struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
     OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
                 .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3219,6 +3230,8 @@
     mOutput.mState.isSecure = false;
     mLayer2.mLayerFEState.hasProtectedContent = true;
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+    EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
+    EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
 
     mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
 }
@@ -3311,6 +3324,7 @@
         EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
         EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
                 .WillRepeatedly(Return());
         EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3583,15 +3597,15 @@
     mLayers[1].mLayerFEState.isOpaque = true;
     mLayers[2].mLayerFEState.isOpaque = true;
     Region accumClearRegion(Rect(10, 11, 12, 13));
-    Region dummyRegion;
+    Region stubRegion;
 
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
-            false,       /* identity transform */
-            false,       /* needs filtering */
-            false,       /* secure */
-            false,       /* supports protected content */
-            dummyRegion, /* clear region */
+            false,      /* identity transform */
+            false,      /* needs filtering */
+            false,      /* secure */
+            false,      /* supports protected content */
+            stubRegion, /* clear region */
             kDisplayViewport,
             kDisplayDataspace,
             false /* realContentIsVisible */,
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index cb467ea..ca7119e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -313,7 +313,7 @@
             logicalOrientation = ui::Rotation::Rotation90;
         }
 
-        const ui::Rotation orientation = device->getPhysicalOrientation() + logicalOrientation;
+        const ui::Rotation orientation = logicalOrientation;
 
         switch (orientation) {
             case ui::ROTATION_0:
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index a3f1b52..1bf43da 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -117,63 +117,7 @@
 
 namespace impl {
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
-    : CommandWriterBase(initialMaxSize) {}
-
-Composer::CommandWriter::~CommandWriter()
-{
-}
-
-void Composer::CommandWriter::setLayerInfo(uint32_t type, uint32_t appId)
-{
-    constexpr uint16_t kSetLayerInfoLength = 2;
-    beginCommand(static_cast<V2_1::IComposerClient::Command>(
-                         IVrComposerClient::VrCommand::SET_LAYER_INFO),
-                 kSetLayerInfoLength);
-    write(type);
-    write(appId);
-    endCommand();
-}
-
-void Composer::CommandWriter::setClientTargetMetadata(
-        const IVrComposerClient::BufferMetadata& metadata)
-{
-    constexpr uint16_t kSetClientTargetMetadataLength = 7;
-    beginCommand(static_cast<V2_1::IComposerClient::Command>(
-                         IVrComposerClient::VrCommand::SET_CLIENT_TARGET_METADATA),
-                 kSetClientTargetMetadataLength);
-    writeBufferMetadata(metadata);
-    endCommand();
-}
-
-void Composer::CommandWriter::setLayerBufferMetadata(
-        const IVrComposerClient::BufferMetadata& metadata)
-{
-    constexpr uint16_t kSetLayerBufferMetadataLength = 7;
-    beginCommand(static_cast<V2_1::IComposerClient::Command>(
-                         IVrComposerClient::VrCommand::SET_LAYER_BUFFER_METADATA),
-                 kSetLayerBufferMetadataLength);
-    writeBufferMetadata(metadata);
-    endCommand();
-}
-
-void Composer::CommandWriter::writeBufferMetadata(
-        const IVrComposerClient::BufferMetadata& metadata)
-{
-    write(metadata.width);
-    write(metadata.height);
-    write(metadata.stride);
-    write(metadata.layerCount);
-    writeSigned(static_cast<int32_t>(metadata.format));
-    write64(metadata.usage);
-}
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
-Composer::Composer(const std::string& serviceName)
-    : mWriter(kWriterInitialSize),
-      mIsUsingVrComposer(serviceName == std::string("vr"))
-{
+Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize) {
     mComposer = V2_1::IComposer::getService(serviceName);
 
     if (mComposer == nullptr) {
@@ -215,15 +159,6 @@
     if (mClient == nullptr) {
         LOG_ALWAYS_FATAL("failed to create composer client");
     }
-
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-    if (mIsUsingVrComposer) {
-        sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
-        if (vrClient == nullptr) {
-            LOG_ALWAYS_FATAL("failed to create vr composer client");
-        }
-    }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
 }
 
 Composer::~Composer() = default;
@@ -262,10 +197,6 @@
     }
 }
 
-bool Composer::isRemote() {
-    return mClient->isRemote();
-}
-
 void Composer::resetCommands() {
     mWriter.reset();
 }
@@ -587,20 +518,6 @@
 {
     mWriter.selectDisplay(display);
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-    if (mIsUsingVrComposer && target.get()) {
-        IVrComposerClient::BufferMetadata metadata = {
-                .width = target->getWidth(),
-                .height = target->getHeight(),
-                .stride = target->getStride(),
-                .layerCount = target->getLayerCount(),
-                .format = static_cast<types::V1_2::PixelFormat>(target->getPixelFormat()),
-                .usage = target->getUsage(),
-        };
-        mWriter.setClientTargetMetadata(metadata);
-    }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
     const native_handle_t* handle = nullptr;
     if (target.get()) {
         handle = target->getNativeBuffer()->handle;
@@ -720,20 +637,6 @@
     mWriter.selectDisplay(display);
     mWriter.selectLayer(layer);
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-    if (mIsUsingVrComposer && buffer.get()) {
-        IVrComposerClient::BufferMetadata metadata = {
-                .width = buffer->getWidth(),
-                .height = buffer->getHeight(),
-                .stride = buffer->getStride(),
-                .layerCount = buffer->getLayerCount(),
-                .format = static_cast<types::V1_2::PixelFormat>(buffer->getPixelFormat()),
-                .usage = buffer->getUsage(),
-        };
-        mWriter.setLayerBufferMetadata(metadata);
-    }
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
     const native_handle_t* handle = nullptr;
     if (buffer.get()) {
         handle = buffer->getNativeBuffer()->handle;
@@ -850,27 +753,6 @@
     return Error::NONE;
 }
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type,
-                             uint32_t appId)
-{
-    if (mIsUsingVrComposer) {
-        mWriter.selectDisplay(display);
-        mWriter.selectLayer(layer);
-        mWriter.setLayerInfo(type, appId);
-    }
-    return Error::NONE;
-}
-#else
-Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) {
-    if (mIsUsingVrComposer) {
-        mWriter.selectDisplay(display);
-        mWriter.selectLayer(layer);
-    }
-    return Error::NONE;
-}
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
 Error Composer::execute()
 {
     // prepare input command queue
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 00ef782..5b66809 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -27,9 +27,6 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
 #include <android/hardware/graphics/common/1.1/types.h>
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <android/hardware/graphics/composer/2.4/IComposerClient.h>
@@ -47,10 +44,6 @@
 
 namespace Hwc2 {
 
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-using frameworks::vr::composer::V2_0::IVrComposerClient;
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-
 namespace types = hardware::graphics::common;
 
 namespace V2_1 = hardware::graphics::composer::V2_1;
@@ -91,11 +84,6 @@
 
     virtual void registerCallback(const sp<IComposerCallback>& callback) = 0;
 
-    // Returns true if the connected composer service is running in a remote
-    // process, false otherwise. This will return false if the service is
-    // configured in passthrough mode, for example.
-    virtual bool isRemote() = 0;
-
     // Reset all pending commands in the command buffer. Useful if you want to
     // skip a frame but have already queued some commands.
     virtual void resetCommands() = 0;
@@ -104,7 +92,6 @@
     virtual Error executeCommands() = 0;
 
     virtual uint32_t getMaxVirtualDisplayCount() = 0;
-    virtual bool isUsingVrComposer() const = 0;
     virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
                                        Display* outDisplay) = 0;
     virtual Error destroyVirtualDisplay(Display display) = 0;
@@ -188,7 +175,6 @@
     virtual Error setLayerVisibleRegion(Display display, Layer layer,
                                         const std::vector<IComposerClient::Rect>& visible) = 0;
     virtual Error setLayerZOrder(Display display, Layer layer, uint32_t z) = 0;
-    virtual Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) = 0;
 
     // Composer HAL 2.2
     virtual Error setLayerPerFrameMetadata(
@@ -344,11 +330,6 @@
 
     void registerCallback(const sp<IComposerCallback>& callback) override;
 
-    // Returns true if the connected composer service is running in a remote
-    // process, false otherwise. This will return false if the service is
-    // configured in passthrough mode, for example.
-    bool isRemote() override;
-
     // Reset all pending commands in the command buffer. Useful if you want to
     // skip a frame but have already queued some commands.
     void resetCommands() override;
@@ -357,7 +338,6 @@
     Error executeCommands() override;
 
     uint32_t getMaxVirtualDisplayCount() override;
-    bool isUsingVrComposer() const override { return mIsUsingVrComposer; }
     Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
                                Display* outDisplay) override;
     Error destroyVirtualDisplay(Display display) override;
@@ -436,7 +416,6 @@
     Error setLayerVisibleRegion(Display display, Layer layer,
                                 const std::vector<IComposerClient::Rect>& visible) override;
     Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
-    Error setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) override;
 
     // Composer HAL 2.2
     Error setLayerPerFrameMetadata(
@@ -490,29 +469,11 @@
             IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
 
 private:
-#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
-    class CommandWriter : public CommandWriterBase {
-    public:
-        explicit CommandWriter(uint32_t initialMaxSize);
-        ~CommandWriter() override;
-
-        void setLayerInfo(uint32_t type, uint32_t appId);
-        void setClientTargetMetadata(
-                const IVrComposerClient::BufferMetadata& metadata);
-        void setLayerBufferMetadata(
-                const IVrComposerClient::BufferMetadata& metadata);
-
-    private:
-        void writeBufferMetadata(
-                const IVrComposerClient::BufferMetadata& metadata);
-    };
-#else
     class CommandWriter : public CommandWriterBase {
     public:
         explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
         ~CommandWriter() override {}
     };
-#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
 
     // Many public functions above simply write a command into the command
     // queue to batch the calls.  validateDisplay and presentDisplay will call
@@ -531,10 +492,6 @@
         64 * 1024 / sizeof(uint32_t) - 16;
     CommandWriter mWriter;
     CommandReader mReader;
-
-    // When true, the we attach to the vr_hwcomposer service instead of the
-    // hwcomposer. This allows us to redirect surfaces to 3d surfaces in vr.
-    const bool mIsUsingVrComposer;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 08559bd..e6bff04 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -977,12 +977,6 @@
     return static_cast<Error>(intError);
 }
 
-Error Layer::setInfo(uint32_t type, uint32_t appId)
-{
-  auto intError = mComposer.setLayerInfo(mDisplayId, mId, type, appId);
-  return static_cast<Error>(intError);
-}
-
 // Composer HAL 2.3
 Error Layer::setColorTransform(const android::mat4& matrix) {
     if (matrix == mColorMatrix) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 6819ff4..8bd6ea8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -380,7 +380,6 @@
     [[clang::warn_unused_result]] virtual hal::Error setVisibleRegion(
             const android::Region& region) = 0;
     [[clang::warn_unused_result]] virtual hal::Error setZOrder(uint32_t z) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setInfo(uint32_t type, uint32_t appId) = 0;
 
     // Composer HAL 2.3
     [[clang::warn_unused_result]] virtual hal::Error setColorTransform(
@@ -422,7 +421,6 @@
     hal::Error setTransform(hal::Transform transform) override;
     hal::Error setVisibleRegion(const android::Region& region) override;
     hal::Error setZOrder(uint32_t z) override;
-    hal::Error setInfo(uint32_t type, uint32_t appId) override;
 
     // Composer HAL 2.3
     hal::Error setColorTransform(const android::mat4& matrix) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 7a2f0f3..7db9359 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -815,10 +815,6 @@
             });
 }
 
-bool HWComposer::isUsingVrComposer() const {
-    return getComposer()->isUsingVrComposer();
-}
-
 status_t HWComposer::setAutoLowLatencyMode(DisplayId displayId, bool on) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
     const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on);
@@ -883,11 +879,6 @@
 
 bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId,
                                             bool hasDisplayIdentificationData) const {
-    if (isUsingVrComposer() && mInternalHwcDisplayId) {
-        ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
-        return true;
-    }
-
     if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) {
         ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
               hwcDisplayId);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c355ebd..e05e41a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -195,8 +195,6 @@
     virtual status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
                                         ui::RenderIntent renderIntent) = 0;
 
-    virtual bool isUsingVrComposer() const = 0;
-
     // Composer 2.4
     virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
@@ -336,8 +334,6 @@
     status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
                                 ui::RenderIntent renderIntent) override;
 
-    bool isUsingVrComposer() const override;
-
     // Composer 2.4
     DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
     bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index fba3261..c8cd442 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -73,6 +73,7 @@
         mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
         mProducerSlotSource(0),
         mProducerBuffers(),
+        mProducerSlotNeedReallocation(0),
         mQueueBufferOutput(),
         mSinkBufferWidth(0),
         mSinkBufferHeight(0),
@@ -335,10 +336,14 @@
             dbgSourceStr(source), *sslot, pslot, result);
     uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
 
+    // reset producer slot reallocation flag
+    mProducerSlotNeedReallocation &= ~(1ULL << pslot);
+
     if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
         // This slot was previously dequeued from the other source; must
         // re-request the buffer.
-        result |= BUFFER_NEEDS_REALLOCATION;
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
+
         mProducerSlotSource &= ~(1ULL << pslot);
         mProducerSlotSource |= sourceBit;
     }
@@ -360,6 +365,9 @@
                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
                 mProducerBuffers[pslot]->getPixelFormat(),
                 mProducerBuffers[pslot]->getUsage());
+
+        // propagate reallocation to VDS consumer
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
     }
 
     return result;
@@ -434,6 +442,11 @@
     if (outBufferAge) {
         *outBufferAge = 0;
     }
+
+    if ((mProducerSlotNeedReallocation & (1ULL << *pslot)) != 0) {
+        result |= BUFFER_NEEDS_REALLOCATION;
+    }
+
     return result;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 3cbad8f..22b5528 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -180,6 +180,10 @@
     uint64_t mProducerSlotSource;
     sp<GraphicBuffer> mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
 
+    // Need to propagate reallocation to VDS consumer.
+    // Each bit corresponds to a producer slot.
+    uint64_t mProducerSlotNeedReallocation;
+
     // The QueueBufferOutput with the latest info from the sink, and with the
     // transform hint cleared. Since we defer queueBuffer from the GPU driver
     // to the sink, we have to return the previous version.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e9965d4..3282a5a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -492,9 +492,6 @@
     compositionState->geomUsesSourceCrop = usesSourceCrop();
     compositionState->isSecure = isSecure();
 
-    compositionState->type = type;
-    compositionState->appId = appId;
-
     compositionState->metadata.clear();
     const auto& supportedMetadata = mFlinger->getHwComposer().getSupportedLayerGenericMetadata();
     for (const auto& [key, mandatory] : supportedMetadata) {
@@ -793,7 +790,9 @@
             // to be applied as per normal (no synchronization).
             mCurrentState.barrierLayer_legacy = nullptr;
         } else {
-            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this);
+            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy,
+                                                         this,
+                                                         barrierLayer);
             if (barrierLayer->addSyncPoint(syncPoint)) {
                 std::stringstream ss;
                 ss << "Adding sync point " << mCurrentState.frameNumber_legacy;
@@ -818,7 +817,7 @@
     ATRACE_CALL();
     *stateToCommit = mPendingStates[0];
 
-    mPendingStates.removeAt(0);
+    mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
@@ -857,6 +856,7 @@
                 mRemoteSyncPoints.pop_front();
             } else {
                 ATRACE_NAME("!frameIsAvailable");
+                mRemoteSyncPoints.front()->checkTimeoutAndLog();
                 break;
             }
         } else {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2c90c92..d071710 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -35,6 +35,7 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
+#include <chrono>
 #include <cstdint>
 #include <list>
 #include <optional>
@@ -881,12 +882,14 @@
 
     class SyncPoint {
     public:
-        explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer)
+        explicit SyncPoint(uint64_t frameNumber,
+                           wp<Layer> requestedSyncLayer,
+                           wp<Layer> barrierLayer_legacy)
               : mFrameNumber(frameNumber),
                 mFrameIsAvailable(false),
                 mTransactionIsApplied(false),
-                mRequestedSyncLayer(requestedSyncLayer) {}
-
+                mRequestedSyncLayer(requestedSyncLayer),
+                mBarrierLayer_legacy(barrierLayer_legacy) {}
         uint64_t getFrameNumber() const { return mFrameNumber; }
 
         bool frameIsAvailable() const { return mFrameIsAvailable; }
@@ -899,11 +902,41 @@
 
         sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); }
 
+        sp<Layer> getBarrierLayer() const { return mBarrierLayer_legacy.promote(); }
+
+        bool isTimeout() const {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s;
+
+            return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD;
+        }
+
+        void checkTimeoutAndLog() {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s;
+
+            if (!frameIsAvailable() && isTimeout()) {
+                const auto now = std::chrono::steady_clock::now();
+                if (now - mLastLogTime > LOG_PERIOD) {
+                    mLastLogTime = now;
+                    sp<Layer> requestedSyncLayer = getRequestedSyncLayer();
+                    sp<Layer> barrierLayer = getBarrierLayer();
+                    ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s",
+                          requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed",
+                          mFrameNumber, (now - mCreateTimeStamp).count(),
+                          barrierLayer ? barrierLayer->getDebugName() : "Removed");
+                }
+            }
+        }
     private:
         const uint64_t mFrameNumber;
         std::atomic<bool> mFrameIsAvailable;
         std::atomic<bool> mTransactionIsApplied;
         wp<Layer> mRequestedSyncLayer;
+        wp<Layer> mBarrierLayer_legacy;
+        const std::chrono::time_point<std::chrono::steady_clock> mCreateTimeStamp =
+            std::chrono::steady_clock::now();
+        std::chrono::time_point<std::chrono::steady_clock> mLastLogTime;
     };
 
     // SyncPoints which will be signaled when the correct frame is at the head
@@ -984,12 +1017,12 @@
     State mDrawingState;
     // Store a copy of the pending state so that the drawing thread can access the
     // states without a lock.
-    Vector<State> mPendingStatesSnapshot;
+    std::deque<State> mPendingStatesSnapshot;
 
     // these are protected by an external lock (mStateLock)
     State mCurrentState;
     std::atomic<uint32_t> mTransactionFlags{0};
-    Vector<State> mPendingStates;
+    std::deque<State> mPendingStates;
 
     // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index f2bc65d..f273725 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -3,8 +3,6 @@
 alecmouri@google.com
 chaviw@google.com
 lpy@google.com
-marissaw@google.com
 racarr@google.com
-steventhomas@google.com
 stoza@google.com
-vhau@google.com
+vishnun@google.com
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index ff91bf7..46112f5 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -340,7 +340,7 @@
         return nextEventTime;
     }
 
-    // Sanity check that the duration is close enough in length to a period without
+    // Check that the duration is close enough in length to a period without
     // falling into double-rate vsyncs.
     bool isCloseToPeriod(nsecs_t duration) {
         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 832f08e..6fb5654 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -227,7 +227,7 @@
 
     // mZeroErrSamplesCount keeps track of how many times in a row there were
     // zero timestamps available in the mPresentFences array.
-    // Used to sanity check that we are able to calculate the model error.
+    // Used to check that we are able to calculate the model error.
     size_t mZeroErrSamplesCount;
 
     // Whether we have updated the vsync event model since the last resync.
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/TimeKeeper.h
index da2195c..40dd841 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/TimeKeeper.h
@@ -43,10 +43,10 @@
     virtual ~TimeKeeper();
 
     /*
-     * Arms callback to fired in time nanoseconds.
+     * Arms callback to fired when time is current based on CLOCK_MONOTONIC
      * There is only one timer, and subsequent calls will reset the callback function and the time.
      */
-    virtual void alarmIn(std::function<void()> const& callback, nsecs_t time) = 0;
+    virtual void alarmAt(std::function<void()> const& callback, nsecs_t time) = 0;
 
     /*
      * Cancels an existing pending callback
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 7c5058e..59c336a 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -88,7 +88,7 @@
     return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
-void Timer::alarmIn(std::function<void()> const& cb, nsecs_t fireIn) {
+void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
     std::lock_guard<decltype(mMutex)> lk(mMutex);
     using namespace std::literals;
     static constexpr int ns_per_s =
@@ -99,11 +99,11 @@
     struct itimerspec old_timer;
     struct itimerspec new_timer {
         .it_interval = {.tv_sec = 0, .tv_nsec = 0},
-        .it_value = {.tv_sec = static_cast<long>(fireIn / ns_per_s),
-                     .tv_nsec = static_cast<long>(fireIn % ns_per_s)},
+        .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
+                     .tv_nsec = static_cast<long>(time % ns_per_s)},
     };
 
-    if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
+    if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
         ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
     }
 }
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h
index a8e2d5a..69ce079 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/Timer.h
@@ -30,9 +30,9 @@
     ~Timer();
     nsecs_t now() const final;
 
-    // NB: alarmIn and alarmCancel are threadsafe; with the last-returning function being effectual
+    // NB: alarmAt and alarmCancel are threadsafe; with the last-returning function being effectual
     //     Most users will want to serialize thes calls so as to be aware of the timer state.
-    void alarmIn(std::function<void()> const& cb, nsecs_t fireIn) final;
+    void alarmAt(std::function<void()> const& cb, nsecs_t time) final;
     void alarmCancel() final;
     void dump(std::string& result) const final;
 
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 2a6fd05..ef92680 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -180,10 +180,10 @@
     mTimeKeeper->alarmCancel();
 }
 
-void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
+void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
     mIntendedWakeupTime = targetTime;
-    mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
-                         targetTime - now);
+    mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
+                         mIntendedWakeupTime);
     mLastTimerSchedule = mTimeKeeper->now();
 }
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61f3fbb..708a5b8 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -78,8 +78,12 @@
 
     if (!validate(timestamp)) {
         // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
-        // don't insert this ts into mTimestamps ringbuffer.
-        if (!mTimestamps.empty()) {
+        // don't insert this ts into mTimestamps ringbuffer. If we are still
+        // in the learning phase we should just clear all timestamps and start
+        // over.
+        if (mTimestamps.size() < kMinimumSamplesForPrediction) {
+            clearTimestamps();
+        } else if (!mTimestamps.empty()) {
             mKnownTimestamp =
                     std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
         } else {
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
index db82772..f42cd53 100644
--- a/services/surfaceflinger/StartPropertySetThread.cpp
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -31,6 +31,7 @@
     property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
     // Clear BootAnimation exit flag
     property_set("service.bootanim.exit", "0");
+    property_set("service.bootanim.progress", "0");
     // Start BootAnimation if not started
     property_set("ctl.start", "bootanim");
     // Exit immediately
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 79f99cc..4698ac6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -46,7 +46,6 @@
 #include <cutils/compiler.h>
 #include <cutils/properties.h>
 #include <dlfcn.h>
-#include <dvr/vr_flinger.h>
 #include <errno.h>
 #include <gui/BufferQueue.h>
 #include <gui/DebugEGLImageTracker.h>
@@ -57,6 +56,7 @@
 #include <gui/LayerMetadata.h>
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
+#include <hidl/ServiceManagement.h>
 #include <input/IInputFlinger.h>
 #include <layerproto/LayerProtoParser.h>
 #include <log/log.h>
@@ -266,7 +266,6 @@
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
-bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 uint32_t SurfaceFlinger::maxGraphicsWidth;
 uint32_t SurfaceFlinger::maxGraphicsHeight;
@@ -331,9 +330,6 @@
 
     maxVirtualDisplaySize = max_virtual_display_dimension(0);
 
-    // Vr flinger is only enabled on Daydream ready devices.
-    useVrFlinger = use_vr_flinger(false);
-
     maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
 
     maxGraphicsWidth = std::max(max_graphics_width(0), 0);
@@ -441,7 +437,7 @@
         // deriving the setting from the set service name, but it
         // would be brittle if the name that's not 'default' is used
         // for production purposes later on.
-        setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+        android::hardware::details::setTrebleTestingOverride(true);
     }
 
     useFrameRateApi = use_frame_rate_api(true);
@@ -601,10 +597,6 @@
         mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
     }
 
-    if (mVrFlinger) {
-      mVrFlinger->OnBootFinished();
-    }
-
     // stop boot animation
     // formerly we would just kill the process, but we now ask it to exit so it
     // can choose where to stop the animation.
@@ -688,9 +680,6 @@
                         : renderengine::RenderEngine::ContextPriority::MEDIUM)
                 .build()));
     mCompositionEngine->setTimeStats(mTimeStats);
-
-    LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
-            "Starting with vr flinger active is not currently supported.");
     mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
     mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
     // Process any initial hotplug and resulting display changes.
@@ -700,30 +689,6 @@
     LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
                         "Internal display is disconnected.");
 
-    if (useVrFlinger) {
-        auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
-            // This callback is called from the vr flinger dispatch thread. We
-            // need to call signalTransaction(), which requires holding
-            // mStateLock when we're not on the main thread. Acquiring
-            // mStateLock from the vr flinger dispatch thread might trigger a
-            // deadlock in surface flinger (see b/66916578), so post a message
-            // to be handled on the main thread instead.
-            static_cast<void>(schedule([=] {
-                ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
-                mVrFlingerRequestsDisplay = requestDisplay;
-                signalTransaction();
-            }));
-        };
-        mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
-                                            getHwComposer()
-                                                    .fromPhysicalDisplayId(*display->getId())
-                                                    .value_or(0),
-                                            vrFlingerRequestDisplayCallback);
-        if (!mVrFlinger) {
-            ALOGE("Failed to start vrflinger");
-        }
-    }
-
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
@@ -1700,98 +1665,6 @@
     }
 }
 
-void SurfaceFlinger::resetDisplayState() {
-    mScheduler->disableHardwareVsync(true);
-    // Clear the drawing state so that the logic inside of
-    // handleTransactionLocked will fire. It will determine the delta between
-    // mCurrentState and mDrawingState and re-apply all changes when we make the
-    // transition.
-    mDrawingState.displays.clear();
-    mDisplays.clear();
-}
-
-void SurfaceFlinger::updateVrFlinger() {
-    ATRACE_CALL();
-    if (!mVrFlinger)
-        return;
-    bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
-    if (vrFlingerRequestsDisplay == getHwComposer().isUsingVrComposer()) {
-        return;
-    }
-
-    if (vrFlingerRequestsDisplay && !getHwComposer().getComposer()->isRemote()) {
-        ALOGE("Vr flinger is only supported for remote hardware composer"
-              " service connections. Ignoring request to transition to vr"
-              " flinger.");
-        mVrFlingerRequestsDisplay = false;
-        return;
-    }
-
-    Mutex::Autolock _l(mStateLock);
-
-    sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
-    LOG_ALWAYS_FATAL_IF(!display);
-
-    const hal::PowerMode currentDisplayPowerMode = display->getPowerMode();
-
-    // Clear out all the output layers from the composition engine for all
-    // displays before destroying the hardware composer interface. This ensures
-    // any HWC layers are destroyed through that interface before it becomes
-    // invalid.
-    for (const auto& [token, displayDevice] : mDisplays) {
-        displayDevice->getCompositionDisplay()->clearOutputLayers();
-    }
-
-    // This DisplayDevice will no longer be relevant once resetDisplayState() is
-    // called below. Clear the reference now so we don't accidentally use it
-    // later.
-    display.clear();
-
-    if (!vrFlingerRequestsDisplay) {
-        mVrFlinger->SeizeDisplayOwnership();
-    }
-
-    resetDisplayState();
-    // Delete the current instance before creating the new one
-    mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
-    mCompositionEngine->setHwComposer(getFactory().createHWComposer(
-            vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
-    mCompositionEngine->getHwComposer().setConfiguration(this, ++getBE().mComposerSequenceId);
-
-    LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
-                        "Switched to non-remote hardware composer");
-
-    if (vrFlingerRequestsDisplay) {
-        mVrFlinger->GrantDisplayOwnership();
-    }
-
-    mVisibleRegionsDirty = true;
-    invalidateHwcGeometry();
-
-    // Re-enable default display.
-    display = getDefaultDisplayDeviceLocked();
-    LOG_ALWAYS_FATAL_IF(!display);
-    setPowerModeInternal(display, currentDisplayPowerMode);
-
-    // Reset the timing values to account for the period of the swapped in HWC
-    const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
-    mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
-
-    // The present fences returned from vr_hwc are not an accurate
-    // representation of vsync times.
-    mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() || !hasSyncFramework);
-
-    // Use phase of 0 since phase is not known.
-    // Use latency of 0, which will snap to the ideal latency.
-    DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
-    setCompositorTimingSnapped(stats, 0);
-
-    mScheduler->resyncToHardwareVsync(false, vsyncPeriod);
-
-    mRepaintEverything = true;
-    setTransactionFlags(eDisplayTransactionNeeded);
-}
-
 sp<Fence> SurfaceFlinger::previousFrameFence() {
     // We are storing the last 2 present fences. If sf's phase offset is to be
     // woken up before the actual vsync but targeting the next vsync, we need to check
@@ -1853,8 +1726,14 @@
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
     // seeing this same value.
-    const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load();
-    mExpectedPresentTime = expectedVSyncTime;
+    if (expectedVSyncTime >= frameStart) {
+        mExpectedPresentTime = expectedVSyncTime;
+    } else {
+        mExpectedPresentTime = mScheduler->getDispSyncExpectedPresentTime(frameStart);
+    }
+
+    const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
+    mScheduledPresentTime = expectedVSyncTime;
 
     // When Backpressure propagation is enabled we want to give a small grace period
     // for the present fence to fire instead of just giving up on this frame to handle cases
@@ -1884,7 +1763,7 @@
     const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
                                              framePending ||
                                                      (previousPresentTime >= 0 &&
-                                                      (lastExpectedPresentTime <
+                                                      (lastScheduledPresentTime <
                                                        previousPresentTime - frameMissedSlop))};
     const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
                                                 mHadDeviceComposition && frameMissed};
@@ -1960,11 +1839,6 @@
         }
     }
 
-    // Now that we're going to make it to the handleMessageTransaction()
-    // call below it's safe to call updateVrFlinger(), which will
-    // potentially trigger a display handoff.
-    updateVrFlinger();
-
     if (mTracingEnabledChanged) {
         mTracingEnabled = mTracing.isEnabled();
         mTracingEnabledChanged = false;
@@ -2611,7 +2485,7 @@
     builder.setIsSecure(state.isSecure);
     builder.setLayerStackId(state.layerStack);
     builder.setPowerAdvisor(&mPowerAdvisor);
-    builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer());
+    builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays);
     builder.setName(state.displayName);
     const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
 
@@ -4501,12 +4375,9 @@
 
 void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
     result.append("Layer frame timestamps:\n");
-
-    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        currentLayers[i]->dumpFrameEvents(result);
-    }
+    // Traverse all layers to dump frame-events for each layer
+    mCurrentState.traverseInZOrder(
+        [&] (Layer* layer) { layer->dumpFrameEvents(result); });
 }
 
 void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
@@ -4835,15 +4706,6 @@
     const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
     alloc.dump(result);
 
-    /*
-     * Dump VrFlinger state if in use.
-     */
-    if (mVrFlingerRequestsDisplay && mVrFlinger) {
-        result.append("VrFlinger state:\n");
-        result.append(mVrFlinger->Dump());
-        result.append("\n");
-    }
-
     result.append(mTimeStats->miniDump());
     result.append("\n");
 }
@@ -5226,11 +5088,8 @@
                 }
                 return NO_ERROR;
             }
-            // Is VrFlinger active?
-            case 1028: {
-                Mutex::Autolock _l(mStateLock);
-                reply->writeBool(getHwComposer().isUsingVrComposer());
-                return NO_ERROR;
+            case 1028: { // Unused.
+                return NAME_NOT_FOUND;
             }
             // Set buffer size for SF tracing (value in KB)
             case 1029: {
@@ -5746,7 +5605,7 @@
 
     // TODO(b/116112787) Make buffer usage a parameter.
     const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
     *outBuffer =
             getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
                                              static_cast<android_pixel_format>(reqPixelFormat), 1,
@@ -6209,9 +6068,6 @@
     // on the work to remove the table in that bug rather than adding more to
     // it.
     static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{
-            // Note: METADATA_OWNER_UID and METADATA_WINDOW_TYPE are officially
-            // supported, and exposed via the
-            // IVrComposerClient::VrCommand::SET_LAYER_INFO command.
             {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID},
             {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR},
     };
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c727574..90ac856 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -109,10 +109,6 @@
 class RenderEngine;
 } // namespace renderengine
 
-namespace dvr {
-class VrFlinger;
-} // namespace dvr
-
 enum {
     eTransactionNeeded = 0x01,
     eTraversalNeeded = 0x02,
@@ -798,8 +794,7 @@
     // The following thread safety rules apply when accessing mHwc, either
     // directly or via getHwComposer():
     //
-    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
-    //    only when switching into and out of vr. Recreating mHwc must only be
+    // 1. When recreating mHwc, acquire mStateLock. Recreating mHwc must only be
     //    done on the main thread.
     //
     // 2. When accessing mHwc on the main thread, it's not necessary to acquire
@@ -983,14 +978,6 @@
 
     void onFrameRateFlexibilityTokenReleased();
 
-    /* ------------------------------------------------------------------------
-     * VrFlinger
-     */
-    void resetDisplayState() REQUIRES(mStateLock);
-
-    // Check to see if we should handoff to vr flinger.
-    void updateVrFlinger();
-
     void updateColorMatrixLocked();
 
     /* ------------------------------------------------------------------------
@@ -1175,9 +1162,6 @@
     // to mWindowManager or mInputFlinger
     std::atomic<bool> mBootFinished = false;
 
-    std::unique_ptr<dvr::VrFlinger> mVrFlinger;
-    std::atomic<bool> mVrFlingerRequestsDisplay = false;
-    static bool useVrFlinger;
     std::thread::id mMainThreadId = std::this_thread::get_id();
 
     DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::kEnhanced;
@@ -1215,6 +1199,7 @@
     std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
     std::atomic<nsecs_t> mExpectedPresentTime = 0;
+    nsecs_t mScheduledPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index cfc301b..7666f7f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -72,7 +72,7 @@
 prop {
     api_name: "max_graphics_width"
     type: Integer
-    scope: System
+    scope: Public
     access: Readonly
     prop_name: "ro.surface_flinger.max_graphics_width"
 }
@@ -82,7 +82,7 @@
 prop {
     api_name: "max_graphics_height"
     type: Integer
-    scope: System
+    scope: Public
     access: Readonly
     prop_name: "ro.surface_flinger.max_graphics_height"
 }
@@ -328,7 +328,7 @@
 prop {
     api_name: "refresh_rate_switching"
     type: Boolean
-    scope: System
+    scope: Public
     access: Readonly
     prop_name: "ro.surface_flinger.refresh_rate_switching"
     deprecated: true
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
index b66e56e..ba60a7d 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
@@ -36,6 +36,11 @@
     prop_name: "ro.surface_flinger.display_primary_white"
   }
   prop {
+    api_name: "display_update_imminent_timeout_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+  }
+  prop {
     api_name: "enable_protected_contents"
     prop_name: "ro.surface_flinger.protected_contents"
   }
@@ -57,6 +62,16 @@
     prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
   }
   prop {
+    api_name: "max_graphics_height"
+    type: Integer
+    prop_name: "ro.surface_flinger.max_graphics_height"
+  }
+  prop {
+    api_name: "max_graphics_width"
+    type: Integer
+    prop_name: "ro.surface_flinger.max_graphics_width"
+  }
+  prop {
     api_name: "max_virtual_display_dimension"
     type: Long
     prop_name: "ro.surface_flinger.max_virtual_display_dimension"
@@ -73,6 +88,11 @@
     enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
   }
   prop {
+    api_name: "refresh_rate_switching"
+    prop_name: "ro.surface_flinger.refresh_rate_switching"
+    deprecated: true
+  }
+  prop {
     api_name: "running_without_sync_framework"
     prop_name: "ro.surface_flinger.running_without_sync_framework"
   }
@@ -100,16 +120,29 @@
     prop_name: "ro.surface_flinger.support_kernel_idle_timer"
   }
   prop {
+    api_name: "supports_background_blur"
+    prop_name: "ro.surface_flinger.supports_background_blur"
+  }
+  prop {
     api_name: "use_color_management"
     prop_name: "ro.surface_flinger.use_color_management"
   }
   prop {
+    api_name: "use_content_detection_for_refresh_rate"
+    prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate"
+  }
+  prop {
     api_name: "use_context_priority"
     prop_name: "ro.surface_flinger.use_context_priority"
   }
   prop {
+    api_name: "use_frame_rate_api"
+    prop_name: "ro.surface_flinger.use_frame_rate_api"
+  }
+  prop {
     api_name: "use_smart_90_for_video"
     prop_name: "ro.surface_flinger.use_smart_90_for_video"
+    deprecated: true
   }
   prop {
     api_name: "use_vr_flinger"
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index fe2af80..1532855 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -44,7 +44,7 @@
         "libtrace_proto",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.composer@2.1",
         "libandroid",
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 293738c..4868c12 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -88,7 +88,7 @@
     sp<Surface> mSurface;
 };
 
-/* Used to generate valid fences. It is not possible to create a dummy sync
+/* Used to generate valid fences. It is not possible to create a placeholder sync
  * fence for testing. Egl can generate buffers along with a valid fence.
  * The buffer cannot be guaranteed to be the same format across all devices so
  * a CPU filled buffer is used instead. The Egl fence is used along with the
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 97cba63..1f8f7ed 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -118,10 +118,9 @@
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
     const auto producer = layer->getIGraphicBufferProducer();
-    const sp<IProducerListener> dummyListener(new DummyProducerListener);
+    const sp<IProducerListener> stubListener(new StubProducerListener);
     IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
-    ASSERT_EQ(OK,
-              producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+    ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
 
     std::map<int, sp<GraphicBuffer>> slotMap;
     auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2861013..3535fbb 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -8,12 +8,12 @@
          "FakeComposerUtils.cpp",
          "SFFakeHwc_test.cpp"
     ],
+    require_root: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
         "android.hardware.graphics.composer@2.4",
-        "android.hardware.graphics.composer@2.1-resources",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
@@ -33,6 +33,7 @@
         "libutils",
     ],
     static_libs: [
+        "android.hardware.graphics.composer@2.1-resources",
         "libcompositionengine",
         "libgmock",
         "libperfetto_client_experimental",
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 96a7541..1cea25a 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -29,8 +29,8 @@
 #include "SurfaceFlinger.h" // Get the name of the service...
 
 #include <binder/IServiceManager.h>
-
 #include <cutils/properties.h>
+#include <hidl/ServiceManagement.h>
 
 #include <iomanip>
 #include <thread>
@@ -173,7 +173,7 @@
     property_set("debug.sf.hwc_service_name", "mock");
 
     // This allows tests/SF to register/load a HIDL service not listed in manifest files.
-    setenv("TREBLE_TESTING_OVERRIDE", "true", true);
+    android::hardware::details::setTrebleTestingOverride(true);
     property_set("debug.sf.treble_testing_override", "true");
 }
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 3c4a791..1bbc3f8 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -58,6 +58,7 @@
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
         "FrameTracerTest.cpp",
+        "TimerTest.cpp",
         "TransactionApplicationTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 32d722e..faa619e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -577,8 +577,6 @@
                     .Times(1);
             // TODO: Coverage of other values
             EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
-            // TODO: Coverage of other values
-            EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
 
             // These expectations retire on saturation as the code path these
             // expectations are for appears to make an extra call to them.
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 06bdcdc..0323778 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1298,55 +1298,6 @@
 }
 
 /* ------------------------------------------------------------------------
- * SurfaceFlinger::resetDisplayState
- */
-
-TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // vsync is enabled and available
-    mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
-    mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
-
-    // A display exists
-    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
-    existing.inject();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // The call disable vsyncs
-    EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1);
-
-    // The call ends any display resyncs
-    EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.resetDisplayState();
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // vsyncs should be off and not available.
-    EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
-    EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
-
-    // The display should have been removed from the display map.
-    EXPECT_FALSE(hasDisplayDevice(existing.token()));
-
-    // The display should still exist in the current state
-    EXPECT_TRUE(hasCurrentDisplayState(existing.token()));
-
-    // The display should have been removed from the drawing state
-    EXPECT_FALSE(hasDrawingDisplayState(existing.token()));
-}
-
-/* ------------------------------------------------------------------------
  * DisplayDevice::GetBestColorMode
  */
 class GetBestColorModeTest : public DisplayTransactionTest {
@@ -2019,8 +1970,6 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillOnce(Return(false));
-
     setupCommonCallExpectationsForConnectProcessing<Case>();
 
     // --------------------------------------------------------------------
@@ -2082,7 +2031,6 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
             .Times(0);
 
@@ -2139,20 +2087,9 @@
                             SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
                             Return(Error::NONE)));
 
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
     ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
 }
 
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfExternalForVrComposer) {
-    // Inject a primary display.
-    PrimaryDisplayVariant::injectHwcDisplay(this);
-
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(true));
-
-    ignoresHotplugConnectCommon<SimpleExternalDisplayCase>();
-}
-
 TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
     processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
 }
@@ -2177,8 +2114,6 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
     setupCommonCallExpectationsForConnectProcessing<Case>();
     setupCommonCallExpectationsForDisconnectProcessing<Case>();
 
@@ -2225,8 +2160,6 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
     setupCommonCallExpectationsForConnectProcessing<Case>();
     setupCommonCallExpectationsForDisconnectProcessing<Case>();
 
@@ -2385,11 +2318,6 @@
     mFlinger.mutableCurrentState().displays.removeItem(existing.token());
 
     // --------------------------------------------------------------------
-    // Call Expectations
-
-    EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
-
-    // --------------------------------------------------------------------
     // Invocation
 
     mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
index 68cb52f..a119e27 100644
--- a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -77,6 +77,22 @@
         return tracingSession;
     }
 
+    std::vector<perfetto::protos::TracePacket> readGraphicsFramePacketsBlocking(
+            perfetto::TracingSession* tracingSession) {
+        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+        perfetto::protos::Trace trace;
+        EXPECT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+
+        std::vector<perfetto::protos::TracePacket> packets;
+        for (const auto& packet : trace.packet()) {
+            if (!packet.has_graphics_frame_event()) {
+                continue;
+            }
+            packets.emplace_back(packet);
+        }
+        return packets;
+    }
+
     std::unique_ptr<FrameTracer> mFrameTracer;
     FenceToFenceTimeMap fenceFactory;
 };
@@ -142,40 +158,29 @@
         auto tracingSession = getTracingSessionForTest();
 
         tracingSession->StartBlocking();
-        // Clean up irrelevant traces.
-        tracingSession->ReadTraceBlocking();
-
         mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
         // Create second trace packet to finalize the previous one.
         mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
         tracingSession->StopBlocking();
 
-        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-        EXPECT_EQ(raw_trace.size(), 0);
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 0);
     }
 
     {
         auto tracingSession = getTracingSessionForTest();
 
         tracingSession->StartBlocking();
-        // Clean up irrelevant traces.
-        tracingSession->ReadTraceBlocking();
-
         mFrameTracer->traceNewLayer(layerId, layerName);
         mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
         // Create second trace packet to finalize the previous one.
         mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
         tracingSession->StopBlocking();
 
-        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-        ASSERT_GT(raw_trace.size(), 0);
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 1);
 
-        perfetto::protos::Trace trace;
-        ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
-        ASSERT_FALSE(trace.packet().empty());
-        EXPECT_EQ(trace.packet().size(), 1);
-
-        const auto& packet = trace.packet().Get(0);
+        const auto& packet = packets[0];
         ASSERT_TRUE(packet.has_timestamp());
         EXPECT_EQ(packet.timestamp(), timestamp);
         ASSERT_TRUE(packet.has_graphics_frame_event());
@@ -205,24 +210,21 @@
         fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
         auto tracingSession = getTracingSessionForTest();
         tracingSession->StartBlocking();
-        // Clean up irrelevant traces.
-        tracingSession->ReadTraceBlocking();
         // Trace.
         mFrameTracer->traceNewLayer(layerId, layerName);
         mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
         // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
         mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
         tracingSession->StopBlocking();
-        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-        EXPECT_EQ(raw_trace.size(), 0);
+
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 0);
     }
 
     {
         auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
         auto tracingSession = getTracingSessionForTest();
         tracingSession->StartBlocking();
-        // Clean up irrelevant traces.
-        tracingSession->ReadTraceBlocking();
         mFrameTracer->traceNewLayer(layerId, layerName);
         mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
         const nsecs_t timestamp = systemTime();
@@ -231,15 +233,10 @@
         mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
         tracingSession->StopBlocking();
 
-        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-        ASSERT_GT(raw_trace.size(), 0);
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above.
 
-        perfetto::protos::Trace trace;
-        ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
-        ASSERT_FALSE(trace.packet().empty());
-        EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
-
-        const auto& packet = trace.packet().Get(1);
+        const auto& packet = packets[1];
         ASSERT_TRUE(packet.has_timestamp());
         EXPECT_EQ(packet.timestamp(), timestamp);
         ASSERT_TRUE(packet.has_graphics_frame_event());
@@ -266,8 +263,6 @@
     auto tracingSession = getTracingSessionForTest();
 
     tracingSession->StartBlocking();
-    // Clean up irrelevant traces.
-    tracingSession->ReadTraceBlocking();
     mFrameTracer->traceNewLayer(layerId, layerName);
 
     // traceFence called after fence signalled.
@@ -288,22 +283,17 @@
     mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
     tracingSession->StopBlocking();
 
-    std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-    ASSERT_GT(raw_trace.size(), 0);
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 2);
 
-    perfetto::protos::Trace trace;
-    ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
-    ASSERT_FALSE(trace.packet().empty());
-    EXPECT_EQ(trace.packet().size(), 2);
-
-    const auto& packet1 = trace.packet().Get(0);
+    const auto& packet1 = packets[0];
     ASSERT_TRUE(packet1.has_timestamp());
     EXPECT_EQ(packet1.timestamp(), signalTime1);
     ASSERT_TRUE(packet1.has_graphics_frame_event());
     ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
     ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
 
-    const auto& packet2 = trace.packet().Get(1);
+    const auto& packet2 = packets[1];
     ASSERT_TRUE(packet2.has_timestamp());
     EXPECT_EQ(packet2.timestamp(), signalTime2);
     ASSERT_TRUE(packet2.has_graphics_frame_event());
@@ -323,8 +313,6 @@
     auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
 
     tracingSession->StartBlocking();
-    // Clean up irrelevant traces.
-    tracingSession->ReadTraceBlocking();
     mFrameTracer->traceNewLayer(layerId, layerName);
     mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence, type);
     fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
@@ -332,8 +320,8 @@
     mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
     tracingSession->StopBlocking();
 
-    std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-    EXPECT_EQ(raw_trace.size(), 0);
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 0);
 }
 
 TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
@@ -347,8 +335,6 @@
     auto tracingSession = getTracingSessionForTest();
 
     tracingSession->StartBlocking();
-    // Clean up irrelevant traces.
-    tracingSession->ReadTraceBlocking();
     mFrameTracer->traceNewLayer(layerId, layerName);
 
     // traceFence called after fence signalled.
@@ -369,15 +355,10 @@
     mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
     tracingSession->StopBlocking();
 
-    std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
-    ASSERT_GT(raw_trace.size(), 0);
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 2);
 
-    perfetto::protos::Trace trace;
-    ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
-    ASSERT_FALSE(trace.packet().empty());
-    EXPECT_EQ(trace.packet().size(), 2);
-
-    const auto& packet1 = trace.packet().Get(0);
+    const auto& packet1 = packets[0];
     ASSERT_TRUE(packet1.has_timestamp());
     EXPECT_EQ(packet1.timestamp(), startTime1);
     ASSERT_TRUE(packet1.has_graphics_frame_event());
@@ -386,7 +367,7 @@
     const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
     EXPECT_EQ(buffer_event1.duration_ns(), duration);
 
-    const auto& packet2 = trace.packet().Get(1);
+    const auto& packet2 = packets[1];
     ASSERT_TRUE(packet2.has_timestamp());
     EXPECT_EQ(packet2.timestamp(), startTime2);
     ASSERT_TRUE(packet2.has_graphics_frame_event());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 38bc8a1..cd2a482 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,8 +289,6 @@
         return mFlinger->destroyDisplay(displayToken);
     }
 
-    auto resetDisplayState() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->resetDisplayState(); }
-
     auto setupNewDisplayDeviceInternal(
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -365,6 +363,10 @@
 
     auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
 
+    auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+        return mFlinger->onTransact(code, data, reply, flags);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 63a34af..0a24650 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -221,7 +221,7 @@
 }
 
 static std::string genLayerName(int32_t layerId) {
-    return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.dummy#") + std::to_string(layerId);
+    return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.example.fake#") + std::to_string(layerId);
 }
 
 void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
@@ -424,7 +424,7 @@
                                            std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
                                                    .count());
 
-    // Push a dummy present fence to trigger flushing the RenderEngine timings.
+    // Push a fake present fence to trigger flushing the RenderEngine timings.
     mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
@@ -505,7 +505,7 @@
     ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
     ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
 
-    // Push a dummy present fence to trigger flushing the RenderEngine timings.
+    // Push a fake present fence to trigger flushing the RenderEngine timings.
     mTimeStats->setPowerMode(PowerMode::ON);
     mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
             std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
diff --git a/services/surfaceflinger/tests/unittests/TimerTest.cpp b/services/surfaceflinger/tests/unittests/TimerTest.cpp
new file mode 100644
index 0000000..cda6bbf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TimerTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AsyncCallRecorder.h"
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/Timer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+struct TimerTest : testing::Test {
+    static constexpr int mIterations = 20;
+
+    AsyncCallRecorder<void (*)()> mCallbackRecorder;
+    Timer mTimer;
+
+    void timerCallback() { mCallbackRecorder.recordCall(); }
+};
+
+TEST_F(TimerTest, callsCallbackIfScheduledInPast) {
+    for (int i = 0; i < mIterations; i++) {
+        mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00);
+        EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
+        EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
+    }
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 373f6a5..f630e3b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -64,19 +64,19 @@
 class ControllableClock : public TimeKeeper {
 public:
     ControllableClock() {
-        ON_CALL(*this, alarmIn(_, _))
-                .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
+        ON_CALL(*this, alarmAt(_, _))
+                .WillByDefault(Invoke(this, &ControllableClock::alarmAtDefaultBehavior));
         ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
     }
 
     MOCK_CONST_METHOD0(now, nsecs_t());
-    MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
+    MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time));
     MOCK_METHOD0(alarmCancel, void());
     MOCK_CONST_METHOD1(dump, void(std::string&));
 
-    void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+    void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
         mCallback = callback;
-        mNextCallbackTime = time + mCurrentTime;
+        mNextCallbackTime = time;
     }
 
     nsecs_t fakeTime() const { return mCurrentTime; }
@@ -192,8 +192,8 @@
         class TimeKeeperWrapper : public TimeKeeper {
         public:
             TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
-            void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
-                mControllableClock.alarmIn(callback, time);
+            void alarmAt(std::function<void()> const& callback, nsecs_t time) final {
+                mControllableClock.alarmAt(callback, time);
             }
             void alarmCancel() final { mControllableClock.alarmCancel(); }
             nsecs_t now() const final { return mControllableClock.now(); }
@@ -222,7 +222,7 @@
 };
 
 TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
     {
         VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
@@ -234,7 +234,7 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
     auto intended = mPeriod - 230;
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
 
     CountingCallback cb(mDispatch);
     EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
@@ -246,7 +246,7 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
-    EXPECT_CALL(mMockClock, alarmIn(_, 1050));
+    EXPECT_CALL(mMockClock, alarmAt(_, 1050));
 
     CountingCallback cb(mDispatch);
     mDispatch.schedule(cb, 100, mPeriod);
@@ -262,14 +262,14 @@
     auto const workDuration = 10 * mPeriod;
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
             .WillOnce(Return(mPeriod * 11));
-    EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
+    EXPECT_CALL(mMockClock, alarmAt(_, mPeriod));
 
     CountingCallback cb(mDispatch);
     EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb(mDispatch);
@@ -278,7 +278,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb(mDispatch);
@@ -288,7 +288,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
@@ -302,7 +302,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmAt(_, 900));
     EXPECT_CALL(mMockClock, alarmCancel());
 
     auto resource = std::make_shared<int>(110);
@@ -332,9 +332,9 @@
             .WillOnce(Return(1075));
 
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 955)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 813)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 975)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -360,9 +360,9 @@
             .WillOnce(Return(10000));
 
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 750)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -374,8 +374,8 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -388,9 +388,9 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -403,10 +403,10 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1590)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
 
     auto offset = 400;
     auto closeOffset = offset + mDispatchGroupThreshold - 1;
@@ -437,9 +437,10 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 900));
-    EXPECT_CALL(mMockClock, alarmIn(_, 800));
-    EXPECT_CALL(mMockClock, alarmIn(_, 100));
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 800)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel());
 
     CountingCallback cb0(mDispatch);
@@ -477,8 +478,8 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
 
     VSyncDispatch::CallbackToken tmp;
     tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
@@ -512,10 +513,10 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
 
     CountingCallback cb(mDispatch);
     mDispatch.schedule(cb, 0, 1000);
@@ -532,10 +533,10 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 850)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1800)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -553,7 +554,7 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     CountingCallback cb1(mDispatch);
@@ -563,9 +564,9 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
 
     CountingCallback cb0(mDispatch);
     mDispatch.schedule(cb0, 500, 1000);
@@ -587,7 +588,7 @@
 
 // b/1450138150
 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500));
+    EXPECT_CALL(mMockClock, alarmAt(_, 500));
     CountingCallback cb(mDispatch);
     EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
     mMockClock.advanceBy(400);
@@ -617,8 +618,8 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq);
     CountingCallback cb0(mDispatch);
     EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
     advanceToNextCallback();
@@ -626,7 +627,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 600));
+    EXPECT_CALL(mMockClock, alarmAt(_, 600));
 
     CountingCallback cb(mDispatch);
     EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
@@ -637,7 +638,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
@@ -651,7 +652,7 @@
 }
 
 TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
-    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
 
     VSyncCallbackRegistration cb(
@@ -669,8 +670,8 @@
 // b/154303580
 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
     CountingCallback cb1(mDispatch);
     CountingCallback cb2(mDispatch);
 
@@ -691,8 +692,8 @@
 // update later, as opposed to blocking the calling thread.
 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
     CountingCallback cb(mDispatch);
 
     EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
@@ -709,7 +710,7 @@
 // b/154303580.
 TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
     CountingCallback cb1(mDispatch);
     CountingCallback cb2(mDispatch);
@@ -730,8 +731,8 @@
 
 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
     Sequence seq;
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
-    EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
     CountingCallback cb1(mDispatch);
     CountingCallback cb2(mDispatch);
@@ -760,7 +761,7 @@
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
             .InSequence(seq)
             .WillOnce(Return(1000));
-    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
             .InSequence(seq)
             .WillOnce(Return(1000));
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index d4cd11d..5e5d51c 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -450,6 +450,20 @@
     EXPECT_THAT(intercept, Eq(0));
 }
 
+TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) {
+    EXPECT_TRUE(tracker.addVsyncTimestamp(600));
+    EXPECT_TRUE(tracker.needsMoreSamples());
+
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
+
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.needsMoreSamples());
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+    }
+
+    EXPECT_FALSE(tracker.needsMoreSamples());
+}
+
 } // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index c2c5072..cd9b87a 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -52,11 +52,9 @@
     MOCK_METHOD0(getCapabilities, std::vector<IComposer::Capability>());
     MOCK_METHOD0(dumpDebugInfo, std::string());
     MOCK_METHOD1(registerCallback, void(const sp<IComposerCallback>&));
-    MOCK_METHOD0(isRemote, bool());
     MOCK_METHOD0(resetCommands, void());
     MOCK_METHOD0(executeCommands, Error());
     MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
-    MOCK_CONST_METHOD0(isUsingVrComposer, bool());
     MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
     MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
     MOCK_METHOD1(acceptDisplayChanges, Error(Display));
@@ -110,7 +108,6 @@
     MOCK_METHOD3(setLayerVisibleRegion,
                  Error(Display, Layer, const std::vector<IComposerClient::Rect>&));
     MOCK_METHOD3(setLayerZOrder, Error(Display, Layer, uint32_t));
-    MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t));
     MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector<RenderIntent>*));
     MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
     MOCK_METHOD4(getDisplayedContentSamplingAttributes,
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index afb3004..7097e7a 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -15,7 +15,6 @@
 sharedLibraries = [
     "libbase",
     "libcutils",
-    "libgtest_prod",
     "libgui",
     "liblog",
     "libpdx_default_transport",
@@ -48,6 +47,7 @@
 
 cc_binary {
     srcs: ["bufferhubd.cpp"],
+    system_ext_specific: true,
     cflags: [
         "-DLOG_TAG=\"bufferhubd\"",
         "-DTRACE=0",
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 4df7b7c..3728731 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,6 +1,8 @@
 cc_library_shared {
     name: "libvr_hwc-hal",
 
+    system_ext_specific: true,
+
     srcs: [
         "impl/vr_hwc.cpp",
         "impl/vr_composer_client.cpp",
@@ -97,6 +99,7 @@
 
 cc_binary {
     name: "vr_hwc",
+    system_ext_specific: true,
     vintf_fragments: ["manifest_vr_hwc.xml"],
     srcs: [
         "vr_hardware_composer_service.cpp",
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 20301f6..0ef8cc4 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -30,6 +30,7 @@
 
 cc_binary {
     name: "performanced",
+    system_ext_specific: true,
     defaults: ["performanced_defaults"],
     srcs: [
         "cpu_set.cpp",
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index dcaa663..9cf4905 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -14,6 +14,7 @@
 ]
 
 header_libraries = [
+    "jni_headers",
     "libdvr_headers",
 ]
 
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index f69de1f..1d29bab 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -21,7 +21,7 @@
 }
 
 llndk_library {
-    name: "libvulkan",
+    name: "libvulkan.llndk",
     symbol_file: "libvulkan.map.txt",
     export_llndk_headers: [
         "vulkan_headers_llndk",
@@ -30,6 +30,7 @@
 
 cc_library_shared {
     name: "libvulkan",
+    llndk_stubs: "libvulkan.llndk",
     clang: true,
     sanitize: {
         misc_undefined: ["integer"],
@@ -89,7 +90,6 @@
         "libhardware",
         "libsync",
         "libbase",
-        "libdl_android",
         "libhidlbase",
         "liblog",
         "libui",
@@ -100,6 +100,7 @@
         "libnativebridge_lazy",
         "libnativeloader_lazy",
         "libnativewindow",
+        "libvndksupport",
         "android.hardware.graphics.common@1.0",
         "libSurfaceFlingerProp",
     ],
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index d9a9427..26052fb 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -226,6 +226,7 @@
     INIT_PROC(true, dev, CreateQueryPool);
     INIT_PROC(true, dev, DestroyQueryPool);
     INIT_PROC(true, dev, GetQueryPoolResults);
+    INIT_PROC(false, dev, ResetQueryPool);
     INIT_PROC(true, dev, CreateBuffer);
     INIT_PROC(true, dev, DestroyBuffer);
     INIT_PROC(true, dev, CreateBufferView);
@@ -337,8 +338,20 @@
     INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
     INIT_PROC(false, dev, GetDeviceQueue2);
     INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
+    INIT_PROC(false, dev, CreateRenderPass2);
+    INIT_PROC(false, dev, CmdBeginRenderPass2);
+    INIT_PROC(false, dev, CmdNextSubpass2);
+    INIT_PROC(false, dev, CmdEndRenderPass2);
+    INIT_PROC(false, dev, GetSemaphoreCounterValue);
+    INIT_PROC(false, dev, WaitSemaphores);
+    INIT_PROC(false, dev, SignalSemaphore);
     INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID);
     INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID);
+    INIT_PROC(false, dev, CmdDrawIndirectCount);
+    INIT_PROC(false, dev, CmdDrawIndexedIndirectCount);
+    INIT_PROC(false, dev, GetBufferOpaqueCaptureAddress);
+    INIT_PROC(false, dev, GetBufferDeviceAddress);
+    INIT_PROC(false, dev, GetDeviceMemoryOpaqueCaptureAddress);
     // clang-format on
 
     return success;
@@ -391,6 +404,7 @@
 VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
 VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
 VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -520,8 +534,20 @@
 VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
 VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
 VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
 VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
 
 VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
     return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -551,6 +577,7 @@
         "vkEnumerateInstanceVersion",
         "vkEnumeratePhysicalDeviceGroups",
         "vkEnumeratePhysicalDeviceGroupsKHR",
+        "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR",
         "vkEnumeratePhysicalDevices",
         "vkGetDisplayModeProperties2KHR",
         "vkGetDisplayPlaneCapabilities2KHR",
@@ -571,7 +598,7 @@
         "vkGetPhysicalDeviceFormatProperties",
         "vkGetPhysicalDeviceFormatProperties2",
         "vkGetPhysicalDeviceFormatProperties2KHR",
-        "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
+        "vkGetPhysicalDeviceFragmentShadingRatesKHR",
         "vkGetPhysicalDeviceImageFormatProperties",
         "vkGetPhysicalDeviceImageFormatProperties2",
         "vkGetPhysicalDeviceImageFormatProperties2KHR",
@@ -583,6 +610,7 @@
         "vkGetPhysicalDeviceProperties",
         "vkGetPhysicalDeviceProperties2",
         "vkGetPhysicalDeviceProperties2KHR",
+        "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR",
         "vkGetPhysicalDeviceQueueFamilyProperties",
         "vkGetPhysicalDeviceQueueFamilyProperties2",
         "vkGetPhysicalDeviceQueueFamilyProperties2KHR",
@@ -595,6 +623,7 @@
         "vkGetPhysicalDeviceSurfaceFormatsKHR",
         "vkGetPhysicalDeviceSurfacePresentModesKHR",
         "vkGetPhysicalDeviceSurfaceSupportKHR",
+        "vkGetPhysicalDeviceToolPropertiesEXT",
         "vkSubmitDebugUtilsMessageEXT",
     };
     // clang-format on
@@ -646,6 +675,7 @@
         { "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
         { "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
         { "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
+        { "vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass2) },
         { "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
         { "vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer) },
         { "vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline) },
@@ -665,12 +695,16 @@
         { "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
         { "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
         { "vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect) },
+        { "vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirectCount) },
         { "vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect) },
+        { "vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirectCount) },
         { "vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery) },
         { "vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass) },
+        { "vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass2) },
         { "vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands) },
         { "vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer) },
         { "vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass) },
+        { "vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass2) },
         { "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
         { "vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants) },
         { "vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent) },
@@ -709,6 +743,7 @@
         { "vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout) },
         { "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
         { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
+        { "vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass2) },
         { "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
         { "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
         { "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
@@ -749,13 +784,16 @@
         { "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
         { "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
         { "vkGetAndroidHardwareBufferPropertiesANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetAndroidHardwareBufferPropertiesANDROID) },
+        { "vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferDeviceAddress) },
         { "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
         { "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+        { "vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferOpaqueCaptureAddress) },
         { "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
         { "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
         { "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
         { "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
         { "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
+        { "vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryOpaqueCaptureAddress) },
         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
         { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
         { "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
@@ -771,6 +809,7 @@
         { "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
         { "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
         { "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
+        { "vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreCounterValue) },
         { "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
         { "vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges) },
         { "vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory) },
@@ -784,12 +823,15 @@
         { "vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool) },
         { "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
         { "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
+        { "vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(ResetQueryPool) },
         { "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+        { "vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(SignalSemaphore) },
         { "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
         { "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
         { "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
         { "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
         { "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
+        { "vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(WaitSemaphores) },
     };
     // clang-format on
     constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
@@ -965,6 +1007,10 @@
     return GetData(device).dispatch.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
 }
 
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    GetData(device).dispatch.ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
     return GetData(device).dispatch.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
 }
@@ -1481,6 +1527,34 @@
     GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
 }
 
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+    return GetData(device).dispatch.CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+    GetData(commandBuffer).dispatch.CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+    GetData(commandBuffer).dispatch.CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+    GetData(commandBuffer).dispatch.CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    return GetData(device).dispatch.GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    return GetData(device).dispatch.WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    return GetData(device).dispatch.SignalSemaphore(device, pSignalInfo);
+}
+
 VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
     return GetData(device).dispatch.GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
 }
@@ -1489,6 +1563,26 @@
     return GetData(device).dispatch.GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
 }
 
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    GetData(commandBuffer).dispatch.CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    GetData(commandBuffer).dispatch.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetBufferDeviceAddress(device, pInfo);
+}
+
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
 
 }  // anonymous namespace
 
@@ -1755,6 +1849,11 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR void vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    vulkan::api::ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR VkResult vkCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
     return vulkan::api::CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
 }
@@ -2400,6 +2499,41 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+    return vulkan::api::CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+    vulkan::api::CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+    vulkan::api::CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+    vulkan::api::CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    return vulkan::api::GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    return vulkan::api::WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    return vulkan::api::SignalSemaphore(device, pSignalInfo);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR VkResult vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
     return vulkan::api::GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
 }
@@ -2409,4 +2543,29 @@
     return vulkan::api::GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
 }
 
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    vulkan::api::CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    vulkan::api::CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return vulkan::api::GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkDeviceAddress vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return vulkan::api::GetBufferDeviceAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    return vulkan::api::GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
 // clang-format on
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 2195845..ad5cc34 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -99,6 +99,7 @@
     PFN_vkCreateQueryPool CreateQueryPool;
     PFN_vkDestroyQueryPool DestroyQueryPool;
     PFN_vkGetQueryPoolResults GetQueryPoolResults;
+    PFN_vkResetQueryPool ResetQueryPool;
     PFN_vkCreateBuffer CreateBuffer;
     PFN_vkDestroyBuffer DestroyBuffer;
     PFN_vkCreateBufferView CreateBufferView;
@@ -210,8 +211,20 @@
     PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
     PFN_vkGetDeviceQueue2 GetDeviceQueue2;
     PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
+    PFN_vkCreateRenderPass2 CreateRenderPass2;
+    PFN_vkCmdBeginRenderPass2 CmdBeginRenderPass2;
+    PFN_vkCmdNextSubpass2 CmdNextSubpass2;
+    PFN_vkCmdEndRenderPass2 CmdEndRenderPass2;
+    PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue;
+    PFN_vkWaitSemaphores WaitSemaphores;
+    PFN_vkSignalSemaphore SignalSemaphore;
     PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
     PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
+    PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount;
+    PFN_vkCmdDrawIndexedIndirectCount CmdDrawIndexedIndirectCount;
+    PFN_vkGetBufferOpaqueCaptureAddress GetBufferOpaqueCaptureAddress;
+    PFN_vkGetBufferDeviceAddress GetBufferDeviceAddress;
+    PFN_vkGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddress;
     // clang-format on
 };
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7bcb2c1..55d80fb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,20 +28,17 @@
 #include <android/dlext.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
-#include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
 #include <sys/prctl.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
+#include <vndksupport/linker.h>
 
 #include <algorithm>
 #include <array>
 #include <climits>
 #include <new>
-#include <string_view>
-#include <sstream>
 #include <vector>
 
 #include "stubhal.h"
@@ -151,19 +148,11 @@
 
 Hal Hal::hal_;
 
-void* LoadLibrary(const android_dlextinfo& dlextinfo,
-                  const std::string_view subname) {
-    ATRACE_CALL();
-
-    std::stringstream ss;
-    ss << "vulkan." << subname << ".so";
-    return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
-}
-
 const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
-    "ro.hardware." HWVULKAN_HARDWARE_MODULE_ID,
+    "ro.hardware.vulkan",
     "ro.board.platform",
 }};
+constexpr int LIB_DL_FLAGS = RTLD_LOCAL | RTLD_NOW;
 
 // LoadDriver returns:
 // * 0 when succeed, or
@@ -174,20 +163,26 @@
                const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    const android_dlextinfo dlextinfo = {
-        .flags = ANDROID_DLEXT_USE_NAMESPACE,
-        .library_namespace = library_namespace,
-    };
     void* so = nullptr;
-    char prop[PROPERTY_VALUE_MAX];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-        int prop_len = property_get(key, prop, nullptr);
-        if (prop_len > 0 && prop_len <= UINT_MAX) {
-            std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
-            so = LoadLibrary(dlextinfo, lib_name);
-            if (so)
-                break;
+        std::string lib_name = android::base::GetProperty(key, "");
+        if (lib_name.empty())
+            continue;
+
+        lib_name = "vulkan." + lib_name + ".so";
+        if (library_namespace) {
+            // load updated driver
+            const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = library_namespace,
+            };
+            so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo);
+        } else {
+            // load built-in driver
+            so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS);
         }
+        if (so)
+            break;
     }
     if (!so)
         return -ENOENT;
@@ -211,12 +206,9 @@
 int LoadBuiltinDriver(const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    auto ns = android_get_exported_namespace("sphal");
-    if (!ns)
-        return -ENOENT;
     android::GraphicsEnv::getInstance().setDriverToLoad(
         android::GpuStatsInfo::Driver::VULKAN);
-    return LoadDriver(ns, module);
+    return LoadDriver(nullptr, module);
 }
 
 int LoadUpdatedDriver(const hwvulkan_module_t** module) {
@@ -549,6 +541,7 @@
             case ProcHook::GOOGLE_display_timing:
             case ProcHook::EXTENSION_CORE_1_0:
             case ProcHook::EXTENSION_CORE_1_1:
+            case ProcHook::EXTENSION_CORE_1_2:
             case ProcHook::EXTENSION_COUNT:
                 // Device and meta extensions. If we ever get here it's a bug in
                 // our code. But enumerating them lets us avoid having a default
@@ -598,6 +591,7 @@
             case ProcHook::ANDROID_native_buffer:
             case ProcHook::EXTENSION_CORE_1_0:
             case ProcHook::EXTENSION_CORE_1_1:
+            case ProcHook::EXTENSION_CORE_1_2:
             case ProcHook::EXTENSION_COUNT:
                 // Instance and meta extensions. If we ever get here it's a bug
                 // in our code. But enumerating them lets us avoid having a
@@ -964,9 +958,7 @@
 
     // conditionally add VK_GOOGLE_display_timing if present timestamps are
     // supported by the driver:
-    const std::string timestamp_property("service.sf.present_timestamp");
-    android::base::WaitForPropertyCreation(timestamp_property);
-    if (android::base::GetBoolProperty(timestamp_property, true)) {
+    if (android::base::GetBoolProperty("service.sf.present_timestamp", false)) {
         loader_extensions.push_back({
                 VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
                 VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 43c4d14..62538c1 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -51,6 +51,7 @@
 
         EXTENSION_CORE_1_0,
         EXTENSION_CORE_1_1,
+        EXTENSION_CORE_1_2,
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
     };
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 0be66c9..df97d7f 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -12,6 +12,7 @@
     vkBindImageMemory2; # introduced=28
     vkCmdBeginQuery;
     vkCmdBeginRenderPass;
+    vkCmdBeginRenderPass2; # introduced=31
     vkCmdBindDescriptorSets;
     vkCmdBindIndexBuffer;
     vkCmdBindPipeline;
@@ -31,12 +32,16 @@
     vkCmdDraw;
     vkCmdDrawIndexed;
     vkCmdDrawIndexedIndirect;
+    vkCmdDrawIndexedIndirectCount; # introduced=31
     vkCmdDrawIndirect;
+    vkCmdDrawIndirectCount; # introduced=31
     vkCmdEndQuery;
     vkCmdEndRenderPass;
+    vkCmdEndRenderPass2; # introduced=31
     vkCmdExecuteCommands;
     vkCmdFillBuffer;
     vkCmdNextSubpass;
+    vkCmdNextSubpass2; # introduced=31
     vkCmdPipelineBarrier;
     vkCmdPushConstants;
     vkCmdResetEvent;
@@ -76,6 +81,7 @@
     vkCreatePipelineLayout;
     vkCreateQueryPool;
     vkCreateRenderPass;
+    vkCreateRenderPass2; # introduced=31
     vkCreateSampler;
     vkCreateSamplerYcbcrConversion; # introduced=28
     vkCreateSemaphore;
@@ -119,13 +125,16 @@
     vkFreeDescriptorSets;
     vkFreeMemory;
     vkGetAndroidHardwareBufferPropertiesANDROID; # introduced=28
+    vkGetBufferDeviceAddress; # introduced=31
     vkGetBufferMemoryRequirements;
     vkGetBufferMemoryRequirements2; # introduced=28
+    vkGetBufferOpaqueCaptureAddress; # introduced=31
     vkGetDescriptorSetLayoutSupport; # introduced=28
     vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
     vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
     vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
     vkGetDeviceMemoryCommitment;
+    vkGetDeviceMemoryOpaqueCaptureAddress; # introduced=31
     vkGetDeviceProcAddr;
     vkGetDeviceQueue;
     vkGetDeviceQueue2; # introduced=28
@@ -163,6 +172,7 @@
     vkGetPipelineCacheData;
     vkGetQueryPoolResults;
     vkGetRenderAreaGranularity;
+    vkGetSemaphoreCounterValue; # introduced=31
     vkGetSwapchainImagesKHR;
     vkInvalidateMappedMemoryRanges;
     vkMapMemory;
@@ -176,12 +186,15 @@
     vkResetDescriptorPool;
     vkResetEvent;
     vkResetFences;
+    vkResetQueryPool; # introduced=31
     vkSetEvent;
+    vkSignalSemaphore; # introduced=31
     vkTrimCommandPool; # introduced=28
     vkUnmapMemory;
     vkUpdateDescriptorSets;
     vkUpdateDescriptorSetWithTemplate; # introduced=28
     vkWaitForFences;
+    vkWaitSemaphores; # introduced=31
   local:
     *;
 };
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index d3ed88d..6b51817 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -258,7 +258,11 @@
     bool shared;
 
     struct Image {
-        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
+        Image()
+            : image(VK_NULL_HANDLE),
+              dequeue_fence(-1),
+              release_fence(-1),
+              dequeued(false) {}
         VkImage image;
         android::sp<ANativeWindowBuffer> buffer;
         // The fence is only valid when the buffer is dequeued, and should be
@@ -266,6 +270,10 @@
         // closed: either by closing it explicitly when queueing the buffer,
         // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
         int dequeue_fence;
+        // This fence is a dup of the sync fd returned from the driver via
+        // vkQueueSignalReleaseImageANDROID upon vkQueuePresentKHR. We must
+        // ensure it is closed upon re-presenting or releasing the image.
+        int release_fence;
         bool dequeued;
     } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
 
@@ -280,10 +288,19 @@
     return reinterpret_cast<Swapchain*>(handle);
 }
 
+static bool IsFencePending(int fd) {
+    if (fd < 0)
+        return false;
+
+    errno = 0;
+    return sync_wait(fd, 0 /* timeout */) == -1 && errno == ETIME;
+}
+
 void ReleaseSwapchainImage(VkDevice device,
                            ANativeWindow* window,
                            int release_fence,
-                           Swapchain::Image& image) {
+                           Swapchain::Image& image,
+                           bool defer_if_pending) {
     ATRACE_CALL();
 
     ALOG_ASSERT(release_fence == -1 || image.dequeued,
@@ -319,10 +336,18 @@
                 close(release_fence);
             }
         }
-
+        release_fence = -1;
         image.dequeued = false;
     }
 
+    if (defer_if_pending && IsFencePending(image.release_fence))
+        return;
+
+    if (image.release_fence >= 0) {
+        close(image.release_fence);
+        image.release_fence = -1;
+    }
+
     if (image.image) {
         ATRACE_BEGIN("DestroyImage");
         GetData(device).driver.DestroyImage(device, image.image, nullptr);
@@ -338,7 +363,8 @@
         return;
     for (uint32_t i = 0; i < swapchain->num_images; i++) {
         if (!swapchain->images[i].dequeued)
-            ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
+            ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
+                                  true);
     }
     swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
     swapchain->timing.clear();
@@ -998,7 +1024,7 @@
     }
 
     for (uint32_t i = 0; i < swapchain->num_images; i++) {
-        ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
+        ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
     }
 
     if (active) {
@@ -1630,6 +1656,9 @@
             ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
             swapchain_result = result;
         }
+        if (img.release_fence >= 0)
+            close(img.release_fence);
+        img.release_fence = fence < 0 ? -1 : dup(fence);
 
         if (swapchain.surface.swapchain_handle ==
             present_info->pSwapchains[sc]) {
@@ -1763,7 +1792,7 @@
                     WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
             }
         } else {
-            ReleaseSwapchainImage(device, nullptr, fence, img);
+            ReleaseSwapchainImage(device, nullptr, fence, img, true);
             swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
         }
 
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 4647a80..b94233b 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1123,6 +1123,14 @@
     return VK_SUCCESS;
 }
 
+VkResult CreateRenderPass2(VkDevice device,
+                           const VkRenderPassCreateInfo2*,
+                           const VkAllocationCallbacks* /*allocator*/,
+                           VkRenderPass* pRenderPass) {
+    *pRenderPass = AllocHandle<VkRenderPass>(device, HandleType::kRenderPass);
+    return VK_SUCCESS;
+}
+
 // -----------------------------------------------------------------------------
 // No-op entrypoints
 
@@ -1568,6 +1576,55 @@
 void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
 }
 
+void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+}
+
+void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+}
+
+void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return 0;
+}
+
+VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return (VkDeviceAddress)0;
+}
+
+uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return 0;
+}
+
 #pragma clang diagnostic pop
 // clang-format on
 
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index b8d7d2b..edda12c 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -67,6 +67,7 @@
     {"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
     {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
     {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
+    {"vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass2>(CmdBeginRenderPass2))},
     {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
     {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindIndexBuffer>(CmdBindIndexBuffer))},
     {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindPipeline>(CmdBindPipeline))},
@@ -86,12 +87,16 @@
     {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
     {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
     {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirect>(CmdDrawIndexedIndirect))},
+    {"vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirectCount>(CmdDrawIndexedIndirectCount))},
     {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirect>(CmdDrawIndirect))},
+    {"vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirectCount>(CmdDrawIndirectCount))},
     {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndQuery>(CmdEndQuery))},
     {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass>(CmdEndRenderPass))},
+    {"vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass2>(CmdEndRenderPass2))},
     {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdExecuteCommands>(CmdExecuteCommands))},
     {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdFillBuffer>(CmdFillBuffer))},
     {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass>(CmdNextSubpass))},
+    {"vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass2>(CmdNextSubpass2))},
     {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPipelineBarrier>(CmdPipelineBarrier))},
     {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPushConstants>(CmdPushConstants))},
     {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdResetEvent>(CmdResetEvent))},
@@ -131,6 +136,7 @@
     {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreatePipelineLayout>(CreatePipelineLayout))},
     {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
     {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
+    {"vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass2>(CreateRenderPass2))},
     {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
     {"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
     {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
@@ -172,11 +178,14 @@
     {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
     {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
     {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
+    {"vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferDeviceAddress>(GetBufferDeviceAddress))},
     {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
     {"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+    {"vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferOpaqueCaptureAddress>(GetBufferOpaqueCaptureAddress))},
     {"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
     {"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
     {"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
+    {"vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryOpaqueCaptureAddress>(GetDeviceMemoryOpaqueCaptureAddress))},
     {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
     {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
     {"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
@@ -215,6 +224,7 @@
     {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
     {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
     {"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
+    {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
     {"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
     {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
     {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
@@ -229,12 +239,15 @@
     {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetDescriptorPool>(ResetDescriptorPool))},
     {"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
     {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
+    {"vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetQueryPool>(ResetQueryPool))},
     {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+    {"vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSignalSemaphore>(SignalSemaphore))},
     {"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
     {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
     {"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
     {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
     {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
+    {"vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitSemaphores>(WaitSemaphores))},
     // clang-format on
 };
 
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 0d3f688..e59cae9 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -79,6 +79,7 @@
 VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
 VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
 VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -207,6 +208,18 @@
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
 VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
 // clang-format on
 
 }  // namespace null_driver
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index ef0719d..e9a96f3 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -25,6 +25,7 @@
 _BLOCKED_EXTENSIONS = [
     'VK_EXT_acquire_xlib_display',
     'VK_EXT_direct_mode_display',
+    'VK_EXT_directfb_surface',
     'VK_EXT_display_control',
     'VK_EXT_display_surface_counter',
     'VK_EXT_full_screen_exclusive',
@@ -302,12 +303,12 @@
   else:
     f.write('INIT_PROC(')
 
-  if name in version_dict and version_dict[name] == 'VK_VERSION_1_1':
+  if name in _OPTIONAL_COMMANDS:
     f.write('false, ')
-  elif name in _OPTIONAL_COMMANDS:
-    f.write('false, ')
-  else:
+  elif version_dict[name] == 'VK_VERSION_1_0':
     f.write('true, ')
+  else:
+    f.write('false, ')
 
   if is_instance_dispatched(name):
     f.write('instance, ')
@@ -376,7 +377,7 @@
 
   for exts in root.iter('extensions'):
     for extension in exts:
-      apiversion = ''
+      apiversion = 'VK_VERSION_1_0'
       if extension.tag == 'extension':
         extname = extension.get('name')
         for req in extension:
@@ -387,8 +388,7 @@
               cmd_name = commands.get('name')
               if cmd_name not in extension_dict:
                 extension_dict[cmd_name] = extname
-                if apiversion:
-                  version_dict[cmd_name] = apiversion
+                version_dict[cmd_name] = apiversion
 
   for feature in root.iter('feature'):
     apiversion = feature.get('name')
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index b0b466c..bfc240e 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -57,9 +57,17 @@
 
 template <typename T> struct EnumTraits;
 template <> struct EnumTraits<VkPhysicalDeviceType> {
-  static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
-  static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_PHYSICAL_DEVICE_TYPE_OTHER:
+      case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_CPU:
+        return true;
+    }
+    return false;
+  }
 };
 
 template <> struct EnumTraits<VkFormat> {
@@ -250,6 +258,40 @@
       case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
       case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
       case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+      case VK_FORMAT_G8B8G8R8_422_UNORM:
+      case VK_FORMAT_B8G8R8G8_422_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+      case VK_FORMAT_R10X6_UNORM_PACK16:
+      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
+      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+      case VK_FORMAT_R12X4_UNORM_PACK16:
+      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
+      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+      case VK_FORMAT_G16B16G16R16_422_UNORM:
+      case VK_FORMAT_B16G16R16G16_422_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
       case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
       case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
@@ -258,40 +300,22 @@
       case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
-      case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
-      case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
-      case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
-      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
-      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
-      case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
-      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
-      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
-      case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+      case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:
+      case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
         return true;
     }
     return false;
@@ -300,9 +324,14 @@
 
 template <>
 struct EnumTraits<VkPointClippingBehavior> {
-  static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
-  static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES:
+      case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY:
+        return true;
+    }
+    return false;
+  }
 };
 
 template <>
@@ -336,9 +365,26 @@
 
 template <>
 struct EnumTraits<VkDriverIdKHR> {
-  static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
-  static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_DRIVER_ID_AMD_PROPRIETARY:
+      case VK_DRIVER_ID_AMD_OPEN_SOURCE:
+      case VK_DRIVER_ID_MESA_RADV:
+      case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
+      case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
+      case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
+      case VK_DRIVER_ID_IMAGINATION_PROPRIETARY:
+      case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
+      case VK_DRIVER_ID_ARM_PROPRIETARY:
+      case VK_DRIVER_ID_GOOGLE_SWIFTSHADER:
+      case VK_DRIVER_ID_GGP_PROPRIETARY:
+      case VK_DRIVER_ID_BROADCOM_PROPRIETARY:
+      case VK_DRIVER_ID_MESA_LLVMPIPE:
+      case VK_DRIVER_ID_MOLTENVK:
+        return true;
+    }
+    return false;
+  }
 };
 
 // VkSparseImageFormatProperties
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 84cfe5e..73586d4 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -165,7 +165,9 @@
 
   VkFormatProperties format_properties = {};
   for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
-       format <= VK_FORMAT_END_RANGE;
+       // TODO(http://b/171403054): avoid hard-coding last value in the
+       // contiguous range
+       format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
        format = static_cast<VkFormat>(format + 1)) {
     vkGetPhysicalDeviceFormatProperties(physical_device, format,
                                         &format_properties);
@@ -178,6 +180,8 @@
 
   if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
     for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+         // TODO(http://b/171403054): avoid hard-coding last value in the
+         // contiguous range
          format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
          format = static_cast<VkFormat>(format + 1)) {
       vkGetPhysicalDeviceFormatProperties(physical_device, format,