[automerger skipped] Check if the window is partially obscured for slippery enters am: 6e689ffe3f am: 224d576c0b am: e26b6061f8 -s ours am: eb59e4756d -s ours am: 1140211821 -s ours

am skip reason: Merged-In I93d9681479f41244ffed4b1f88cceb69be71adf2 with SHA-1 d8c6ef2138 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/16185286

Change-Id: I99b3e2cf96520e8d2e7ee37314e37c20ea6af53e
diff --git a/.clang-format b/.clang-format
index 03af56d..6725a1f 100644
--- a/.clang-format
+++ b/.clang-format
@@ -11,3 +11,4 @@
 IndentWidth: 4
 PenaltyBreakBeforeFirstCallParameter: 100000
 SpacesBeforeTrailingComments: 1
+IncludeBlocks: Preserve
diff --git a/.gitignore b/.gitignore
index 0d20b64..ed653c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,5 @@
+*.iml
 *.pyc
+.idea/
+.vscode/
+*.code-workspace
diff --git a/Android.bp b/Android.bp
index 9829c7f..dec6716 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,41 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+//
+// large-scale-change filtered out the below license kinds as false-positives:
+//   SPDX-license-identifier-LGPL
+//   SPDX-license-identifier-LGPL-2.1
+//   SPDX-license-identifier-LGPL-3.0
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+        "SPDX-license-identifier-BSD",
+        "SPDX-license-identifier-MIT",
+        "SPDX-license-identifier-Unicode-DFS",
+        "legacy_notice",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 ndk_headers {
     name: "libandroid_headers",
     from: "include/android",
@@ -43,3 +81,14 @@
         ":framework_native_aidl_gui",
     ],
 }
+
+cc_library_headers{
+    name: "libandroid_headers_private",
+    export_include_dirs: ["include/private"],
+}
+
+filegroup {
+    name: "deviceproductinfoconstants_aidl",
+    srcs: ["aidl/android/hardware/display/IDeviceProductInfoConstants.aidl"],
+    path: "aidl",
+}
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..8bcb1e5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,20 +5,25 @@
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/idlcli/
+               cmds/servicemanager/
                include/input/
+               include/powermanager/
                libs/binder/fuzzer/
-               libs/binder/ndk/
+               libs/binder/
                libs/binderthreadstate/
                libs/graphicsenv/
                libs/gui/
                libs/input/
+               libs/nativedisplay/
                libs/renderengine/
                libs/ui/
                libs/vr/
                opengl/libs/
                services/bufferhub/
                services/inputflinger/
+               services/powermanager/
                services/surfaceflinger/
+               services/vibratorservice/
                services/vr/
                vulkan/
 
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8173c89..4b64203 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -53,11 +53,19 @@
         },
         {
           "include-filter": "*RelativeZTest.*"
+        },
+        {
+          "include-filter": "*RefreshRateOverlayTest.*"
         }
       ]
     },
     {
-      "name": "libsurfaceflinger_unittest"
+      "name": "CtsGraphicsTestCases",
+      "options": [
+        {
+          "include-filter": "android.graphics.cts.VulkanPreTransformTest"
+        }
+      ]
     }
   ]
 }
diff --git a/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl b/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl
new file mode 100644
index 0000000..7cc272a
--- /dev/null
+++ b/aidl/android/hardware/display/IDeviceProductInfoConstants.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+/** @hide */
+interface IDeviceProductInfoConstants {
+    /** The device connection to the display sink is unknown. */
+    const int CONNECTION_TO_SINK_UNKNOWN = 0;
+
+    /** The device is built-in in the display sink. */
+    const int CONNECTION_TO_SINK_BUILT_IN = 1;
+
+    /** The device is directly connected to the display sink. */
+    const int CONNECTION_TO_SINK_DIRECT = 2;
+
+    /** The device is transitively connected to the display sink. */
+    const int CONNECTION_TO_SINK_TRANSITIVE = 3;
+}
\ No newline at end of file
diff --git a/aidl/gui/android/view/LayerMetadataKey.aidl b/aidl/gui/android/view/LayerMetadataKey.aidl
index 7026ca8..d6ca3db 100644
--- a/aidl/gui/android/view/LayerMetadataKey.aidl
+++ b/aidl/gui/android/view/LayerMetadataKey.aidl
@@ -23,4 +23,8 @@
     METADATA_WINDOW_TYPE = 2,
     METADATA_TASK_ID = 3,
     METADATA_MOUSE_CURSOR = 4,
+    METADATA_ACCESSIBILITY_ID = 5,
+    METADATA_OWNER_PID = 6,
+    METADATA_DEQUEUE_TIME = 7,
+    METADATA_GAME_MODE = 8,
 }
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/Android.bp b/cmds/atrace/Android.bp
index e7d0ad0..aa0ef25 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2012 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_atrace_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_atrace_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "atrace",
     srcs: ["atrace.cpp"],
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 28fdaa4..783a475 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -62,7 +62,7 @@
 
 using std::string;
 
-#define MAX_SYS_FILES 11
+#define MAX_SYS_FILES 12
 
 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
 const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -99,7 +99,9 @@
 
 /* Tracing categories */
 static const TracingCategory k_categories[] = {
-    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, { } },
+    { "gfx",        "Graphics",                 ATRACE_TAG_GRAPHICS, {
+        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
+    } },
     { "input",      "Input",                    ATRACE_TAG_INPUT, { } },
     { "view",       "View System",              ATRACE_TAG_VIEW, { } },
     { "webview",    "WebView",                  ATRACE_TAG_WEBVIEW, { } },
@@ -172,6 +174,9 @@
         { 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" },
+        { OPT,      "events/cpuhp/cpuhp_pause/enable" },
     } },
     { "membus",     "Memory Bus Utilization", 0, {
         { REQ,      "events/memory_bus/enable" },
@@ -238,6 +243,11 @@
         { OPT,      "events/kmem/ion_heap_grow/enable" },
         { OPT,      "events/kmem/ion_heap_shrink/enable" },
         { OPT,      "events/ion/ion_stat/enable" },
+        { OPT,      "events/gpu_mem/gpu_mem_total/enable" },
+    } },
+    { "thermal",  "Thermal event", 0, {
+        { REQ,      "events/thermal/thermal_temperature/enable" },
+        { OPT,      "events/thermal/cdev_update/enable" },
     } },
 };
 
@@ -312,9 +322,6 @@
 static const char* k_funcgraphProcPath =
     "options/funcgraph-proc";
 
-static const char* k_funcgraphFlatPath =
-    "options/funcgraph-flat";
-
 static const char* k_ftraceFilterPath =
     "set_ftrace_filter";
 
@@ -692,7 +699,6 @@
         ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
         ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
         ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
-        ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
 
         // Set the requested filter functions.
         ok &= truncateFile(k_ftraceFilterPath);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f442dae..e3c4ede 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -37,16 +37,28 @@
     chmod 0666 /sys/kernel/tracing/events/sched/sched_process_exit/enable
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_waking/enable
     chmod 0666 /sys/kernel/tracing/events/sched/sched_waking/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/enable
+    chmod 0666 /sys/kernel/tracing/events/sched/sched_wakeup_new/enable
     chmod 0666 /sys/kernel/debug/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/tracing/events/cgroup/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
     chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
     chmod 0666 /sys/kernel/tracing/events/power/cpu_idle/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/clock_enable/enable
+    chmod 0666 /sys/kernel/tracing/events/power/clock_enable/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/power/clock_disable/enable
+    chmod 0666 /sys/kernel/tracing/events/power/clock_disable/enable
     chmod 0666 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
     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/cpuhp/cpuhp_pause/enable
+    chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/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
@@ -75,6 +87,8 @@
     chmod 0666 /sys/kernel/tracing/events/binder/binder_locked/enable
     chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
     chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_set_priority/enable
+    chmod 0666 /sys/kernel/tracing/events/binder/binder_set_priority/enable
     chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable
     chmod 0666 /sys/kernel/tracing/events/i2c/enable
     chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
@@ -121,12 +135,48 @@
     chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
     chmod 0666 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/enable
     chmod 0666 /sys/kernel/tracing/events/oom/oom_score_adj_update/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/oom/mark_victim/enable
+    chmod 0666 /sys/kernel/tracing/events/oom/mark_victim/enable
     chmod 0666 /sys/kernel/debug/tracing/events/task/task_rename/enable
     chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable
     chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable
     chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
     chmod 0666 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total/enable
     chmod 0666 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_raise/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_raise/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_raise/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_raise/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_enable/enable
+    chmod 0666 /sys/kernel/tracing/events/clk/clk_disable/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_disable/enable
+    chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable
+    chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
@@ -166,6 +216,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 +266,78 @@
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
 
+# Only create the tracing instance if persist.mm_events.enabled
+# Attempting to remove the tracing instance after it has been created
+# will likely fail with EBUSY as it would be in use by traced_probes.
+on post-fs-data && property:persist.mm_events.enabled=true
+# 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
+
+# Set the default buffer size to the minimum
+    write /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb 1
+    write /sys/kernel/tracing/instances/mm_events/buffer_size_kb 1
+
+# 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
+
+# Tracing disabled by default
+    write /sys/kernel/debug/tracing/instances/mm_events/tracing_on 0
+    write /sys/kernel/tracing/instances/mm_events/tracing_on 0
+
+# 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/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 6c86c21..9186514 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -18,8 +18,3 @@
     chmod 0666 /sys/kernel/tracing/events/filemap/enable
     chmod 0666 /sys/kernel/debug/tracing/events/filemap/enable
 
-    # irq
-    chmod 0666 /sys/kernel/tracing/events/irq/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
-    chmod 0666 /sys/kernel/tracing/events/ipi/enable
-    chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
index 24044a6..8262aed 100644
--- a/cmds/bugreport/Android.bp
+++ b/cmds/bugreport/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "bugreport",
     srcs: ["bugreport.cpp"],
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 1ba7cff..5f56531 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,6 +1,5 @@
 set noparent
 
-felipeal@google.com
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
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/Android.bp b/cmds/bugreportz/Android.bp
index 924a3a3..332f858 100644
--- a/cmds/bugreportz/Android.bp
+++ b/cmds/bugreportz/Android.bp
@@ -1,5 +1,14 @@
 // bugreportz
 // ==========
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "bugreportz",
 
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 1ba7cff..5f56531 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,6 +1,5 @@
 set noparent
 
-felipeal@google.com
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
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/cmd/Android.bp b/cmds/cmd/Android.bp
index 8ea71cd..c900a24 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_cmd_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_library_static {
     name: "libcmd",
 
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index acca11a..aff32c3 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -13,6 +13,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "dumpstate_cflag_defaults",
     cflags: [
@@ -90,6 +99,7 @@
         "libhidlbase",
         "liblog",
         "libutils",
+        "libbinderdebug",
     ],
     srcs: [
         "DumpstateService.cpp",
@@ -105,34 +115,28 @@
     name: "dumpstate",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "DumpPool.cpp",
+        "TaskQueue.cpp",
         "dumpstate.cpp",
         "main.cpp",
     ],
     required: [
         "atrace",
-        "df",
-        "getprop",
+        "dmabuf_dump",
         "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 +145,8 @@
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "DumpPool.cpp",
+        "TaskQueue.cpp",
         "dumpstate.cpp",
         "tests/dumpstate_test.cpp",
     ],
@@ -157,10 +163,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..c2c8a72
--- /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;
+    }
+    futures_map_.clear();
+    while (!tasks_.empty()) tasks_.pop();
+
+    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/OWNERS b/cmds/dumpstate/OWNERS
index 1ba7cff..5f56531 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,6 +1,5 @@
 set noparent
 
-felipeal@google.com
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
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..2d11b90 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,8 @@
 #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"
+#define CGROUPFS_DIR "/sys/fs/cgroup"
 
 // TODO(narayan): Since this information has to be kept in sync
 // with tombstoned, we should just put it in a common header.
@@ -195,8 +202,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 +339,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 +699,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()) {
 }
 
@@ -743,6 +794,9 @@
     if (module_metadata_version != 0) {
         printf("Module Metadata version: %" PRId64 "\n", module_metadata_version);
     }
+    printf("SDK extension versions [r=%s s=%s]\n",
+           android::base::GetProperty("build.version.extensions.r", "-").c_str(),
+           android::base::GetProperty("build.version.extensions.s", "-").c_str());
 
     printf("Kernel: ");
     DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
@@ -751,8 +805,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 +1037,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 +1051,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() {
@@ -1138,10 +1212,6 @@
 
 static void DumpPacketStats() {
     DumpFile("NETWORK DEV INFO", "/proc/net/dev");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
-    DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
-    DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
-    DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 }
 
 static void DumpIpAddrAndRules() {
@@ -1171,8 +1241,15 @@
         if (status == OK) {
             dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
             std::chrono::duration<double> elapsed_seconds;
-            status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
-                                       /* as_proto = */ false, elapsed_seconds, bytes_written);
+            if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+                service == String16("meminfo")) {
+                // Use a longer timeout for meminfo, since 30s is not always enough.
+                status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
+            } else {
+                status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
+            }
             dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
             bool dump_complete = (status == OK);
             dumpsys.stopDumpThread(dump_complete);
@@ -1294,15 +1371,21 @@
                            /* 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(),
+                   false, out_fd);
         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 +1407,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 +1422,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 +1501,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 +1519,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 +1593,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 +1636,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"});
@@ -1479,10 +1649,13 @@
         MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
     } else {
         RunCommand("LSMOD", {"lsmod"});
+        RunCommand("MODULES INFO",
+                   {"sh", "-c", "cat /proc/modules | cut -d' ' -f1 | "
+                    "    while read MOD ; do echo modinfo:$MOD ; modinfo $MOD ; "
+                    "done"}, CommandOptions::AS_ROOT);
     }
 
-    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();
@@ -1495,8 +1668,8 @@
     for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
     for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
 
-    /* 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 +1678,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(),
@@ -1529,6 +1704,12 @@
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);
 
+    // The dump mechanism in connectivity is refactored due to modularization work. Connectivity can
+    // only register with a default priority(NORMAL priority). Dumpstate has to call connectivity
+    // dump with priority parameters to dump high priority information.
+    RunDumpsys("SERVICE HIGH connectivity", {"connectivity", "--dump-priority", "HIGH"},
+                   CommandOptions::WithTimeout(10).Build());
+
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
     RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
@@ -1552,7 +1733,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 +1759,16 @@
 
     RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
 
-    printf("========================================================\n");
-    printf("== Checkins\n");
-    printf("========================================================\n");
+    /* Dump Bluetooth HCI logs after getting bluetooth_manager dumpsys */
+    ds.AddDir("/data/misc/bluetooth/logs", true);
 
-    RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+    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);
+    }
 
-    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 +1793,15 @@
     // Add linker configuration directory
     ds.AddDir(LINKERCONFIG_DIR, true);
 
-    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
+    /* Dump cgroupfs */
+    ds.AddDir(CGROUPFS_DIR, true);
+
+    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 +1822,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());
@@ -1704,15 +1867,22 @@
     RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
 
     // Gather shared memory buffer info if the product implements it
-    struct stat st;
-    if (!stat("/product/bin/dmabuf_dump", &st)) {
-        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
-    }
+    RunCommand("Dmabuf dump", {"dmabuf_dump"});
+    RunCommand("Dmabuf per-buffer/per-exporter/per-device stats", {"dmabuf_dump", "-b"});
 
     DumpFile("PSI cpu", "/proc/pressure/cpu");
     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 +1894,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 +1950,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) {
@@ -1788,6 +1981,8 @@
 
     RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"vcn_management"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
     if (include_sensitive_info) {
         // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
         RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
@@ -1848,12 +2043,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,9 +2083,7 @@
 }
 
 Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
-    DurationReporter duration_reporter("DUMP TRACES");
-
-    const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
+    const std::string temp_file_pattern = ds.bugreport_internal_dir_ + "/dumptrace_XXXXXX";
     const size_t buf_size = temp_file_pattern.length() + 1;
     std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
     memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
@@ -1980,17 +2190,31 @@
     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 with ro.product.debugfs_restrictions.enabled
+     * set to true 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 mount_debugfs =
+        android::base::GetBoolProperty("ro.product.debugfs_restrictions.enabled", false);
+    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 +2314,13 @@
                "there might be racing in content\n", killing_timeout_sec);
     }
 
+    if (mount_debugfs) {
+        auto keep_debugfs_mounted =
+            android::base::GetProperty("persist.dbg.keep_debugfs_mounted", "");
+        if (keep_debugfs_mounted.empty())
+            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 +2341,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 +2371,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());
@@ -2207,7 +2442,9 @@
 
 static void Vibrate(int duration_ms) {
     // clang-format off
-    RunCommand("", {"cmd", "vibrator", "vibrate", "-f", std::to_string(duration_ms), "dumpstate"},
+    std::vector<std::string> args = {"cmd", "vibrator_manager", "synced", "-f", "-d", "dumpstate",
+                                     "oneshot", std::to_string(duration_ms)};
+    RunCommand("", args,
                CommandOptions::WithTimeout(10)
                    .Log("Vibrate: '%s'\n")
                    .Always()
@@ -2224,21 +2461,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 +2498,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 +2516,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 +2527,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 +2573,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 +2584,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 +2597,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 +2607,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 +2622,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 +2635,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 +2677,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 +2737,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 +2760,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 +2810,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 +2824,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 +2835,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 +2876,83 @@
         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();
 
+        // If a winscope trace is running, snapshot it now. It will be pulled into bugreport later
+        // from WMTRACE_DATA_DIR.
+        MaybeSnapshotWinTrace();
+    }
+    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 +2964,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 +3010,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 +3034,45 @@
     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::MaybeSnapshotWinTrace() {
+    // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol.
+    for (const auto& service : {"window", "input_method"}) {
+        RunCommand(
+            // Empty name because it's not intended to be classified as a bugreport section.
+            // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
+            "", {"cmd", service, "tracing", "save-for-bugreport"},
+            CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+    }
+}
+
+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();
     }
 }
 
@@ -2869,6 +3109,45 @@
     android::os::UnlinkAndLogOnError(tmp_path_);
     android::os::UnlinkAndLogOnError(screenshot_path_);
     android::os::UnlinkAndLogOnError(path_);
+    if (dump_traces_path != nullptr) {
+        android::os::UnlinkAndLogOnError(dump_traces_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() {
@@ -2927,6 +3206,11 @@
         // Since we do not have user consent to share the bugreport it does not get
         // copied over to the calling app but remains in the internal directory from
         // where the user can manually pull it.
+        std::string final_path = GetPath(".zip");
+        bool copy_succeeded = android::os::CopyFileToFile(path_, final_path);
+        if (copy_succeeded) {
+            android::os::UnlinkAndLogOnError(path_);
+        }
         return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
     }
     // Unknown result; must be a programming error.
@@ -2981,7 +3265,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 +3274,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 +3290,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 +3877,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 +3893,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 +3935,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 +4007,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..83e6787 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,10 @@
     RunStatus DumpstateDefaultAfterCritical();
 
     void MaybeTakeEarlyScreenshot();
+    void MaybeSnapshotSystemTrace();
+    void MaybeSnapshotWinTrace();
 
-    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 +559,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 +604,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/cmds/dumpstate/dumpstate_smoke_test.xml b/cmds/dumpstate/dumpstate_smoke_test.xml
new file mode 100644
index 0000000..0aff200
--- /dev/null
+++ b/cmds/dumpstate/dumpstate_smoke_test.xml
@@ -0,0 +1,31 @@
+<?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="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="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/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..0712c0a 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) {
@@ -388,7 +411,6 @@
 }
 
 TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
-    SectionExists("HIGH connectivity", /* bytes= */ 3000);
     SectionExists("connectivity", /* bytes= */ 5000);
 }
 
@@ -400,10 +422,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..db508b5 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 LimitedOnly report redirected to a file, open it and verify entry exist.
+TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) {
+    std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip";
+    android::base::unique_fd out_fd;
+    CreateFd(out_path, &out_fd);
+    ds_.options_->limited_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-.+(-[[:digit:]]+){6}\\.txt)"));
+    VerifyEntry(handle_, bugreport_txt_name, &entry);
+}
+
 class DumpstateServiceTest : public DumpstateBaseTest {
   public:
     DumpstateService dss;
@@ -1618,6 +1666,175 @@
     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));
+}
+
+TEST_F(DumpPoolTest, Shutdown_withoutCrash) {
+    bool run_1 = false;
+    auto dump_func_1 = [&]() {
+        run_1 = true;
+    };
+    auto dump_func = []() {
+        sleep(1);
+    };
+
+    dump_pool_->start(/* thread_counts = */1);
+    dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
+    dump_pool_->enqueueTask(/* task_name = */"2", dump_func);
+    dump_pool_->enqueueTask(/* task_name = */"3", dump_func);
+    dump_pool_->enqueueTask(/* task_name = */"4", dump_func);
+    dump_pool_->waitForTask("1", "", out_fd_.get());
+    dump_pool_->shutdown();
+
+    EXPECT_TRUE(run_1);
+    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/Android.bp b/cmds/dumpsys/Android.bp
index f99588f..6ab6b7f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_dumpsys_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_defaults {
     name: "dumpsys_defaults",
 
@@ -15,6 +32,7 @@
         "libutils",
         "liblog",
         "libbinder",
+        "libbinderdebug",
     ],
 
     static_libs: [
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 1ba7cff..97a63ca 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,6 +1,8 @@
 set noparent
 
-felipeal@google.com
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
-enh@google.com
+
+# for ServiceManager mock
+per-file dumpsys_test.cpp=smoreland@google.com
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index a427c8d..ba1c449 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -25,6 +25,7 @@
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/TextOutput.h>
+#include <binderdebug/BinderDebug.h>
 #include <serviceutils/PriorityDumper.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
@@ -60,13 +61,15 @@
             "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--help | -l | --skip SERVICES "
+            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | "
+            "--skip SERVICES "
             "| SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
             "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
             "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
             "         --pid: dump PID instead of usual dump\n"
+            "         --thread: dump thread usage instead of usual dump\n"
             "         --proto: filter services that support dumping data in proto format. Dumps\n"
             "               will be in proto format.\n"
             "         --priority LEVEL: filter services based on specified priority\n"
@@ -125,7 +128,8 @@
     Type type = Type::DUMP;
     int timeoutArgMs = 10000;
     int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
-    static struct option longOptions[] = {{"pid", no_argument, 0, 0},
+    static struct option longOptions[] = {{"thread", no_argument, 0, 0},
+                                          {"pid", no_argument, 0, 0},
                                           {"priority", required_argument, 0, 0},
                                           {"proto", no_argument, 0, 0},
                                           {"skip", no_argument, 0, 0},
@@ -163,6 +167,8 @@
                 }
             } else if (!strcmp(longOptions[optionIndex].name, "pid")) {
                 type = Type::PID;
+            } else if (!strcmp(longOptions[optionIndex].name, "thread")) {
+                type = Type::THREAD;
             }
             break;
 
@@ -230,7 +236,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;
 
@@ -329,6 +335,23 @@
      return OK;
 }
 
+static status_t dumpThreadsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+    pid_t pid;
+    status_t status = service->getDebugPid(&pid);
+    if (status != OK) {
+        return status;
+    }
+    BinderPidInfo pidInfo;
+    status = getBinderPidInfo(BinderDebugContext::BINDER, pid, &pidInfo);
+    if (status != OK) {
+        return status;
+    }
+    WriteStringToFd("Threads in use: " + std::to_string(pidInfo.threadUsage) + "/" +
+                        std::to_string(pidInfo.threadCount) + "\n",
+                    fd.get());
+    return OK;
+}
+
 status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
                                   const Vector<String16>& args) {
     sp<IBinder> service = sm_->checkService(serviceName);
@@ -359,6 +382,9 @@
         case Type::PID:
             err = dumpPidToFd(service, remote_end);
             break;
+        case Type::THREAD:
+            err = dumpThreadsToFd(service, remote_end);
+            break;
         default:
             std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
             return;
@@ -427,7 +453,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/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 929c55c..349947c 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -52,13 +52,14 @@
     static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
 
     enum class Type {
-        DUMP,  // dump using `dump` function
-        PID,   // dump pid of server only
+        DUMP,    // dump using `dump` function
+        PID,     // dump pid of server only
+        THREAD,  // dump thread usage of server only
     };
 
     /**
      * Starts a thread to connect to a service and get its dump output. The thread redirects
-     * the output to a pipe. Thread must be stopped by a subsequent callto {@code
+     * the output to a pipe. Thread must be stopped by a subsequent call to {@code
      * stopDumpThread}.
      * @param serviceName
      * @param args list of arguments to pass to service dump method.
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
index e182b9d..58fec30 100644
--- a/cmds/dumpsys/tests/Android.bp
+++ b/cmds/dumpsys/tests/Android.bp
@@ -1,4 +1,13 @@
 // Build the unit tests for dumpsys
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_cmds_dumpsys_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_cmds_dumpsys_license"],
+}
+
 cc_test {
     name: "dumpsys_test",
     test_suites: ["device-tests"],
@@ -10,6 +19,7 @@
         "libbase",
         "libbinder",
         "libutils",
+        "libbinderdebug",
     ],
 
     static_libs: [
@@ -17,6 +27,4 @@
         "libgmock",
         "libserviceutils",
     ],
-
-    clang: true,
 }
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
index 1a8c67f..c2351d9 100644
--- a/cmds/dumpsys/tests/AndroidTest.xml
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -23,4 +23,4 @@
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="dumpsys_test" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index b9395ba..c9d2dbb 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -16,12 +16,15 @@
 
 #include "../dumpsys.h"
 
+#include <regex>
 #include <vector>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <android-base/file.h>
+#include <binder/Binder.h>
+#include <binder/ProcessState.h>
 #include <serviceutils/PriorityDumper.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
@@ -55,6 +58,8 @@
     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&));
+    MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
@@ -206,10 +211,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");
         }
@@ -224,6 +226,10 @@
         EXPECT_THAT(stdout_, HasSubstr(expected));
     }
 
+    void AssertOutputFormat(const std::string format) {
+        EXPECT_THAT(stdout_, testing::MatchesRegex(format));
+    }
+
     void AssertDumped(const std::string& service, const std::string& dump) {
         EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
         EXPECT_THAT(stdout_, HasSubstr("was the duration of dumpsys " + service + ", ending at: "));
@@ -263,6 +269,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"});
@@ -561,6 +582,30 @@
     AssertOutput(std::to_string(getpid()) + "\n");
 }
 
+// Tests 'dumpsys --thread'
+TEST_F(DumpsysTest, ListAllServicesWithThread) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"--thread"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+
+    const std::string format("(.|\n)*((Threads in use: [0-9]+/[0-9]+)?\n-(.|\n)*){2}");
+    AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --thread service_name'
+TEST_F(DumpsysTest, ListServiceWithThread) {
+    ExpectCheckService("Locksmith");
+
+    CallMain({"--thread", "Locksmith"});
+    // returns an empty string without root enabled
+    const std::string format("(^$|Threads in use: [0-9]/[0-9]+\n)");
+    AssertOutputFormat(format);
+}
+
 TEST_F(DumpsysTest, GetBytesWritten) {
     const char* serviceName = "service2";
     const char* dumpContents = "dump1";
@@ -586,3 +631,13 @@
                         /* as_proto = */ false, elapsedDuration, bytesWritten);
     EXPECT_THAT(status, Eq(INVALID_OPERATION));
 }
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // start a binder thread pool for testing --thread option
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+    ProcessState::self()->startThreadPool();
+
+    return RUN_ALL_TESTS();
+}
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index 7aa111c..754a99c 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -11,6 +11,9 @@
 LOCAL_CFLAGS := -Wall -Werror
 
 LOCAL_MODULE:= flatland
+LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS:= notice
+LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../../NOTICE
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 3a3df08..01f7d30 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -19,7 +19,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 namespace android {
 
@@ -227,15 +227,15 @@
         return false;
     }
 
-    DisplayConfig config;
-    status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config);
+    ui::DisplayMode mode;
+    status_t err = mSurfaceComposerClient->getActiveDisplayMode(dpy, &mode);
     if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err);
+        fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
         return false;
     }
 
-    float scaleX = static_cast<float>(config.resolution.getWidth()) / w;
-    float scaleY = static_cast<float>(config.resolution.getHeight()) / h;
+    float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
+    float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
     *scale = scaleX < scaleY ? scaleX : scaleY;
 
     return true;
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 402767a..ec3bc61 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -12,10 +12,19 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
-        "android.hardware.vibrator-ndk_platform",
+        "android.hardware.vibrator-V2-ndk_platform",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
@@ -37,10 +46,25 @@
     defaults: ["idlcli-defaults"],
     srcs: [
         "CommandVibrator.cpp",
+        "vibrator/CommandAlwaysOnDisable.cpp",
+        "vibrator/CommandAlwaysOnEnable.cpp",
         "vibrator/CommandCompose.cpp",
+        "vibrator/CommandComposePwle.cpp",
+        "vibrator/CommandGetBandwidthAmplitudeMap.cpp",
         "vibrator/CommandGetCapabilities.cpp",
         "vibrator/CommandGetCompositionDelayMax.cpp",
         "vibrator/CommandGetCompositionSizeMax.cpp",
+        "vibrator/CommandGetFrequencyMinimum.cpp",
+        "vibrator/CommandGetFrequencyResolution.cpp",
+        "vibrator/CommandGetPrimitiveDuration.cpp",
+        "vibrator/CommandGetPwleCompositionSizeMax.cpp",
+        "vibrator/CommandGetPwlePrimitiveDurationMax.cpp",
+        "vibrator/CommandGetQFactor.cpp",
+        "vibrator/CommandGetResonantFrequency.cpp",
+        "vibrator/CommandGetSupportedAlwaysOnEffects.cpp",
+        "vibrator/CommandGetSupportedBraking.cpp",
+        "vibrator/CommandGetSupportedEffects.cpp",
+        "vibrator/CommandGetSupportedPrimitives.cpp",
         "vibrator/CommandOff.cpp",
         "vibrator/CommandOn.cpp",
         "vibrator/CommandPerform.cpp",
diff --git a/cmds/idlcli/CommandVibrator.cpp b/cmds/idlcli/CommandVibrator.cpp
index a7a70c3..81bdbe2 100644
--- a/cmds/idlcli/CommandVibrator.cpp
+++ b/cmds/idlcli/CommandVibrator.cpp
@@ -22,7 +22,7 @@
 class IdlCli;
 
 class CommandVibrator : public CommandWithSubcommands<CommandVibrator> {
-    std::string getDescription() const override { return "Invoke Vibrator HIDL APIs."; }
+    std::string getDescription() const override { return "Invoke Vibrator IDL APIs."; }
 
     std::string getUsageSummary() const override { return "<api> [arguments]"; }
 
diff --git a/cmds/idlcli/IdlCli.h b/cmds/idlcli/IdlCli.h
index dd84304..24a40d9 100644
--- a/cmds/idlcli/IdlCli.h
+++ b/cmds/idlcli/IdlCli.h
@@ -25,14 +25,47 @@
 class IdlCli : public CommandWithSubcommands<IdlCli> {
     std::string getDescription() const override { return "Invoke IDL APIs."; }
 
-    std::string getUsageSummary() const override { return "<idl> [arguments]"; }
+    std::string getUsageSummary() const override { return "<idl> [options] [arguments]"; }
 
     UsageDetails getUsageDetails() const override {
         UsageDetails details{
+                {"-n <name>", {"Get named service, rather than default."}},
                 {"<idl>", CommandRegistry<IdlCli>::List()},
         };
         return details;
     }
+
+    Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-n") {
+                if (auto name = args.pop<decltype(mName)>()) {
+                    mName = *name;
+                } else {
+                    std::cerr << "Missing Value for Name!" << std::endl;
+                    return USAGE;
+                }
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
+        return CommandWithSubcommands::doArgs(args);
+    }
+
+    IdlCli() {}
+
+    std::string mName;
+
+public:
+    static IdlCli &Get() {
+        static IdlCli instance;
+        return instance;
+    }
+
+    auto getName() { return mName; }
 };
 
 } // namespace idlcli
diff --git a/cmds/idlcli/main.cpp b/cmds/idlcli/main.cpp
index 9ed9d82..308f294 100644
--- a/cmds/idlcli/main.cpp
+++ b/cmds/idlcli/main.cpp
@@ -19,5 +19,5 @@
 
 int main(const int argc, const char* const argv[]) {
     using namespace ::android::idlcli;
-    return IdlCli{}.main(Args{argc, argv});
+    return IdlCli::Get().main(Args{argc, argv});
 }
diff --git a/cmds/idlcli/utils.h b/cmds/idlcli/utils.h
index a8e5954..262f2e5 100644
--- a/cmds/idlcli/utils.h
+++ b/cmds/idlcli/utils.h
@@ -17,6 +17,7 @@
 #ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_
 #define FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_
 
+#include <android/binder_enums.h>
 #include <hidl/HidlSupport.h>
 
 #include <iomanip>
@@ -66,7 +67,7 @@
 
 } // namespace overrides
 
-template <typename T, typename R = hardware::hidl_enum_range<T>>
+template <typename T, typename R = ndk::enum_range<T>>
 inline std::istream &operator>>(std::istream &stream, T &out) {
     using overrides::operator>>;
     auto validRange = R();
@@ -248,7 +249,7 @@
 
 template <typename T>
 class CommandWithSubcommands : public Command {
-private:
+protected:
     Status doArgs(Args &args) override {
         mCommand = CommandRegistry<T>::Create(*args.get());
         if (!mCommand) {
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index ca5142d..dfbb886 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -13,20 +13,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
-#define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
+#pragma once
 
+#include <future>
+
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
 #include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <aidl/android/hardware/vibrator/IVibratorManager.h>
 #include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
 
+#include "IdlCli.h"
 #include "utils.h"
 
-#include "log/log.h"
-
 namespace android {
 
 using hardware::Return;
+using idlcli::IdlCli;
 
 static constexpr int NUM_TRIES = 2;
 
@@ -43,20 +47,34 @@
 }
 
 template <typename I>
-inline auto getService() {
-    return I::getService();
+inline auto getService(std::string name) {
+    const auto instance = std::string() + I::descriptor + "/" + name;
+    auto vibBinder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
+    return I::fromBinder(vibBinder);
 }
 
 template <>
-inline auto getService<aidl::android::hardware::vibrator::IVibrator>() {
-    const auto instance =
-            std::string() + aidl::android::hardware::vibrator::IVibrator::descriptor + "/default";
-    auto vibBinder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
-    return aidl::android::hardware::vibrator::IVibrator::fromBinder(vibBinder);
+inline auto getService<android::hardware::vibrator::V1_0::IVibrator>(std::string name) {
+    return android::hardware::vibrator::V1_0::IVibrator::getService(name);
+}
+
+template <>
+inline auto getService<android::hardware::vibrator::V1_1::IVibrator>(std::string name) {
+    return android::hardware::vibrator::V1_1::IVibrator::getService(name);
+}
+
+template <>
+inline auto getService<android::hardware::vibrator::V1_2::IVibrator>(std::string name) {
+    return android::hardware::vibrator::V1_2::IVibrator::getService(name);
+}
+
+template <>
+inline auto getService<android::hardware::vibrator::V1_3::IVibrator>(std::string name) {
+    return android::hardware::vibrator::V1_3::IVibrator::getService(name);
 }
 
 template <typename I>
-using shared_ptr = std::result_of_t<decltype(getService<I>)&()>;
+using shared_ptr = std::result_of_t<decltype(getService<I>)&(std::string)>;
 
 template <typename I>
 class HalWrapper {
@@ -64,7 +82,8 @@
     static std::unique_ptr<HalWrapper> Create() {
         // Assume that if getService returns a nullptr, HAL is not available on the
         // device.
-        auto hal = getService<I>();
+        const auto name = IdlCli::Get().getName();
+        auto hal = getService<I>(name.empty() ? "default" : name);
         return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
     }
 
@@ -101,9 +120,19 @@
 namespace V1_3 = ::android::hardware::vibrator::V1_3;
 namespace aidl = ::aidl::android::hardware::vibrator;
 
+class VibratorCallback : public aidl::BnVibratorCallback {
+public:
+    ndk::ScopedAStatus onComplete() override {
+        mPromise.set_value();
+        return ndk::ScopedAStatus::ok();
+    }
+    void waitForComplete() { mPromise.get_future().wait(); }
+
+private:
+    std::promise<void> mPromise;
+};
+
 } // namespace vibrator
 } // namespace idlcli
 
 } // namespace android
-
-#endif // FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
new file mode 100644
index 0000000..9afa300
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandAlwaysOnDisable : public Command {
+    std::string getDescription() const override { return "Disarm always-on haptic source."; }
+
+    std::string getUsageSummary() const override { return "<id>"; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+                {"<id>", {"Source ID (device-specific)."}},
+        };
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (auto id = args.pop<decltype(mId)>()) {
+            mId = *id;
+            std::cout << "Source ID: " << mId << std::endl;
+        } else {
+            std::cerr << "Missing or Invalid Source ID!" << std::endl;
+            return USAGE;
+        }
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::alwaysOnDisable, mId);
+
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+
+        return ret;
+    }
+
+    int32_t mId;
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandAlwaysOnDisable>("alwaysOnDisable");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
new file mode 100644
index 0000000..bb7f9f2
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+using aidl::EffectStrength;
+
+class CommandAlwaysOnEnable : public Command {
+    std::string getDescription() const override {
+        return "Arm always-on haptic source with an effect.";
+    }
+
+    std::string getUsageSummary() const override { return "<id> <effect> <strength>"; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+                {"<id>", {"Source ID (device-specific)."}},
+                {"<effect>", {"Effect ID."}},
+                {"<strength>", {"0-2."}},
+        };
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (auto id = args.pop<decltype(mId)>()) {
+            mId = *id;
+            std::cout << "Source ID: " << mId << std::endl;
+        } else {
+            std::cerr << "Missing or Invalid Source ID!" << std::endl;
+            return USAGE;
+        }
+        if (auto effect = args.pop<decltype(mEffect)>()) {
+            mEffect = *effect;
+            std::cout << "Effect: " << toString(mEffect) << std::endl;
+        } else {
+            std::cerr << "Missing or Invalid Effect!" << std::endl;
+            return USAGE;
+        }
+        if (auto strength = args.pop<decltype(mStrength)>()) {
+            mStrength = *strength;
+            std::cout << "Strength: " << toString(mStrength) << std::endl;
+        } else {
+            std::cerr << "Missing or Invalid Strength!" << std::endl;
+            return USAGE;
+        }
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::alwaysOnEnable, mId, mEffect, mStrength);
+
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+
+        return ret;
+    }
+
+    int32_t mId;
+    Effect mEffect;
+    EffectStrength mStrength;
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandAlwaysOnEnable>("alwaysOnEnable");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 4721a5f..eb9008b 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -28,19 +28,33 @@
 class CommandCompose : public Command {
     std::string getDescription() const override { return "Compose vibration."; }
 
-    std::string getUsageSummary() const override { return "<delay> <primitive> <scale> ..."; }
+    std::string getUsageSummary() const override {
+        return "[options] <delay> <primitive> <scale> ...";
+    }
 
     UsageDetails getUsageDetails() const override {
         UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
                 {"<delay>", {"In milliseconds"}},
                 {"<primitive>", {"Primitive ID."}},
-                {"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}},
+                {"<scale>", {"0.0 (inclusive) - 1.0 (inclusive)."}},
                 {"...", {"May repeat multiple times."}},
         };
         return details;
     }
 
     Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
         while (!args.empty()) {
             CompositeEffect effect;
             if (auto delay = args.pop<decltype(effect.delayMs)>()) {
@@ -50,16 +64,15 @@
                 std::cerr << "Missing or Invalid Delay!" << std::endl;
                 return USAGE;
             }
-            // TODO: Use range validation when supported by AIDL
-            if (auto primitive = args.pop<std::underlying_type_t<decltype(effect.primitive)>>()) {
-                effect.primitive = static_cast<decltype(effect.primitive)>(*primitive);
+            if (auto primitive = args.pop<decltype(effect.primitive)>()) {
+                effect.primitive = *primitive;
                 std::cout << "Primitive: " << toString(effect.primitive) << std::endl;
             } else {
                 std::cerr << "Missing or Invalid Primitive!" << std::endl;
                 return USAGE;
             }
             if (auto scale = args.pop<decltype(effect.scale)>();
-                scale && *scale > 0.0 && scale <= 1.0) {
+                scale && *scale >= 0.0 && scale <= 1.0) {
                 effect.scale = *scale;
                 std::cout << "Scale: " << effect.scale << std::endl;
             } else {
@@ -76,21 +89,33 @@
     }
 
     Status doMain(Args && /*args*/) override {
-        std::string statusStr;
-        Status ret;
-        if (auto hal = getHal<aidl::IVibrator>()) {
-            auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr);
-            statusStr = status.getDescription();
-            ret = status.isOk() ? OK : ERROR;
-        } else {
+        auto hal = getHal<aidl::IVibrator>();
+
+        if (!hal) {
             return UNAVAILABLE;
         }
 
-        std::cout << "Status: " << statusStr << std::endl;
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
 
-        return ret;
+        std::shared_ptr<VibratorCallback> callback;
+
+        if (mBlocking) {
+            callback = ndk::SharedRefBase::make<VibratorCallback>();
+        }
+
+        auto status = hal->call(&aidl::IVibrator::compose, mComposite, callback);
+
+        if (status.isOk() && callback) {
+            callback->waitForComplete();
+        }
+
+        std::cout << "Status: " << status.getDescription() << std::endl;
+
+        return status.isOk() ? OK : ERROR;
     }
 
+    bool mBlocking;
     std::vector<CompositeEffect> mComposite;
 };
 
diff --git a/cmds/idlcli/vibrator/CommandComposePwle.cpp b/cmds/idlcli/vibrator/CommandComposePwle.cpp
new file mode 100644
index 0000000..b8308ce
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandComposePwle.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#include <charconv>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::ActivePwle;
+using aidl::Braking;
+using aidl::BrakingPwle;
+using aidl::PrimitivePwle;
+
+class CommandComposePwle : public Command {
+    std::string getDescription() const override { return "Compose PWLE vibration."; }
+
+    std::string getUsageSummary() const override {
+        return "[options] a <active pwle params> b <braking pwle params> ...";
+    }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+            {"-b", {"Block for duration of vibration."}},
+            {"a <startAmplitude> <startFrequency> <endAmplitude> <endFrequency> <duration>",
+             {"Enter the active PWLE segment parameters"}},
+            {"b <brakingMethod> <duration>", {"Enter the braking PWLE segment parameters"}},
+            {"...", {"May repeat multiple times."}},
+        };
+        return details;
+    }
+
+    int getIntFromString(std::string input, int *output) {
+        int rc = 0;
+        int value;
+        const auto res = std::from_chars(input.data(), input.data() + input.size(), value);
+        if (res.ec == std::errc::invalid_argument) {
+            std::cerr << "Invalid int argument: " << input << std::endl;
+            rc = (int)std::errc::invalid_argument;
+        } else if (res.ec == std::errc::result_out_of_range) {
+            std::cerr << "Result out of range: " << input << std::endl;
+            rc = (int)std::errc::result_out_of_range;
+        }
+        *output = value;
+        return rc;
+    }
+
+    float getFloatFromString(std::string_view input, float *output) {
+        int rc = 0;
+        errno = 0;
+        // from_chars doesn't support conversion to float so we need to first
+        // convert the string_view to string and use the C-string for strtof
+        float value = strtof(std::string(input).c_str(), NULL);
+
+        if (input == "0.0" || input == "0") {
+            return rc;
+        }
+
+        if (value <= 0.0) {
+            std::cerr << "Invalid float argument: " << input << std::endl;
+            rc = EINVAL;
+        } else if (errno == ERANGE) {
+            std::cerr << "Result out of range: " << input << std::endl;
+            rc = errno;
+        } else {
+            *output = value;
+        }
+        return rc;
+    }
+
+    Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
+        if (args.empty()) {
+            std::cerr << "Missing arguments! Please see usage" << std::endl;
+            return USAGE;
+        }
+        while (!args.empty()) {
+            PrimitivePwle pwle;
+            auto nextArg = args.pop();
+
+            if (*nextArg == "a") {
+                auto startAmplitude = args.pop();
+                float startAmp;
+                if (getFloatFromString(*startAmplitude, &startAmp))
+                    return USAGE;
+
+                auto startFrequency = args.pop();
+                float startFreq;
+                if (getFloatFromString(*startFrequency, &startFreq))
+                    return USAGE;
+
+                auto endAmplitude = args.pop();
+                float endAmp;
+                if (getFloatFromString(*endAmplitude, &endAmp))
+                    return USAGE;
+
+                auto endFrequency = args.pop();
+                float endFreq;
+                if (getFloatFromString(*endFrequency, &endFreq))
+                    return USAGE;
+
+                auto duration = args.pop();
+                int dur;
+                if (getIntFromString(*duration, &dur))
+                    return USAGE;
+
+                ActivePwle active = {startAmp, startFreq, endAmp, endFreq, dur};
+                pwle = active;
+            } else if (*nextArg == "b") {
+                auto brakingMethod = args.pop();
+                Braking brakingMeth;
+                if (getIntFromString(*brakingMethod, (int *)&brakingMeth))
+                    return USAGE;
+
+                auto duration = args.pop();
+                int dur;
+                if (getIntFromString(*duration, &dur))
+                    return USAGE;
+
+                BrakingPwle braking = {brakingMeth, dur};
+                pwle = braking;
+            } else {
+                std::cerr << "Invalid arguments! Please see usage" << std::endl;
+                return USAGE;
+            }
+            mCompositePwle.emplace_back(std::move(pwle));
+        }
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        auto hal = getHal<aidl::IVibrator>();
+
+        if (!hal) {
+            return UNAVAILABLE;
+        }
+
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
+
+        std::shared_ptr<VibratorCallback> callback;
+
+        if (mBlocking) {
+            callback = ndk::SharedRefBase::make<VibratorCallback>();
+        }
+
+        auto status = hal->call(&aidl::IVibrator::composePwle, mCompositePwle, callback);
+
+        if (status.isOk() && callback) {
+            callback->waitForComplete();
+        }
+
+        std::cout << "Status: " << status.getDescription() << std::endl;
+
+        return status.isOk() ? OK : ERROR;
+    }
+
+    bool mBlocking;
+    std::vector<PrimitivePwle> mCompositePwle;
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandComposePwle>("composePwle");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
new file mode 100644
index 0000000..aa01a11
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetBandwidthAmplitudeMap : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator bandwidth amplitude map.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<float> bandwidthAmplitude;
+        float frequencyMinimumHz;
+        float frequencyResolutionHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status =
+                hal->call(&aidl::IVibrator::getBandwidthAmplitudeMap, &bandwidthAmplitude);
+            statusStr = status.getDescription();
+            ret = (status.isOk() ? OK : ERROR);
+
+            status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
+            ret = (status.isOk() ? OK : ERROR);
+
+            status =
+                hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
+            ret = (status.isOk() ? OK : ERROR);
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Bandwidth Amplitude Map: " << std::endl;
+        float frequency = frequencyMinimumHz;
+        for (auto &e : bandwidthAmplitude) {
+            std::cout << frequency << ":" << e << std::endl;
+            frequency += frequencyResolutionHz;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetBandwidthAmplitudeMap>(
+        "getBandwidthAmplitudeMap");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
new file mode 100644
index 0000000..504c648
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetFrequencyMinimum : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator minimum frequency in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float frequencyMinimumHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Minimum Frequency: " << frequencyMinimumHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyMinimum>("getFrequencyMinimum");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
new file mode 100644
index 0000000..de35838
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetFrequencyResolution : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator frequency resolution in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float frequencyResolutionHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status =
+                hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Frequency Resolution: " << frequencyResolutionHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyResolution>(
+        "getFrequencyResolution");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
new file mode 100644
index 0000000..460d39e
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
@@ -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.
+ */
+
+#include <future>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePrimitive;
+
+class CommandGetPrimitiveDuration : public Command {
+    std::string getDescription() const override {
+        return "Retrieve effect primitive's duration in milliseconds.";
+    }
+
+    std::string getUsageSummary() const override { return "<primitive>"; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+                {"<primitive>", {"Primitive ID."}},
+        };
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (auto primitive = args.pop<decltype(mPrimitive)>()) {
+            mPrimitive = *primitive;
+            std::cout << "Primitive: " << toString(mPrimitive) << std::endl;
+        } else {
+            std::cerr << "Missing or Invalid Primitive!" << std::endl;
+            return USAGE;
+        }
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t duration;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPrimitiveDuration, mPrimitive, &duration);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Duration: " << duration << std::endl;
+
+        return ret;
+    }
+
+    CompositePrimitive mPrimitive;
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetPrimitiveDuration>(
+        "getPrimitiveDuration");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
new file mode 100644
index 0000000..b2c3551
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwleCompositionSizeMax : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PWLE composition size max.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t maxSize;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwleCompositionSizeMax, &maxSize);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Max Size: " << maxSize << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetPwleCompositionSizeMax>(
+        "getPwleCompositionSizeMax");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
new file mode 100644
index 0000000..9081973
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwlePrimitiveDurationMax : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PWLE primitive duration size max in milliseconds.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t maxDurationMs;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwlePrimitiveDurationMax, &maxDurationMs);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetPwlePrimitiveDurationMax>(
+        "getPwlePrimitiveDurationMax");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetQFactor.cpp b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
new file mode 100644
index 0000000..a2681e9
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetQFactor : public Command {
+    std::string getDescription() const override { return "Retrieves vibrator Q factor."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float qFactor;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getQFactor, &qFactor);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Q Factor: " << qFactor << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetQFactor>("getQFactor");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
new file mode 100644
index 0000000..81a6391
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetResonantFrequency : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator resonant frequency in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float resonantFrequencyHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getResonantFrequency, &resonantFrequencyHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Resonant Frequency: " << resonantFrequencyHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetResonantFrequency>(
+    "getResonantFrequency");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
new file mode 100644
index 0000000..edfcd91
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+
+class CommandGetSupportedAlwaysOnEffects : public Command {
+    std::string getDescription() const override { return "List of supported always-on effects."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<Effect> effects;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getSupportedAlwaysOnEffects, &effects);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Effects:" << std::endl;
+        for (auto &e : effects) {
+            std::cout << "  " << toString(e) << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetSupportedAlwaysOnEffects>(
+                "getSupportedAlwaysOnEffects");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
new file mode 100644
index 0000000..b326e07
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Braking;
+
+class CommandGetSupportedBraking : public Command {
+    std::string getDescription() const override { return "List of supported braking mechanisms."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<Braking> braking;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getSupportedBraking, &braking);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Braking Mechanisms:" << std::endl;
+        for (auto &e : braking) {
+            std::cout << "  " << toString(e) << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetSupportedBraking>("getSupportedBraking");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
new file mode 100644
index 0000000..7658f22
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+
+class CommandGetSupportedEffects : public Command {
+    std::string getDescription() const override { return "List supported effects."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<Effect> effects;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getSupportedEffects, &effects);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Effects:" << std::endl;
+        for (auto &e : effects) {
+            std::cout << "  " << toString(e) << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetSupportedEffects>(
+        "getSupportedEffects");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
new file mode 100644
index 0000000..d101681
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePrimitive;
+
+class CommandGetSupportedPrimitives : public Command {
+    std::string getDescription() const override { return "List of supported effect primitive."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<CompositePrimitive> primitives;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getSupportedPrimitives, &primitives);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Primitives:" << std::endl;
+        for (auto &e : primitives) {
+            std::cout << "  " << toString(e) << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+        CommandRegistry<CommandVibrator>::Register<CommandGetSupportedPrimitives>(
+                "getSupportedPrimitives");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index 4e7e493..8212fc1 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -13,9 +13,14 @@
  * limitations under the License.
  */
 
+#include <thread>
+
 #include "utils.h"
 #include "vibrator.h"
 
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
 namespace android {
 namespace idlcli {
 
@@ -26,16 +31,28 @@
 class CommandOn : public Command {
     std::string getDescription() const override { return "Turn on vibrator."; }
 
-    std::string getUsageSummary() const override { return "<duration>"; }
+    std::string getUsageSummary() const override { return "[options] <duration>"; }
 
     UsageDetails getUsageDetails() const override {
         UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
                 {"<duration>", {"In milliseconds."}},
         };
         return details;
     }
 
     Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
         if (auto duration = args.pop<decltype(mDuration)>()) {
             mDuration = *duration;
         } else {
@@ -52,9 +69,21 @@
     Status doMain(Args && /*args*/) override {
         std::string statusStr;
         Status ret;
+        std::shared_ptr<VibratorCallback> callback;
 
         if (auto hal = getHal<aidl::IVibrator>()) {
-            auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
+            ABinderProcess_setThreadPoolMaxThreadCount(1);
+            ABinderProcess_startThreadPool();
+
+            int32_t cap;
+            hal->call(&aidl::IVibrator::getCapabilities, &cap);
+
+            if (mBlocking && (cap & aidl::IVibrator::CAP_ON_CALLBACK)) {
+                callback = ndk::SharedRefBase::make<VibratorCallback>();
+            }
+
+            auto status = hal->call(&aidl::IVibrator::on, mDuration, callback);
+
             statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_0::IVibrator>()) {
@@ -65,11 +94,20 @@
             return UNAVAILABLE;
         }
 
+        if (ret == OK && mBlocking) {
+            if (callback) {
+                callback->waitForComplete();
+            } else {
+                sleep_for(milliseconds(mDuration));
+            }
+        }
+
         std::cout << "Status: " << statusStr << std::endl;
 
         return ret;
     }
 
+    bool mBlocking;
     uint32_t mDuration;
 };
 
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index 69c7e37..c897686 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -13,9 +13,14 @@
  * limitations under the License.
  */
 
+#include <thread>
+
 #include "utils.h"
 #include "vibrator.h"
 
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
 namespace android {
 namespace idlcli {
 
@@ -51,16 +56,17 @@
 static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
               static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
 
-using V1_0::EffectStrength;
-using V1_3::Effect;
+using aidl::Effect;
+using aidl::EffectStrength;
 
 class CommandPerform : public Command {
     std::string getDescription() const override { return "Perform vibration effect."; }
 
-    std::string getUsageSummary() const override { return "<effect> <strength>"; }
+    std::string getUsageSummary() const override { return "[options] <effect> <strength>"; }
 
     UsageDetails getUsageDetails() const override {
         UsageDetails details{
+                {"-b", {"Block for duration of vibration."}},
                 {"<effect>", {"Effect ID."}},
                 {"<strength>", {"0-2."}},
         };
@@ -68,6 +74,17 @@
     }
 
     Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
         if (auto effect = args.pop<decltype(mEffect)>()) {
             mEffect = *effect;
             std::cout << "Effect: " << toString(mEffect) << std::endl;
@@ -93,12 +110,23 @@
         std::string statusStr;
         uint32_t lengthMs;
         Status ret;
+        std::shared_ptr<VibratorCallback> callback;
 
         if (auto hal = getHal<aidl::IVibrator>()) {
+            ABinderProcess_setThreadPoolMaxThreadCount(1);
+            ABinderProcess_startThreadPool();
+
+            int32_t cap;
+            hal->call(&aidl::IVibrator::getCapabilities, &cap);
+
+            if (mBlocking && (cap & aidl::IVibrator::CAP_PERFORM_CALLBACK)) {
+                callback = ndk::SharedRefBase::make<VibratorCallback>();
+            }
+
             int32_t aidlLengthMs;
-            auto status =
-                    hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect),
-                              static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs);
+            auto status = hal->call(&aidl::IVibrator::perform, mEffect, mStrength, callback,
+                                    &aidlLengthMs);
+
             statusStr = status.getDescription();
             lengthMs = static_cast<uint32_t>(aidlLengthMs);
             ret = status.isOk() ? OK : ERROR;
@@ -111,17 +139,20 @@
             };
 
             if (auto hal = getHal<V1_3::IVibrator>()) {
-                hidlRet = hal->call(&V1_3::IVibrator::perform_1_3,
-                                    static_cast<V1_3::Effect>(mEffect), mStrength, callback);
+                hidlRet =
+                        hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect),
+                                  static_cast<V1_0::EffectStrength>(mStrength), callback);
             } else if (auto hal = getHal<V1_2::IVibrator>()) {
-                hidlRet = hal->call(&V1_2::IVibrator::perform_1_2,
-                                    static_cast<V1_2::Effect>(mEffect), mStrength, callback);
+                hidlRet =
+                        hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect),
+                                  static_cast<V1_0::EffectStrength>(mStrength), callback);
             } else if (auto hal = getHal<V1_1::IVibrator>()) {
                 hidlRet = hal->call(&V1_1::IVibrator::perform_1_1,
-                                    static_cast<V1_1::Effect_1_1>(mEffect), mStrength, callback);
+                                    static_cast<V1_1::Effect_1_1>(mEffect),
+                                    static_cast<V1_0::EffectStrength>(mStrength), callback);
             } else if (auto hal = getHal<V1_0::IVibrator>()) {
                 hidlRet = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect),
-                                    mStrength, callback);
+                                    static_cast<V1_0::EffectStrength>(mStrength), callback);
             } else {
                 return UNAVAILABLE;
             }
@@ -130,12 +161,21 @@
             ret = hidlRet.isOk() && status == V1_0::Status::OK ? OK : ERROR;
         }
 
+        if (ret == OK && mBlocking) {
+            if (callback) {
+                callback->waitForComplete();
+            } else {
+                sleep_for(milliseconds(lengthMs));
+            }
+        }
+
         std::cout << "Status: " << statusStr << std::endl;
         std::cout << "Length: " << lengthMs << std::endl;
 
         return ret;
     }
 
+    bool mBlocking;
     Effect mEffect;
     EffectStrength mStrength;
 };
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 8ff4dd8..3f180d9 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "installd_defaults",
 
@@ -17,15 +26,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",
@@ -38,6 +47,12 @@
         "libutils",
         "server_configurable_flags",
     ],
+    static_libs: [
+        "libasync_safe",
+    ],
+    export_shared_lib_headers: [
+        "libbinder",
+    ],
 
     product_variables: {
         arc: {
@@ -103,6 +118,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
 //
 
@@ -155,16 +192,15 @@
         "liblog",
         "libutils",
     ],
-    static_libs: [
-        "libapexd",
+    required: [
+      "apexd"
     ],
 }
 
 filegroup {
     name: "installd_aidl",
     srcs: [
-        "binder/android/os/IInstalld.aidl",
-        "binder/android/os/storage/CrateMetadata.aidl",
+        "binder/**/*.aidl",
     ],
     path: "binder",
 }
@@ -205,18 +241,19 @@
 
     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",
+        "libasync_safe",
         "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 01eb3fe..74be7ce 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);
@@ -420,33 +424,7 @@
     return true;
 }
 
-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,
-        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) {
-    ENFORCE_UID(AID_SYSTEM);
-    std::lock_guard<std::recursive_mutex> lock(mLock);
-
-    ATRACE_BEGIN("createAppDataBatched");
-    binder::Status ret;
-    for (size_t i = 0; i < uuids->size(); i++) {
-        if (!packageNames->at(i)) {
-            continue;
-        }
-        ret = createAppData(uuids->at(i), *packageNames->at(i), userId, flags, appIds[i],
-                seInfos[i], targetSdkVersions[i], _aidl_return);
-        if (!ret.isOk()) {
-            ATRACE_END();
-            return ret;
-        }
-    }
-    ATRACE_END();
-    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 +505,39 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::migrateAppData(const std::unique_ptr<std::string>& uuid,
+
+binder::Status InstalldNativeService::createAppData(
+        const android::os::CreateAppDataArgs& args,
+        android::os::CreateAppDataResult* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    int64_t ceDataInode = -1;
+    auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
+                                args.seInfo, args.targetSdkVersion, &ceDataInode);
+    _aidl_return->ceDataInode = ceDataInode;
+    _aidl_return->exceptionCode = status.exceptionCode();
+    _aidl_return->exceptionMessage = status.exceptionMessage();
+    return ok();
+}
+
+binder::Status InstalldNativeService::createAppDataBatched(
+        const std::vector<android::os::CreateAppDataArgs>& args,
+        std::vector<android::os::CreateAppDataResult>* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    std::vector<android::os::CreateAppDataResult> results;
+    for (auto arg : args) {
+        android::os::CreateAppDataResult result;
+        createAppData(arg, &result);
+        results.push_back(result);
+    }
+    *_aidl_return = results;
+    return ok();
+}
+
+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 +598,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 +718,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 +790,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 +910,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);
@@ -1030,7 +1040,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);
@@ -1102,7 +1112,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);
@@ -1135,7 +1145,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);
@@ -1143,7 +1153,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) {
@@ -1162,7 +1172,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);
@@ -1172,8 +1182,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);
@@ -1280,7 +1290,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);
@@ -1298,7 +1308,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);
@@ -1335,13 +1345,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);
@@ -1739,7 +1749,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) {
@@ -1779,7 +1789,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)) {
@@ -1966,7 +1976,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);
@@ -1986,7 +1996,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)) {
@@ -2098,7 +2108,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);
@@ -2113,7 +2123,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;
@@ -2215,9 +2225,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) {
@@ -2226,15 +2236,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) {
@@ -2246,15 +2256,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) {
@@ -2265,22 +2275,22 @@
 }
 
 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;
         }
-        retVector->push_back(std::move(crateMetadata));
+        retVector.push_back(std::move(crateMetadata));
     };
 
     std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void {
@@ -2290,15 +2300,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) {
@@ -2308,7 +2318,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);
@@ -2346,7 +2356,7 @@
 
 // TODO: Consider returning error codes.
 binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
-        const std::string& profileName, bool* _aidl_return) {
+        const std::string& profileName, int* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -2379,19 +2389,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);
@@ -2437,7 +2447,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);
@@ -2528,7 +2538,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);
@@ -2646,7 +2656,8 @@
 }
 
 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,
+        int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PATH(apkPath);
     CHECK_ARGUMENT_PATH(outputPath);
@@ -2656,8 +2667,8 @@
     const char* instruction_set = instructionSet.c_str();
     const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
 
-    bool res = delete_odex(apk_path, instruction_set, oat_dir);
-    return res ? ok() : error();
+    *_aidl_return = delete_odex(apk_path, instruction_set, oat_dir);
+    return *_aidl_return == -1 ? error() : ok();
 }
 
 // This kernel feature is experimental.
@@ -2798,7 +2809,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);
@@ -2813,7 +2824,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);
@@ -2872,7 +2883,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) {
@@ -2936,7 +2947,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) {
@@ -2980,7 +2991,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());
@@ -2993,15 +3004,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..ea0c945 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -40,81 +40,84 @@
     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,
-            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 createAppData(
+            const android::os::CreateAppDataArgs& args,
+            android::os::CreateAppDataResult* _aidl_return);
+    binder::Status createAppDataBatched(
+            const std::vector<android::os::CreateAppDataArgs>& args,
+            std::vector<android::os::CreateAppDataResult>* _aidl_return);
+
+    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);
@@ -122,7 +125,7 @@
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
-            const std::string& profileName, bool* _aidl_return);
+            const std::string& profileName, int* _aidl_return);
     binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
             const std::string& profileName, const std::string& codePath, bool* _aidl_return);
     binder::Status copySystemProfile(const std::string& systemProfile,
@@ -137,9 +140,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 +150,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, int64_t* _aidl_return);
     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 +187,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..d6807ff 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
@@ -10,3 +9,4 @@
 ngeoffray@google.com
 rpl@google.com
 toddke@google.com
+patb@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/CreateAppDataArgs.aidl b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
new file mode 100644
index 0000000..96d7faa
--- /dev/null
+++ b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
@@ -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.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable CreateAppDataArgs {
+    @nullable @utf8InCpp String uuid;
+    @utf8InCpp String packageName;
+    int userId;
+    int flags;
+    int appId;
+    @utf8InCpp String seInfo;
+    int targetSdkVersion;
+}
diff --git a/cmds/installd/binder/android/os/CreateAppDataResult.aidl b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
new file mode 100644
index 0000000..3b8fa6b
--- /dev/null
+++ b/cmds/installd/binder/android/os/CreateAppDataResult.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+/** {@hide} */
+parcelable CreateAppDataResult {
+    long ceDataInode;
+    int exceptionCode;
+    @utf8InCpp String exceptionMessage;
+}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index eeda6c5..3d32f61 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -21,11 +21,9 @@
     void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
     void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
 
-    long createAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
-            int userId, int flags, int appId, in @utf8InCpp String seInfo, int targetSdkVersion);
-    long createAppDataBatched(in @nullable @utf8InCpp String[] uuids,
-        in @nullable @utf8InCpp String[] packageNames, in int userId, int flags, in int[] appIds,
-        in @utf8InCpp String[] seInfos, in int[] targetSdkVersions);
+    android.os.CreateAppDataResult createAppData(in android.os.CreateAppDataArgs args);
+    android.os.CreateAppDataResult[] createAppDataBatched(in android.os.CreateAppDataArgs[] args);
+
     void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, int flags, int appId, @utf8InCpp String seInfo);
     void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
@@ -71,7 +69,7 @@
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
-    boolean mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
+    int mergeProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String profileName);
     boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String  profileName,
             @utf8InCpp String codePath);
     boolean copySystemProfile(@utf8InCpp String systemProfile, int uid,
@@ -93,7 +91,7 @@
             @utf8InCpp String toBase);
     void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @utf8InCpp String outputPath);
-    void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+    long deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
             @nullable @utf8InCpp String outputPath);
     void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput,
             int contentSize);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ffa8724..d678281 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,25 +36,30 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <async_safe/log.h>
 #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>
-#include <processgroup/sched_policy.h>
+#include <processgroup/processgroup.h>
 #include <selinux/android.h>
 #include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
 #include "dexopt_return_codes.h"
+#include "execv_helper.h"
 #include "globals.h"
 #include "installd_deps.h"
+#include "installd_constants.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 +72,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 +181,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 +219,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 +233,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.
@@ -654,8 +282,8 @@
 
 static void SetDex2OatScheduling(bool set_to_bg) {
     if (set_to_bg) {
-        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            PLOG(ERROR) << "set_sched_policy failed";
+        if (!SetTaskProfiles(0, {"Dex2OatBootComplete"})) {
+            LOG(ERROR) << "Failed to set dex2oat task profile";
             exit(DexoptReturnCodes::kSetSchedPolicy);
         }
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
@@ -665,8 +293,8 @@
     }
 }
 
-static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, mode)));
     if (fd.get() < 0) {
         if (errno != EEXIST) {
             PLOG(ERROR) << "Failed to create profile " << profile;
@@ -683,7 +311,7 @@
     return fd;
 }
 
-static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
     // Do not follow symlinks when opening a profile:
     //   - primary profiles should not contain symlinks in their paths
     //   - secondary dex paths should have been already resolved and validated
@@ -693,7 +321,7 @@
     // Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
     unique_fd fd;
     if ((flags & O_CREAT) != 0) {
-        fd = create_profile(uid, profile, flags);
+        fd = create_profile(uid, profile, flags, mode);
     } else {
         fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
     }
@@ -709,6 +337,16 @@
             PLOG(ERROR) << "Failed to open profile " << profile;
         }
         return invalid_unique_fd();
+    } else {
+        // If we just create the file we need to set its mode because on Android
+        // open has a mask that only allows owner access.
+        if ((flags & O_CREAT) != 0) {
+            if (fchmod(fd.get(), mode) != 0) {
+                PLOG(ERROR) << "Could not set mode " << std::hex << mode << std::dec
+                        << " on profile" << profile;
+                // Not a terminal failure.
+            }
+        }
     }
 
     return fd;
@@ -718,19 +356,38 @@
         const std::string& location, bool is_secondary_dex) {
     std::string profile = create_current_profile_path(user, package_name, location,
             is_secondary_dex);
-    return open_profile(uid, profile, O_RDONLY);
+    return open_profile(uid, profile, O_RDONLY, /*mode=*/ 0);
 }
 
 static unique_fd open_reference_profile(uid_t uid, const std::string& package_name,
         const std::string& location, bool read_write, bool is_secondary_dex) {
     std::string profile = create_reference_profile_path(package_name, location, is_secondary_dex);
-    return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+    return open_profile(
+        uid,
+        profile,
+        read_write ? (O_CREAT | O_RDWR) : O_RDONLY,
+        S_IRUSR | S_IWUSR | S_IRGRP);  // so that ART can also read it when apps run.
+}
+
+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,
+        S_IRUSR | S_IWUSR | S_IRGRP);  // so that ART can also read it when apps run.
+
+    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);
-    return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
+    return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC,  S_IRUSR | S_IWUSR);
 }
 
 static void open_profile_files(uid_t uid, const std::string& package_name,
@@ -760,11 +417,12 @@
 
 static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0;
 static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1;
-static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 2;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA = 2;
 static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 4;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 5;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_DIFFERENT_VERSIONS = 6;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_EMPTY_PROFILES = 7;
 
 class RunProfman : public ExecVHelper {
   public:
@@ -814,6 +472,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 +546,7 @@
                   /*for_boot_image*/false);
     }
 
+    using ExecVHelper::Exec;  // To suppress -Wno-overloaded-virtual
     void Exec() {
         ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
     }
@@ -878,15 +557,7 @@
     std::vector<unique_fd> apk_fds_;
 };
 
-
-
-// Decides if profile guided compilation is needed or not based on existing profiles.
-// The location is the package name for primary apks or the dex path for secondary dex files.
-// Returns true if there is enough information in the current profiles that makes it
-// worth to recompile the given location.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-static bool analyze_profiles(uid_t uid, const std::string& package_name,
+static int analyze_profiles(uid_t uid, const std::string& package_name,
         const std::string& location, bool is_secondary_dex) {
     std::vector<unique_fd> profiles_fd;
     unique_fd reference_profile_fd;
@@ -895,7 +566,7 @@
     if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
         // Skip profile guided compilation because no profiles were found.
         // Or if the reference profile info couldn't be opened.
-        return false;
+        return PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES;
     }
 
     RunProfman profman_merge;
@@ -917,6 +588,7 @@
     /* parent */
     int return_code = wait_child(pid);
     bool need_to_compile = false;
+    bool empty_profiles = false;
     bool should_clear_current_profiles = false;
     bool should_clear_reference_profile = false;
     if (!WIFEXITED(return_code)) {
@@ -929,11 +601,17 @@
                 should_clear_current_profiles = true;
                 should_clear_reference_profile = false;
                 break;
-            case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
+            case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA:
                 need_to_compile = false;
                 should_clear_current_profiles = false;
                 should_clear_reference_profile = false;
                 break;
+            case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_EMPTY_PROFILES:
+                need_to_compile = false;
+                empty_profiles = true;
+                should_clear_current_profiles = false;
+                should_clear_reference_profile = false;
+                break;
             case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
                 LOG(WARNING) << "Bad profiles for location " << location;
                 need_to_compile = false;
@@ -976,16 +654,29 @@
     if (should_clear_reference_profile) {
         clear_reference_profile(package_name, location, is_secondary_dex);
     }
-    return need_to_compile;
+    int result = 0;
+    if (need_to_compile) {
+        result = PROFILES_ANALYSIS_OPTIMIZE;
+    } else if (empty_profiles) {
+        result = PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES;
+    } else {
+        result = PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+    }
+    return result;
 }
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
-// The analysis is done for the primary apks of the given package.
-// Returns true if there is enough information in the current profiles that makes it
-// worth to recompile the package.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-bool analyze_primary_profiles(uid_t uid, const std::string& package_name,
+// The analysis is done for a single profile name (which corresponds to a single code path).
+//
+// Returns PROFILES_ANALYSIS_OPTIMIZE if there is enough information in the current profiles
+// that makes it worth to recompile the package.
+// If the return value is PROFILES_ANALYSIS_OPTIMIZE all the current profiles would have been
+// merged into the reference profiles accessible with open_reference_profile().
+//
+// Return PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA if the package should not optimize.
+// As a special case returns PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES if all profiles are
+// empty.
+int analyze_primary_profiles(uid_t uid, const std::string& package_name,
         const std::string& profile_name) {
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
@@ -1022,7 +713,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));
 
 
@@ -1070,7 +761,8 @@
 
         if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             if (errno != EWOULDBLOCK) {
-                PLOG(WARNING) << "Error locking profile " << package_name;
+                async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error locking profile %s: %d",
+                        package_name.c_str(), errno);
             }
             // This implies that the app owning this profile is running
             // (and has acquired the lock).
@@ -1078,13 +770,15 @@
             // The app never acquires the lock for the reference profiles of primary apks.
             // Only dex2oat from installd will do that. Since installd is single threaded
             // we should not see this case. Nevertheless be prepared for it.
-            PLOG(WARNING) << "Failed to flock " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Failed to flock %s: %d",
+                    package_name.c_str(), errno);
             return false;
         }
 
         bool truncated = ftruncate(out_fd.get(), 0) == 0;
         if (!truncated) {
-            PLOG(WARNING) << "Could not truncate " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Could not truncate %s: %d",
+                    package_name.c_str(), errno);
         }
 
         // Copy over data.
@@ -1098,7 +792,8 @@
             write(out_fd.get(), buffer, bytes);
         }
         if (flock(out_fd.get(), LOCK_UN) != 0) {
-            PLOG(WARNING) << "Error unlocking profile " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error unlocking profile %s: %d",
+                    package_name.c_str(), errno);
         }
         // Use _exit since we don't want to run the global destructors in the child.
         // b/62597429
@@ -1216,118 +911,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 +926,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 +949,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 +981,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 +999,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 +1009,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 +1052,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 +1070,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 +1087,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 +1115,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 +1168,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
@@ -1607,7 +1180,7 @@
                       int zip_fd,
                       const std::string& instruction_set,
                       const std::string& compiler_filter,
-                      bool profile_was_updated,
+                      int profile_analysis_result,
                       bool downgrade,
                       const char* class_loader_context,
                       const std::string& class_loader_context_fds) {
@@ -1623,7 +1196,8 @@
         std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
         std::string isa_arg = "--isa=" + instruction_set;
         std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
-        const char* assume_profile_changed = "--assume-profile-changed";
+        std::string profile_analysis_arg = "--profile-analysis-result="
+                + std::to_string(profile_analysis_result);
         const char* downgrade_flag = "--downgrade";
         std::string class_loader_context_arg = "--class-loader-context=";
         if (class_loader_context != nullptr) {
@@ -1645,9 +1219,8 @@
             AddArg(vdex_fd_arg);
         }
         AddArg(zip_fd_arg);
-        if (profile_was_updated) {
-            AddArg(assume_profile_changed);
-        }
+        AddArg(profile_analysis_arg);
+
         if (downgrade) {
             AddArg(downgrade_flag);
         }
@@ -1658,6 +1231,14 @@
             }
         }
 
+        // On-device signing related. odsign sets the system property odsign.verification.success if
+        // AOT artifacts have the expected signatures.
+        const bool trust_art_apex_data_files =
+                ::android::base::GetBoolProperty("odsign.verification.success", false);
+        if (!trust_art_apex_data_files) {
+            AddRuntimeArg("-Xdeny-art-apex-data-files");
+        }
+
         PrepareArgs(dexoptanalyzer_bin);
     }
 
@@ -1790,10 +1371,12 @@
         return kSecondaryDexAccessReadOk;
     } else {
         if (errno == ENOENT) {
-            LOG(INFO) << "Secondary dex does not exist: " <<  dex_path;
+            async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+                    "Secondary dex does not exist: %s", dex_path.c_str());
             return kSecondaryDexAccessDoesNotExist;
         } else {
-            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not access secondary dex: %s (%d)", dex_path.c_str(), errno);
             return errno == EACCES
                 ? kSecondaryDexAccessPermissionError
                 : kSecondaryDexAccessIOError;
@@ -1978,7 +1561,8 @@
 
         // Validate the path structure.
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
-            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
         }
 
@@ -2018,7 +1602,7 @@
         }
 
         // Analyze profiles.
-        bool profile_was_updated = analyze_profiles(uid, pkgname, dex_path,
+        int profile_analysis_result = analyze_profiles(uid, pkgname, dex_path,
                 /*is_secondary_dex*/true);
 
         // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
@@ -2029,7 +1613,8 @@
                                               oat_file_fd.get(),
                                               zip_fd.get(),
                                               instruction_set,
-                                              compiler_filter, profile_was_updated,
+                                              compiler_filter,
+                                              profile_analysis_result,
                                               downgrade,
                                               class_loader_context,
                                               join_fds(context_zip_fds));
@@ -2149,8 +1734,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 +1749,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 +1781,86 @@
     }
 
     // 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) {
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "flock(%s) failed",
+                    out_oat.path().c_str());
             _exit(DexoptReturnCodes::kFlock);
         }
 
@@ -2269,13 +1877,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 +1931,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,10 +1952,11 @@
         /* 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;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(kReconcileSecondaryDexValidationError);
         }
 
@@ -2362,7 +1969,8 @@
             case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
             case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
             default:
-                LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                        "Unexpected result from check_secondary_dex_access: %d", access_check);
                 _exit(kReconcileSecondaryDexValidationError);
         }
 
@@ -2375,7 +1983,7 @@
             std::string error_msg;
             if (!create_secondary_dex_oat_layout(
                     dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
-                LOG(ERROR) << error_msg;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
                 _exit(kReconcileSecondaryDexValidationError);
             }
 
@@ -2402,7 +2010,8 @@
             result = rmdir_if_empty(oat_dir) && result;
         }
         if (!result) {
-            PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
         }
         _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
     }
@@ -2447,11 +2056,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: "
@@ -2475,7 +2084,8 @@
         pipe_read.reset();
 
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
-            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(DexoptReturnCodes::kHashValidatePath);
         }
 
@@ -2486,6 +2096,8 @@
                 _exit(0);
             }
             PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Failed to open secondary dex %s: %d", dex_path.c_str(), errno);
             _exit(DexoptReturnCodes::kHashOpenPath);
         }
 
@@ -2498,7 +2110,8 @@
             if (bytes_read == 0) {
                 break;
             } else if (bytes_read == -1) {
-                PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                        "Failed to read secondary dex %s: %d", dex_path.c_str(), errno);
                 _exit(DexoptReturnCodes::kHashReadDex);
             }
 
@@ -2557,8 +2170,9 @@
     {
         struct stat s;
         if (stat(b_path.c_str(), &s) != 0) {
-            // Silently ignore for now. The service calling this isn't smart enough to understand
-            // lack of artifacts at the moment.
+            // Ignore for now. The service calling this isn't smart enough to
+            // understand lack of artifacts at the moment.
+            LOG(VERBOSE) << "A/B artifact " << b_path << " does not exist!";
             return false;
         }
         if (!S_ISREG(s.st_mode)) {
@@ -2648,38 +2262,52 @@
     return success;
 }
 
-bool delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+int64_t delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
     // Delete the oat/odex file.
     char out_path[PKG_PATH_MAX];
     if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
             /*is_secondary_dex*/false, out_path)) {
-        return false;
+        LOG(ERROR) << "Cannot create apk path for " << apk_path;
+        return -1;
     }
 
     // In case of a permission failure report the issue. Otherwise just print a warning.
-    auto unlink_and_check = [](const char* path) -> bool {
-        int result = unlink(path);
-        if (result != 0) {
-            if (errno == EACCES || errno == EPERM) {
-                PLOG(ERROR) << "Could not unlink " << path;
-                return false;
+    auto unlink_and_check = [](const char* path) -> int64_t {
+        struct stat file_stat;
+        if (stat(path, &file_stat) != 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "Could not stat " << path;
+                return -1;
             }
-            PLOG(WARNING) << "Could not unlink " << path;
+            return 0;
         }
-        return true;
+
+        if (unlink(path) != 0) {
+            if (errno != ENOENT) {
+                PLOG(ERROR) << "Could not unlink " << path;
+                return -1;
+            }
+        }
+        return static_cast<int64_t>(file_stat.st_size);
     };
 
     // Delete the oat/odex file.
-    bool return_value_oat = unlink_and_check(out_path);
+    int64_t return_value_oat = unlink_and_check(out_path);
 
     // Derive and delete the app image.
-    bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
+    int64_t return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
 
     // Derive and delete the vdex file.
-    bool return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
+    int64_t return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
 
-    // Report success.
-    return return_value_oat && return_value_art && return_value_vdex;
+    // Report result
+    if (return_value_oat == -1
+            || return_value_art == -1
+            || return_value_vdex == -1) {
+        return -1;
+    }
+
+    return return_value_oat + return_value_art + return_value_vdex;
 }
 
 static bool is_absolute_path(const std::string& path) {
@@ -2914,7 +2542,7 @@
     for (size_t i = 0; i < profiles.size(); )  {
         std::vector<unique_fd> profiles_fd;
         for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) {
-            unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY);
+            unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY, /*mode=*/ 0);
             if (fd.get() >= 0) {
                 profiles_fd.push_back(std::move(fd));
             }
@@ -2978,7 +2606,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 +2617,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..5a637b1 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 {
@@ -52,15 +54,20 @@
 // Clear all current profiles identified by the given profile name (all users).
 bool clear_primary_current_profiles(const std::string& pkgname, const std::string& profile_name);
 
-// Decide if profile guided compilation is needed or not based on existing profiles.
+// Decides if profile guided compilation is needed or not based on existing profiles.
 // The analysis is done for a single profile name (which corresponds to a single code path).
-// Returns true if there is enough information in the current profiles that makes it
-// worth to recompile the package.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-bool analyze_primary_profiles(uid_t uid,
-                              const std::string& pkgname,
-                              const std::string& profile_name);
+//
+// Returns PROFILES_ANALYSIS_OPTIMIZE if there is enough information in the current profiles
+// that makes it worth to recompile the package.
+// If the return value is PROFILES_ANALYSIS_OPTIMIZE all the current profiles would have been
+// merged into the reference profiles accessible with open_reference_profile().
+//
+// Return PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA if the package should not optimize.
+// As a special case returns PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES if all profiles are
+// empty.
+int analyze_primary_profiles(uid_t uid,
+                             const std::string& pkgname,
+                             const std::string& profile_name);
 
 // Create a snapshot of the profile information for the given package profile.
 // If appId is -1, the method creates the profile snapshot for the boot image.
@@ -100,17 +107,18 @@
                          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);
+// Returns the total bytes that were freed, or -1 in case of errors.
+int64_t 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/file_parsing.h b/cmds/installd/file_parsing.h
index 3e2f815..88801ca 100644
--- a/cmds/installd/file_parsing.h
+++ b/cmds/installd/file_parsing.h
@@ -19,18 +19,14 @@
 
 #include <fstream>
 #include <functional>
-#include <string>
+#include <string_view>
+#include "android-base/unique_fd.h"
 
 namespace android {
 namespace installd {
 
-bool ParseFile(const std::string& strFile, std::function<bool (const std::string&)> parse) {
-    std::ifstream input_stream(strFile);
-
-    if (!input_stream.is_open()) {
-        return false;
-    }
-
+template<typename Func>
+bool ParseFile(std::istream& input_stream, Func parse) {
     while (!input_stream.eof()) {
         // Read the next line.
         std::string line;
@@ -54,6 +50,15 @@
     return true;
 }
 
+template<typename Func>
+bool ParseFile(std::string_view str_file, Func parse) {
+  std::ifstream ifs(str_file);
+  if (!ifs.is_open()) {
+    return false;
+  }
+  return ParseFile(ifs, parse);
+}
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index b5ee481..00d8441 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -77,6 +77,12 @@
 constexpr int FLAG_STORAGE_DE = 1 << 0;
 constexpr int FLAG_STORAGE_CE = 1 << 1;
 
+// TODO: import them from dexoptanalyzer.h
+// NOTE: keep in sync with Installer.java
+constexpr int PROFILES_ANALYSIS_OPTIMIZE                     = 1;
+constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA    = 2;
+constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3;
+
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 }  // namespace installd
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 18f8268..6aa32b8 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,18 +26,18 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 
 #include <android-base/logging.h>
 #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>
 
+#include "android-base/file.h"
 #include "dexopt.h"
 #include "file_parsing.h"
 #include "globals.h"
@@ -96,7 +96,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>
@@ -177,8 +177,10 @@
 private:
 
     bool ReadSystemProperties() {
+        // TODO This file does not have a stable format. It should be read by
+        // code shared by init and otapreopt. See b/181182967#comment80
         static constexpr const char* kPropertyFiles[] = {
-                "/default.prop", "/system/build.prop"
+                "/system/build.prop"
         };
 
         for (size_t i = 0; i < arraysize(kPropertyFiles); ++i) {
@@ -195,26 +197,61 @@
         //   export NAME VALUE
         // For simplicity, don't respect string quotation. The values we are interested in can be
         // encoded without them.
+        //
+        // init.environ.rc and derive_classpath all have the same format for
+        // environment variable exports (since they are all meant to be read by
+        // init) and can be matched by the same regex.
+
         std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
-        bool parse_result = ParseFile("/init.environ.rc", [&](const std::string& line) {
-            std::smatch export_match;
-            if (!std::regex_match(line, export_match, export_regex)) {
-                return true;
-            }
+        auto parse_results = [&](auto& input) {
+          ParseFile(input, [&](const std::string& line) {
+              std::smatch export_match;
+              if (!std::regex_match(line, export_match, export_regex)) {
+                  return true;
+              }
 
-            if (export_match.size() != 3) {
-                return true;
-            }
+              if (export_match.size() != 3) {
+                  return true;
+              }
 
-            std::string name = export_match[1].str();
-            std::string value = export_match[2].str();
+              std::string name = export_match[1].str();
+              std::string value = export_match[2].str();
 
-            system_properties_.SetProperty(name, value);
+              system_properties_.SetProperty(name, value);
 
-            return true;
-        });
-        if (!parse_result) {
+              return true;
+          });
+        };
+
+        // TODO Just like with the system-properties above we really should have
+        // common code between init and otapreopt to deal with reading these
+        // things. See b/181182967
+        // There have been a variety of places the various env-vars have been
+        // over the years.  Expand or reduce this list as needed.
+        static constexpr const char* kEnvironmentVariableSources[] = {
+                "/init.environ.rc",
+        };
+        // First get everything from the static files.
+        for (const char* env_vars_file : kEnvironmentVariableSources) {
+          parse_results(env_vars_file);
+        }
+
+        // Next get everything from derive_classpath, since we're already in the
+        // chroot it will get the new versions of any dependencies.
+        {
+          android::base::unique_fd fd(memfd_create("derive_classpath_temp", MFD_CLOEXEC));
+          if (!fd.ok()) {
+            LOG(ERROR) << "Unable to create fd for derive_classpath";
             return false;
+          }
+          std::string memfd_file = StringPrintf("/proc/%d/fd/%d", getpid(), fd.get());
+          std::string error_msg;
+          if (!Exec({"/apex/com.android.sdkext/bin/derive_classpath", memfd_file}, &error_msg)) {
+            PLOG(ERROR) << "Running derive_classpath failed: " << error_msg;
+            return false;
+          }
+          std::ifstream ifs(memfd_file);
+          parse_results(ifs);
         }
 
         if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
@@ -339,9 +376,6 @@
             }
         }
 
-        // Clear cached artifacts.
-        ClearDirectory(isa_path);
-
         // Check whether we have a boot image.
         // TODO: check that the files are correct wrt/ jars.
         std::string preopted_boot_art_path =
@@ -385,37 +419,6 @@
         return false;
     }
 
-    static void ClearDirectory(const std::string& dir) {
-        DIR* c_dir = opendir(dir.c_str());
-        if (c_dir == nullptr) {
-            PLOG(WARNING) << "Unable to open " << dir << " to delete it's contents";
-            return;
-        }
-
-        for (struct dirent* de = readdir(c_dir); de != nullptr; de = readdir(c_dir)) {
-            const char* name = de->d_name;
-            if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
-                continue;
-            }
-            // We only want to delete regular files and symbolic links.
-            std::string file = StringPrintf("%s/%s", dir.c_str(), name);
-            if (de->d_type != DT_REG && de->d_type != DT_LNK) {
-                LOG(WARNING) << "Unexpected file "
-                             << file
-                             << " of type "
-                             << std::hex
-                             << de->d_type
-                             << " encountered.";
-            } else {
-                // Try to unlink the file.
-                if (unlink(file.c_str()) != 0) {
-                    PLOG(ERROR) << "Unable to unlink " << file;
-                }
-            }
-        }
-        CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
-    }
-
     static const char* ParseNull(const char* arg) {
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
@@ -475,24 +478,29 @@
     // Run dexopt with the parameters of parameters_.
     // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
-        std::string dummy;
-        return dexopt(parameters_.apk_path,
-                      parameters_.uid,
-                      parameters_.pkgName,
-                      parameters_.instruction_set,
-                      parameters_.dexopt_needed,
-                      parameters_.oat_dir,
-                      parameters_.dexopt_flags,
-                      parameters_.compiler_filter,
-                      parameters_.volume_uuid,
-                      parameters_.shared_libraries,
-                      parameters_.se_info,
-                      parameters_.downgrade,
-                      parameters_.target_sdk_version,
-                      parameters_.profile_name,
-                      parameters_.dex_metadata_path,
-                      parameters_.compilation_reason,
-                      &dummy);
+        std::string error;
+        int res = dexopt(parameters_.apk_path,
+                         parameters_.uid,
+                         parameters_.pkgName,
+                         parameters_.instruction_set,
+                         parameters_.dexopt_needed,
+                         parameters_.oat_dir,
+                         parameters_.dexopt_flags,
+                         parameters_.compiler_filter,
+                         parameters_.volume_uuid,
+                         parameters_.shared_libraries,
+                         parameters_.se_info,
+                         parameters_.downgrade,
+                         parameters_.target_sdk_version,
+                         parameters_.profile_name,
+                         parameters_.dex_metadata_path,
+                         parameters_.compilation_reason,
+                         &error);
+        if (res != 0) {
+            LOG(ERROR) << "During preopt of " << parameters_.apk_path << " got result " << res
+                       << " error: " << error;
+        }
+        return res;
     }
 
     int RunPreopt() {
@@ -523,6 +531,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..c62734a 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -20,16 +20,19 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 
+#include <array>
+#include <fstream>
 #include <sstream>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <libdm/dm.h>
 #include <selinux/android.h>
 
-#include <apexd.h>
-
 #include "installd_constants.h"
 #include "otapreopt_utils.h"
 
@@ -59,28 +62,23 @@
     }
 }
 
-static std::vector<apex::ApexFile> ActivateApexPackages() {
-    // The logic here is (partially) copied and adapted from
-    // system/apex/apexd/apexd.cpp.
-    //
-    // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
-    std::vector<const char*> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
-                                       apex::kApexPackageVendorDir};
-    for (const auto& dir : apex_dirs) {
-        // Cast call to void to suppress warn_unused_result.
-        static_cast<void>(apex::scanPackagesDirAndActivate(dir));
+static void ActivateApexPackages() {
+    std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
+    std::string apexd_error_msg;
+
+    bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+    if (!exec_result) {
+        PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg;
+        exit(220);
     }
-    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);
-        if (!status.ok()) {
-            LOG(ERROR) << "Failed to deactivate " << package_path << ": "
-                       << status.error();
-        }
+static void DeactivateApexPackages() {
+    std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"};
+    std::string apexd_error_msg;
+    bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+    if (!exec_result) {
+        PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg;
     }
 }
 
@@ -181,6 +179,18 @@
     // want it for product APKs. Same notes as vendor above.
     TryExtraMount("product", arg[2], "/postinstall/product");
 
+    // Try to mount the system_ext partition. update_engine doesn't do this for
+    // us, but we want it for system_ext APKs. Same notes as vendor and product
+    // above.
+    TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+
+    constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
+    // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
+    if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) {
+        PLOG(ERROR) << "Failed to mount a tmpfs for " << kPostInstallLinkerconfig;
+        exit(215);
+    }
+
     // Setup APEX mount point and its security context.
     static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
     // The following logic is similar to the one in system/core/rootdir/init.rc:
@@ -236,20 +246,71 @@
         exit(205);
     }
 
+    // Call apexd --unmount-all to free up loop and dm block devices, so that we can re-use
+    // them during the next invocation. Since otapreopt_chroot calls exit in case something goes
+    // wrong we need to register our own atexit handler.
+    // We want to register this handler before actually activating apex packages. This is mostly
+    // due to the fact that if fail to unmount apexes, then on the next run of otapreopt_chroot
+    // we will ask for new loop devices instead of re-using existing ones, and we really don't want
+    // to do that. :)
+    if (atexit(DeactivateApexPackages) != 0) {
+        LOG(ERROR) << "Failed to register atexit hander";
+        exit(206);
+    }
+
     // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
     // the ART APEX, as it is required by otapreopt to run dex2oat.
-    std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
+    ActivateApexPackages();
 
+    auto cleanup = android::base::make_scope_guard([](){
+        std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"};
+        std::string apexd_error_msg;
+        bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+        if (!exec_result) {
+            PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg;
+        }
+    });
     // Check that an ART APEX has been activated; clean up and exit
     // early otherwise.
-    if (std::none_of(active_packages.begin(),
-                     active_packages.end(),
-                     [](const apex::ApexFile& package){
-                         return package.GetManifest().name() == "com.android.art";
-                     })) {
-        LOG(FATAL_WITHOUT_ABORT) << "No activated com.android.art APEX package.";
-        DeactivateApexPackages(active_packages);
-        exit(217);
+    static constexpr const std::string_view kRequiredApexs[] = {
+      "com.android.art",
+      "com.android.runtime",
+      "com.android.sdkext",  // For derive_classpath
+    };
+    std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
+    DIR* apex_dir = opendir("/apex");
+    if (apex_dir == nullptr) {
+        PLOG(ERROR) << "unable to open /apex";
+        exit(220);
+    }
+    for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) {
+        for (int i = 0; i < found_apexs.size(); i++) {
+            if (kRequiredApexs[i] == std::string_view(entry->d_name)) {
+                found_apexs[i] = true;
+                break;
+            }
+        }
+    }
+    closedir(apex_dir);
+    auto it = std::find(found_apexs.cbegin(), found_apexs.cend(), false);
+    if (it != found_apexs.cend()) {
+        LOG(ERROR) << "No activated " << kRequiredApexs[std::distance(found_apexs.cbegin(), it)]
+                   << " package!";
+        exit(221);
+    }
+
+    // Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
+    if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
+        PLOG(ERROR) << "Failed to restorecon /linkerconfig";
+        exit(219);
+    }
+    std::vector<std::string> linkerconfig_cmd{"/apex/com.android.runtime/bin/linkerconfig",
+                                              "--target", "/linkerconfig"};
+    std::string linkerconfig_error_msg;
+    bool linkerconfig_exec_result = Exec(linkerconfig_cmd, &linkerconfig_error_msg);
+    if (!linkerconfig_exec_result) {
+        LOG(ERROR) << "Running linkerconfig failed: " << linkerconfig_error_msg;
+        exit(218);
     }
 
     // Now go on and run otapreopt.
@@ -272,9 +333,6 @@
         LOG(ERROR) << "Running otapreopt failed: " << error_msg;
     }
 
-    // Tear down the work down by the apexd logic. (i.e. deactivate packages).
-    DeactivateApexPackages(active_packages);
-
     if (!exec_result) {
         exit(213);
     }
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
new file mode 100644
index 0000000..b661684
--- /dev/null
+++ b/cmds/installd/run_dex2oat.cpp
@@ -0,0 +1,386 @@
+/*
+ * 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) {
+    PrepareBootImageFlags(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::PrepareBootImageFlags(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);
+}
+
+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);
+            }
+        }
+    }
+
+    // On-device signing related. odsign sets the system property odsign.verification.success if
+    // AOT artifacts have the expected signatures.
+    const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+    if (!trust_art_apex_data_files) {
+        AddRuntimeArg("-Xdeny-art-apex-data-files");
+    }
+
+    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"));
+
+    // Enable compiling dex files in isolation on low ram devices.
+    // It takes longer but reduces the memory footprint.
+    if (GetBoolProperty("ro.config.low_ram", false)) {
+      AddArg("--compile-individually");
+    }
+}
+
+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..475e124
--- /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 PrepareBootImageFlags(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..0a638cd
--- /dev/null
+++ b/cmds/installd/run_dex2oat_test.cpp
@@ -0,0 +1,561 @@
+/*
+ * 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;
+
+        // 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, 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..7082017 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -1,4 +1,13 @@
 // Build the unit tests for installd
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_test {
     name: "installd_utils_test",
     test_suites: ["device-tests"],
@@ -11,6 +20,7 @@
         "libcutils",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
@@ -35,12 +45,28 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
         "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 {
@@ -60,12 +86,28 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
         "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 {
@@ -85,6 +127,7 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
@@ -93,6 +136,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 {
@@ -112,4 +170,3 @@
         "libotapreoptparameters"
     ],
 }
-
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..7e7e513 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -38,6 +38,7 @@
 #include "binder_test_utils.h"
 #include "dexopt.h"
 #include "InstalldNativeService.h"
+#include "installd_constants.h"
 #include "globals.h"
 #include "tests/test_utils.h"
 #include "utils.h"
@@ -193,7 +194,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 +222,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 +295,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";
@@ -351,38 +352,34 @@
             uid = kTestAppUid;
         }
         if (class_loader_context == nullptr) {
-            class_loader_context = "&";
+            class_loader_context = "PCL[]";
         }
-        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 +478,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 = "PCL[]";
         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) {
@@ -527,7 +518,8 @@
         // Check the access to the compiler output.
         //  - speed-profile artifacts are not world-wide readable.
         //  - files are owned by the system uid.
-        std::string odex = GetPrimaryDexArtifact(oat_dir, apk_path_, "odex");
+        std::string odex = GetPrimaryDexArtifact(oat_dir, apk_path_,
+                oat_dir == nullptr ? "dex" : "odex");
         std::string vdex = GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex");
         std::string art = GetPrimaryDexArtifact(oat_dir, apk_path_, "art");
 
@@ -555,7 +547,7 @@
                 }
             }
             return android_data_dir + DALVIK_CACHE + '/' + kRuntimeIsa + "/" + path
-                    + "@classes.dex";
+                    + "@classes." + type;
         } else {
             std::string::size_type name_end = dex_path.rfind('.');
             std::string::size_type name_start = dex_path.rfind('/');
@@ -563,6 +555,53 @@
                     dex_path.substr(name_start + 1, name_end - name_start) + type;
         }
     }
+
+    int64_t GetSize(const std::string& path) {
+        struct stat file_stat;
+        if (stat(path.c_str(), &file_stat) == 0) {
+            return static_cast<int64_t>(file_stat.st_size);
+        }
+        PLOG(ERROR) << "Cannot stat path: " << path;
+        return -1;
+    }
+
+    void TestDeleteOdex(bool in_dalvik_cache) {
+        const char* oat_dir = in_dalvik_cache ? nullptr : app_oat_dir_.c_str();
+        CompilePrimaryDexOk(
+                "speed-profile",
+                DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC
+                        | DEXOPT_GENERATE_APP_IMAGE,
+                oat_dir,
+                kTestAppGid,
+                DEX2OAT_FROM_SCRATCH,
+                /*binder_result=*/nullptr,
+                empty_dm_file_.c_str());
+
+
+        int64_t odex_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_,
+                in_dalvik_cache ? "dex" : "odex"));
+        int64_t vdex_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_, "vdex"));
+        int64_t art_size = GetSize(GetPrimaryDexArtifact(oat_dir, apk_path_, "art"));
+
+        LOG(ERROR) << "test odex " << odex_size;
+        LOG(ERROR) << "test vdex_size " << vdex_size;
+        LOG(ERROR) << "test art_size " << art_size;
+        int64_t expected_bytes_freed = odex_size + vdex_size + art_size;
+
+        int64_t bytes_freed;
+        binder::Status result = service_->deleteOdex(
+            apk_path_,
+            kRuntimeIsa,
+            in_dalvik_cache ? std::nullopt : std::make_optional<std::string>(app_oat_dir_.c_str()),
+            &bytes_freed);
+        ASSERT_TRUE(result.isOk()) << result.toString8().c_str();
+
+        ASSERT_GE(odex_size, 0);
+        ASSERT_GE(vdex_size, 0);
+        ASSERT_GE(art_size, 0);
+
+        ASSERT_EQ(expected_bytes_freed, bytes_freed);
+    }
 };
 
 
@@ -673,7 +712,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) {
@@ -711,6 +750,16 @@
                         empty_dm_file_.c_str());
 }
 
+TEST_F(DexoptTest, DeleteDexoptArtifactsData) {
+    LOG(INFO) << "DeleteDexoptArtifactsData";
+    TestDeleteOdex(/*in_dalvik_cache=*/ false);
+}
+
+TEST_F(DexoptTest, DeleteDexoptArtifactsDalvikCache) {
+    LOG(INFO) << "DeleteDexoptArtifactsDalvikCache";
+    TestDeleteOdex(/*in_dalvik_cache=*/ true);
+}
+
 TEST_F(DexoptTest, ResolveStartupConstStrings) {
     LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
     const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
@@ -929,7 +978,7 @@
             return;
         }
 
-        // Check that the snapshot was created witht he expected acess flags.
+        // Check that the snapshot was created with the expected access flags.
         CheckFileAccess(snap_profile_, kSystemUid, kSystemGid, 0600 | S_IFREG);
 
         // The snapshot should be equivalent to the merge of profiles.
@@ -961,19 +1010,19 @@
 
     void mergePackageProfiles(const std::string& package_name,
                               const std::string& code_path,
-                              bool expected_result) {
-        bool result;
+                              int expected_result) {
+        int result;
         ASSERT_BINDER_SUCCESS(service_->mergeProfiles(
                 kTestAppUid, package_name, code_path, &result));
         ASSERT_EQ(expected_result, result);
 
-        if (!expected_result) {
-            // Do not check the files if we expect to fail.
+        // There's nothing to check if the files are empty.
+        if (result == PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES) {
             return;
         }
 
-        // Check that the snapshot was created witht he expected acess flags.
-        CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+        // Check that the snapshot was created with the expected access flags.
+        CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0640 | S_IFREG);
 
         // The snapshot should be equivalent to the merge of profiles.
         std::string ref_profile_content = ref_profile_ + ".expected";
@@ -992,7 +1041,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) {
@@ -1087,7 +1136,7 @@
     LOG(INFO) << "ProfileMergeOk";
 
     SetupProfiles(/*setup_ref*/ true);
-    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
+    mergePackageProfiles(package_name_, "primary.prof", PROFILES_ANALYSIS_OPTIMIZE);
 }
 
 // The reference profile is created on the fly. We need to be able to
@@ -1096,14 +1145,15 @@
     LOG(INFO) << "ProfileMergeOkNoReference";
 
     SetupProfiles(/*setup_ref*/ false);
-    mergePackageProfiles(package_name_, "primary.prof", /*expected_result*/ true);
+    mergePackageProfiles(package_name_, "primary.prof", PROFILES_ANALYSIS_OPTIMIZE);
 }
 
 TEST_F(ProfileTest, ProfileMergeFailWrongPackage) {
     LOG(INFO) << "ProfileMergeFailWrongPackage";
 
     SetupProfiles(/*setup_ref*/ true);
-    mergePackageProfiles("not.there", "primary.prof", /*expected_result*/ false);
+    mergePackageProfiles("not.there", "primary.prof",
+            PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES);
 }
 
 TEST_F(ProfileTest, ProfileDirOk) {
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/installd/utils.cpp b/cmds/installd/utils.cpp
index c47df52..c4ecd07 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1062,6 +1062,8 @@
 
 static const char* kProcFilesystems = "/proc/filesystems";
 bool supports_sdcardfs() {
+    if (!property_get_bool("external_storage.sdcardfs.enabled", true))
+        return false;
     std::string supported;
     if (!android::base::ReadFileToString(kProcFilesystems, &supported)) {
         PLOG(ERROR) << "Failed to read supported filesystems";
diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk
index e1e2204..396ae9d 100644
--- a/cmds/ip-up-vpn/Android.mk
+++ b/cmds/ip-up-vpn/Android.mk
@@ -21,6 +21,9 @@
 LOCAL_CFLAGS := -Wall -Werror
 LOCAL_SHARED_LIBRARIES := libcutils liblog
 LOCAL_MODULE := ip-up-vpn
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
 LOCAL_MODULE_TAGS := optional
 
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 5afae4b..649e53a 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,10 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "liblshal",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -47,6 +57,7 @@
     name: "lshal_defaults",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -72,15 +83,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..ccf1ab1 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -28,7 +28,7 @@
 }
 
 std::string DebugCommand::getSimpleDescription() const {
-    return "Debug a specified HAL.";
+    return "Debug a specified HIDL HAL.";
 }
 
 Status DebugCommand::parseArgs(const Arg &arg) {
@@ -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());
 }
@@ -78,7 +78,7 @@
             "debug:\n"
             "    lshal debug [-E] <interface> [options [options [...]]] \n"
             "        Print debug information of a specified interface.\n"
-            "        -E: excludes debug output if HAL is actually a subclass.\n"
+            "        -E: excludes debug output if HIDL HAL is actually a subclass.\n"
             "        <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
             "            If instance name is missing `default` is used.\n"
             "        options: space separated options to IBase::debug.\n";
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..2722e21 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>
@@ -82,7 +81,7 @@
     return "list";
 }
 std::string ListCommand::getSimpleDescription() const {
-    return "List HALs.";
+    return "List HIDL HALs.";
 }
 
 std::string ListCommand::parseCmdline(pid_t pid) const {
@@ -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;
@@ -379,21 +295,21 @@
     }
 
     mServicesTable.setDescription(
-            "| All binderized services (registered with hwservicemanager)");
+            "| All HIDL binderized services (registered with hwservicemanager)");
     mPassthroughRefTable.setDescription(
-            "| All interfaces that getService() has ever returned as a passthrough interface;\n"
+            "| All HIDL interfaces getService() has ever returned as a passthrough interface;\n"
             "| PIDs / processes shown below might be inaccurate because the process\n"
             "| might have relinquished the interface or might have died.\n"
             "| The Server / Server CMD column can be ignored.\n"
             "| The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
             "| the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "| All available passthrough implementations (all -impl.so files).\n"
+            "| All available HIDL passthrough implementations (all -impl.so files).\n"
             "| These may return subclasses through their respective HIDL_FETCH_I* functions.");
     mManifestHalsTable.setDescription(
-            "| All HALs that are in VINTF manifest.");
+            "| All HIDL HALs that are in VINTF manifest.");
     mLazyHalsTable.setDescription(
-            "| All HALs that are declared in VINTF manifest:\n"
+            "| All HIDL HALs that are declared in VINTF manifest:\n"
             "|    - as hwbinder HALs but are not registered to hwservicemanager, and\n"
             "|    - as hwbinder/passthrough HALs with no implementation.");
 }
@@ -501,7 +417,7 @@
         }
     }
     out << "-->" << std::endl;
-    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlags::HALS_ONLY);
+    out << vintf::toXml(manifest, vintf::SerializeFlags::HALS_ONLY);
 }
 
 std::string ListCommand::INIT_VINTF_NOTES{
@@ -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
@@ -975,11 +903,11 @@
         thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
         return OK;
     }, "print VINTF info. This column contains a comma-separated list of:\n"
-       "    - DM: if the HAL is in the device manifest\n"
-       "    - DC: if the HAL is in the device compatibility matrix\n"
-       "    - FM: if the HAL is in the framework manifest\n"
-       "    - FC: if the HAL is in the framework compatibility matrix\n"
-       "    - X: if the HAL is in none of the above lists"});
+       "    - DM: if the HIDL HAL is in the device manifest\n"
+       "    - DC: if the HIDL HAL is in the device compatibility matrix\n"
+       "    - FM: if the HIDL HAL is in the framework manifest\n"
+       "    - FC: if the HIDL HAL is in the framework compatibility matrix\n"
+       "    - X: if the HIDL HAL is in none of the above lists"});
     mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
         return OK;
@@ -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..bc99f4d 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -59,7 +59,8 @@
 }
 
 void Lshal::usage() {
-    err() << "lshal: List and debug HALs." << std::endl << std::endl
+    err() << "lshal: List and debug HIDL HALs." << std::endl
+          << "   (for AIDL HALs, see `dumpsys`)" << std::endl << std::endl
           << "commands:" << std::endl;
 
     size_t nameMaxLength = 0;
@@ -101,7 +102,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 +127,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 +135,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/WaitCommand.cpp b/cmds/lshal/WaitCommand.cpp
index 65b41b9..437a66a 100644
--- a/cmds/lshal/WaitCommand.cpp
+++ b/cmds/lshal/WaitCommand.cpp
@@ -29,7 +29,7 @@
 }
 
 std::string WaitCommand::getSimpleDescription() const {
-    return "Wait for HAL to start if it is not already started.";
+    return "Wait for HIDL HAL to start if it is not already started.";
 }
 
 Status WaitCommand::parseArgs(const Arg &arg) {
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index 9592111..cbfbdc9 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_library_static {
     name: "libprocpartition",
     shared_libs: [
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 3d550ba..6f08f74 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,10 +44,9 @@
 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;
-using android::vintf::gHalManifestConverter;
 using android::vintf::HalManifest;
 using android::vintf::Transport;
 using android::vintf::VintfObject;
@@ -59,10 +58,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 +79,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 +88,7 @@
 
 } // namespace implementation
 } // namespace V1_0
-} // namespace baz
+} // namespace inheritance
 } // namespace tests
 } // namespace hardware
 
@@ -124,18 +127,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 +168,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 +189,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 +231,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 +297,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 +361,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 +477,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 +496,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"})));
@@ -483,10 +506,10 @@
     EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
     EXPECT_EQ("", err.str());
 
+    std::string error;
     vintf::HalManifest m;
-    EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
-        << "--init-vintf does not emit valid HAL manifest: "
-        << vintf::gHalManifestConverter.lastError();
+    EXPECT_EQ(true, vintf::fromXml(&m, out.str(), &error))
+        << "--init-vintf does not emit valid HAL manifest: " << error;
 }
 
 // test default columns
@@ -681,8 +704,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) {
@@ -750,10 +773,10 @@
     auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
     auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
 
-    ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
-    ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
-    ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
-    ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
+    ASSERT_TRUE(fromXml(deviceManifest.get(), deviceManifestXml));
+    ASSERT_TRUE(fromXml(frameworkManifest.get(), frameworkManifestXml));
+    ASSERT_TRUE(fromXml(deviceMatrix.get(), deviceMatrixXml));
+    ASSERT_TRUE(fromXml(frameworkMatrix.get(), frameworkMatrixXml));
 
     ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
     ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
@@ -766,6 +789,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 {
@@ -789,7 +962,7 @@
                 "    </hal>\n"
                 "</manifest>";
         auto manifest = std::make_shared<HalManifest>();
-        EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
+        EXPECT_TRUE(fromXml(manifest.get(), mockManifestXml));
         EXPECT_CALL(*mockList, getDeviceManifest())
             .Times(AnyNumber())
             .WillRepeatedly(Return(manifest));
diff --git a/cmds/rawbu/Android.bp b/cmds/rawbu/Android.bp
index 363ffc1..e34119d 100644
--- a/cmds/rawbu/Android.bp
+++ b/cmds/rawbu/Android.bp
@@ -1,5 +1,22 @@
 // Copyright 2009 The Android Open Source Project
 
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_rawbu_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_rawbu_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "rawbu",
 
diff --git a/cmds/rss_hwm_reset/Android.bp b/cmds/rss_hwm_reset/Android.bp
index 15f10ef..cd335d4 100644
--- a/cmds/rss_hwm_reset/Android.bp
+++ b/cmds/rss_hwm_reset/Android.bp
@@ -12,6 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_binary {
     name: "rss_hwm_reset",
 
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index a5b1ac5..3e8e3f6 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -1,3 +1,20 @@
+package {
+    default_applicable_licenses: ["frameworks_native_cmds_service_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+    name: "frameworks_native_cmds_service_license",
+    visibility: [":__subpackages__"],
+    license_kinds: [
+        "SPDX-license-identifier-Apache-2.0",
+    ],
+    license_text: [
+        "NOTICE",
+    ],
+}
+
 cc_binary {
     name: "service",
 
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 7277e85..3ebdeee 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -1,3 +1,12 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
 cc_defaults {
     name: "servicemanager_defaults",
 
@@ -5,6 +14,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
 
     srcs: [
@@ -44,6 +54,9 @@
     cflags: [
         "-DVENDORSERVICEMANAGER=1",
     ],