Merge "Increase the level of depth of apk paths"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 36a53bb..db297a0 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -13,10 +13,12 @@
                libs/renderengine/
                libs/ui/
                libs/vr/
+               opengl/libs/
                services/bufferhub/
                services/inputflinger/
                services/surfaceflinger/
                services/vr/
+               vulkan/
 
 [Hook Scripts]
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
diff --git a/aidl/binder/android/os/PersistableBundle.aidl b/aidl/binder/android/os/PersistableBundle.aidl
index 94e8607..493ecb4 100644
--- a/aidl/binder/android/os/PersistableBundle.aidl
+++ b/aidl/binder/android/os/PersistableBundle.aidl
@@ -17,4 +17,4 @@
 
 package android.os;
 
-parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
+@JavaOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
diff --git a/build/phone-xhdpi-2048-dalvik-heap.mk b/build/phone-xhdpi-2048-dalvik-heap.mk
index 042a6e6..7ccfc13 100644
--- a/build/phone-xhdpi-2048-dalvik-heap.mk
+++ b/build/phone-xhdpi-2048-dalvik-heap.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-# Provides overrides to configure the Dalvik heap for a 2G phone
+# 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 += \
diff --git a/build/phone-xhdpi-4096-dalvik-heap.mk b/build/phone-xhdpi-4096-dalvik-heap.mk
new file mode 100644
index 0000000..2b84841
--- /dev/null
+++ b/build/phone-xhdpi-4096-dalvik-heap.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 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.
+#
+
+# 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
diff --git a/build/phone-xhdpi-6144-dalvik-heap.mk b/build/phone-xhdpi-6144-dalvik-heap.mk
new file mode 100644
index 0000000..2bacc4a
--- /dev/null
+++ b/build/phone-xhdpi-6144-dalvik-heap.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 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.
+#
+
+# 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
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5186ad3..cf75bba 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -854,7 +854,6 @@
             tags |= c.tags;
         }
     }
-    ok &= setTagsProperty(tags);
 
     bool coreServicesTagEnabled = false;
     for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -876,9 +875,11 @@
         packageList += android::base::GetProperty(k_coreServicesProp, "");
     }
     ok &= setAppCmdlineProperty(&packageList[0]);
+    ok &= setTagsProperty(tags);
+#if !ATRACE_SHMEM
     ok &= pokeBinderServices();
     pokeHalServices();
-
+#endif
     if (g_tracePdx) {
         ok &= ServiceUtility::PokeServices();
     }
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 7b4aeb2..8dad475 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -223,7 +223,8 @@
     sp<MyResultReceiver> result = new MyResultReceiver();
 
 #if DEBUG
-    ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", cmd, in, out, err);
+    ALOGD("cmd: Invoking %.*s in=%d, out=%d, err=%d",
+          static_cast<int>(cmd.size()), cmd.data(), in, out, err);
 #endif
 
     // TODO: block until a result is returned to MyResultReceiver.
diff --git a/cmds/dumpstate/DumpstateInternal.h b/cmds/dumpstate/DumpstateInternal.h
index 10db5d6..c1ec55e 100644
--- a/cmds/dumpstate/DumpstateInternal.h
+++ b/cmds/dumpstate/DumpstateInternal.h
@@ -49,6 +49,7 @@
 
 // TODO: use functions from <chrono> instead
 const uint64_t NANOS_PER_SEC = 1000000000;
+const uint64_t NANOS_PER_MILLI = 1000000;
 uint64_t Nanotime();
 
 // Switches to non-root user and group.
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index f98df99..10d3d17 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -115,8 +115,8 @@
 
 binder::Status DumpstateService::startBugreport(int32_t calling_uid,
                                                 const std::string& calling_package,
-                                                const android::base::unique_fd& bugreport_fd,
-                                                const android::base::unique_fd& screenshot_fd,
+                                                android::base::unique_fd bugreport_fd,
+                                                android::base::unique_fd screenshot_fd,
                                                 int bugreport_mode,
                                                 const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 68eda47..aaaa428 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -43,8 +43,8 @@
                                sp<IDumpstateToken>* returned_token) override;
 
     binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
-                                  const android::base::unique_fd& bugreport_fd,
-                                  const android::base::unique_fd& screenshot_fd, int bugreport_mode,
+                                  android::base::unique_fd bugreport_fd,
+                                  android::base::unique_fd screenshot_fd, int bugreport_mode,
                                   const sp<IDumpstateListener>& listener) override;
 
     // No-op
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c5bfb42..585a98e 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -660,7 +660,7 @@
 }
 
 uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
-    return Nanotime() - start_time_;
+    return (Nanotime() - start_time_) / NANOS_PER_MILLI;
 }
 
 void Dumpstate::PrintHeader() const {
@@ -2913,15 +2913,13 @@
 DurationReporter::~DurationReporter() {
     if (!title_.empty()) {
         float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
-        if (elapsed < .5f && !verbose_) {
-            return;
+        if (elapsed >= .5f || verbose_) {
+            MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
         }
-        MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
-        if (logcat_only_) {
-            return;
+        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());
         }
-        // Use "Yoda grammar" to make it easier to grep|sort sections.
-        printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
     }
 }
 
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 7e6f6f5..256dc05 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -449,7 +449,7 @@
 
     sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
     android::binder::Status status =
-        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+        ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
                                   Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
     // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
     // gets expected callbacks.
@@ -485,7 +485,7 @@
     // Call startBugreport with bad arguments.
     sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
     android::binder::Status status =
-        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+        ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
                                   2000,  // invalid bugreport mode
                                   listener);
     EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
@@ -506,20 +506,24 @@
 
     // Prepare arguments
     unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd bugreport_fd2(dup(bugreport_fd.get()));
     unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+    unique_fd screenshot_fd2(dup(screenshot_fd.get()));
 
     EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(bugreport_fd2.get(), -1);
     EXPECT_NE(screenshot_fd.get(), -1);
+    EXPECT_NE(screenshot_fd2.get(), -1);
 
     sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
     android::binder::Status status =
-        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+        ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
                                   Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
     EXPECT_TRUE(status.isOk());
 
     // try to make another call to startBugreport. This should fail.
     sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
-    status = ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+    status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2),
                                        Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
     EXPECT_FALSE(status.isOk());
     WaitTillExecutionComplete(listener2.get());
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index abdf168..5597bcd 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -364,7 +364,7 @@
         }
 
         if (err != OK) {
-            aerr << "Error dumping service info status_t: (" << err << ") "
+            aerr << "Error dumping service info status_t: " << statusToString(err) << " "
                  << serviceName << endl;
         }
     });
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 5476319..402767a 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -15,20 +15,21 @@
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
+        "android.hardware.vibrator-ndk_platform",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
         "libbase",
-        "libbinder",
+        "libbinder_ndk",
         "libhidlbase",
         "liblog",
         "libutils",
-        "vintf-vibrator-cpp",
     ],
     cflags: [
         "-DLOG_TAG=\"idlcli\"",
     ],
+    vendor_available: true,
 }
 
 cc_library {
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index 2f11923..ca5142d 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -13,13 +13,12 @@
  * 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_
 
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <android/binder_manager.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
 
 #include "utils.h"
 
@@ -39,22 +38,27 @@
 }
 
 template <>
-inline binder::Status NullptrStatus() {
-    using binder::Status;
-    return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+inline ndk::ScopedAStatus NullptrStatus() {
+    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NULL_POINTER));
 }
 
 template <typename I>
-inline sp<I> getService() {
+inline auto getService() {
     return I::getService();
 }
 
 template <>
-inline sp<hardware::vibrator::IVibrator> getService() {
-    return waitForVintfService<hardware::vibrator::IVibrator>();
+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);
 }
 
 template <typename I>
+using shared_ptr = std::result_of_t<decltype(getService<I>)&()>;
+
+template <typename I>
 class HalWrapper {
 public:
     static std::unique_ptr<HalWrapper> Create() {
@@ -70,10 +74,10 @@
     }
 
 private:
-    HalWrapper(sp<I>&& hal) : mHal(std::move(hal)) {}
+    HalWrapper(shared_ptr<I>&& hal) : mHal(std::move(hal)) {}
 
 private:
-    sp<I> mHal;
+    shared_ptr<I> mHal;
 };
 
 template <typename I>
@@ -95,7 +99,7 @@
 namespace V1_1 = ::android::hardware::vibrator::V1_1;
 namespace V1_2 = ::android::hardware::vibrator::V1_2;
 namespace V1_3 = ::android::hardware::vibrator::V1_3;
-namespace aidl = ::android::hardware::vibrator;
+namespace aidl = ::aidl::android::hardware::vibrator;
 
 } // namespace vibrator
 } // namespace idlcli
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 705e40b..4721a5f 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -80,7 +80,7 @@
         Status ret;
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else {
             return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
index 30d8587..303a989 100644
--- a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
@@ -48,7 +48,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else {
             return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
index b414307..10508bd 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
@@ -50,7 +50,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else {
             return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
index 360fc9d..900cb18 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
@@ -50,7 +50,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else {
             return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp
index 53fada0..cedb9fe 100644
--- a/cmds/idlcli/vibrator/CommandOff.cpp
+++ b/cmds/idlcli/vibrator/CommandOff.cpp
@@ -47,7 +47,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::off);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_0::IVibrator>()) {
             auto status = hal->call(&V1_0::IVibrator::off);
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index ccb3c19..4e7e493 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -55,7 +55,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_0::IVibrator>()) {
             auto status = hal->call(&V1_0::IVibrator::on, mDuration);
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index 58d4e0a..69c7e37 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -99,7 +99,7 @@
             auto status =
                     hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect),
                               static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             lengthMs = static_cast<uint32_t>(aidlLengthMs);
             ret = status.isOk() ? OK : ERROR;
         } else {
diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
index 33d7eed..8b8058c 100644
--- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
+++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
@@ -56,7 +56,7 @@
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::setAmplitude,
                                     static_cast<float>(mAmplitude) / UINT8_MAX);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_0::IVibrator>()) {
             auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude);
diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
index 5bc827e..1795793 100644
--- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
@@ -53,7 +53,7 @@
 
         if (auto hal = getHal<aidl::IVibrator>()) {
             auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable);
-            statusStr = status.toString8();
+            statusStr = status.getDescription();
             ret = status.isOk() ? OK : ERROR;
         } else if (auto hal = getHal<V1_3::IVibrator>()) {
             auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable);
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b23d69c..0fde31a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -103,6 +103,9 @@
 static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
 static constexpr const char* kFuseProp = "persist.sys.fuse";
 
+static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/";
+static constexpr const char* kMntFuse = "/mnt/pass_through/0/";
+
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -626,10 +629,8 @@
                 if (delete_dir_contents(path, true) != 0) {
                     res = error("Failed to delete contents of " + path);
                 }
-                path = StringPrintf("%s/Android/obb/%s", extPath.c_str(), pkgname);
-                if (delete_dir_contents(path, true) != 0) {
-                    res = error("Failed to delete contents of " + path);
-                }
+                // Note that we explicitly don't delete OBBs - those are only removed on
+                // app uninstall.
             }
         }
     }
@@ -2625,7 +2626,7 @@
 #endif
 
 binder::Status InstalldNativeService::installApkVerity(const std::string& filePath,
-        const ::android::base::unique_fd& verityInputAshmem, int32_t contentSize) {
+        android::base::unique_fd verityInputAshmem, int32_t contentSize) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PATH(filePath);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -2799,13 +2800,13 @@
         std::getline(in, ignored);
 
         if (android::base::GetBoolProperty(kFuseProp, false)) {
-            if (target.compare(0, 17, "/mnt/pass_through") == 0) {
+            if (target.find(kMntFuse) == 0) {
                 LOG(DEBUG) << "Found storage mount " << source << " at " << target;
                 mStorageMounts[source] = target;
             }
         } else {
 #if !BYPASS_SDCARDFS
-            if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
+            if (target.find(kMntSdcardfs) == 0) {
                 LOG(DEBUG) << "Found storage mount " << source << " at " << target;
                 mStorageMounts[source] = target;
             }
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 2b7bf33..149936d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -136,7 +136,7 @@
     binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
             const std::unique_ptr<std::string>& outputPath);
     binder::Status installApkVerity(const std::string& filePath,
-            const ::android::base::unique_fd& verityInput, int32_t contentSize);
+            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,
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index b238dd3..f2abf3a 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -97,6 +97,26 @@
     }
 }
 
+int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId) {
+    const std::string device = FindQuotaDeviceForUuid(uuid);
+    if (device == "") {
+        return -1;
+    }
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, PRJQUOTA), device.c_str(), projectId,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        if (errno != ESRCH) {
+            PLOG(ERROR) << "Failed to quotactl " << device << " for Project ID " << projectId;
+        }
+        return -1;
+    } else {
+#if MEASURE_DEBUG
+        LOG(DEBUG) << "quotactl() for Project ID " << projectId << " " << dq.dqb_curspace;
+#endif
+        return dq.dqb_curspace;
+    }
+}
+
 int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) {
     const std::string device = FindQuotaDeviceForUuid(uuid);
     if (device == "") {
diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h
index 9ad170f..96aca04 100644
--- a/cmds/installd/QuotaUtils.h
+++ b/cmds/installd/QuotaUtils.h
@@ -35,6 +35,8 @@
 /* Get the current occupied space in bytes for a gid or -1 if fails */
 int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid);
 
+/* Get the current occupied space in bytes for a project id or -1 if fails */
+int64_t GetOccupiedSpaceForProjectId(const std::string& uuid, int projectId);
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 26e9984..d99bcc8 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -127,4 +127,6 @@
 
     const int FLAG_USE_QUOTA = 0x1000;
     const int FLAG_FORCE = 0x2000;
+
+    const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000;
 }
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 141171b..ae74ac3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -18,6 +18,9 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
 #include <binder/Stability.h>
 #include <cutils/android_filesystem_config.h>
 #include <cutils/multiuser.h>
@@ -80,7 +83,7 @@
 ServiceManager::~ServiceManager() {
     // this should only happen in tests
 
-    for (const auto& [name, callbacks] : mNameToCallback) {
+    for (const auto& [name, callbacks] : mNameToRegistrationCallback) {
         CHECK(!callbacks.empty()) << name;
         for (const auto& callback : callbacks) {
             CHECK(callback != nullptr) << name;
@@ -108,10 +111,11 @@
     auto ctx = mAccess->getCallingContext();
 
     sp<IBinder> out;
+    Service* service = nullptr;
     if (auto it = mNameToService.find(name); it != mNameToService.end()) {
-        const Service& service = it->second;
+        service = &(it->second);
 
-        if (!service.allowIsolated) {
+        if (!service->allowIsolated) {
             uid_t appid = multiuser_get_app_id(ctx.uid);
             bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;
 
@@ -119,7 +123,7 @@
                 return nullptr;
             }
         }
-        out = service.binder;
+        out = service->binder;
     }
 
     if (!mAccess->canFind(ctx, name)) {
@@ -130,6 +134,12 @@
         tryStartService(name);
     }
 
+    if (out) {
+        // Setting this guarantee each time we hand out a binder ensures that the client-checking
+        // loop knows about the event even if the client immediately drops the service
+        service->guaranteeClient = true;
+    }
+
     return out;
 }
 
@@ -182,15 +192,17 @@
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
     }
 
-    mNameToService[name] = Service {
+    auto entry = mNameToService.emplace(name, Service {
         .binder = binder,
         .allowIsolated = allowIsolated,
         .dumpPriority = dumpPriority,
-    };
+        .debugPid = ctx.debugPid,
+    });
 
-    auto it = mNameToCallback.find(name);
-    if (it != mNameToCallback.end()) {
+    auto it = mNameToRegistrationCallback.find(name);
+    if (it != mNameToRegistrationCallback.end()) {
         for (const sp<IServiceCallback>& cb : it->second) {
+            entry.first->second.guaranteeClient = true;
             // permission checked in registerForNotifications
             cb->onRegistration(name, binder);
         }
@@ -247,7 +259,7 @@
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
     }
 
-    mNameToCallback[name].push_back(callback);
+    mNameToRegistrationCallback[name].push_back(callback);
 
     if (auto it = mNameToService.find(name); it != mNameToService.end()) {
         const sp<IBinder>& binder = it->second.binder;
@@ -269,9 +281,9 @@
 
     bool found = false;
 
-    auto it = mNameToCallback.find(name);
-    if (it != mNameToCallback.end()) {
-        removeCallback(IInterface::asBinder(callback), &it, &found);
+    auto it = mNameToRegistrationCallback.find(name);
+    if (it != mNameToRegistrationCallback.end()) {
+        removeRegistrationCallback(IInterface::asBinder(callback), &it, &found);
     }
 
     if (!found) {
@@ -297,8 +309,8 @@
     return Status::ok();
 }
 
-void ServiceManager::removeCallback(const wp<IBinder>& who,
-                                    CallbackMap::iterator* it,
+void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
+                                    ServiceCallbackMap::iterator* it,
                                     bool* found) {
     std::vector<sp<IServiceCallback>>& listeners = (*it)->second;
 
@@ -312,7 +324,7 @@
     }
 
     if (listeners.empty()) {
-        *it = mNameToCallback.erase(*it);
+        *it = mNameToRegistrationCallback.erase(*it);
     } else {
         (*it)++;
     }
@@ -327,8 +339,12 @@
         }
     }
 
-    for (auto it = mNameToCallback.begin(); it != mNameToCallback.end();) {
-        removeCallback(who, &it, nullptr /*found*/);
+    for (auto it = mNameToRegistrationCallback.begin(); it != mNameToRegistrationCallback.end();) {
+        removeRegistrationCallback(who, &it, nullptr /*found*/);
+    }
+
+    for (auto it = mNameToClientCallback.begin(); it != mNameToClientCallback.end();) {
+        removeClientCallback(who, &it);
     }
 }
 
@@ -341,4 +357,183 @@
     }).detach();
 }
 
-}  // namespace android
+Status ServiceManager::registerClientCallback(const std::string& name, const sp<IBinder>& service,
+                                              const sp<IClientCallback>& cb) {
+    if (cb == nullptr) {
+        return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+    }
+
+    auto ctx = mAccess->getCallingContext();
+    if (!mAccess->canAdd(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    auto serviceIt = mNameToService.find(name);
+    if (serviceIt == mNameToService.end()) {
+        LOG(ERROR) << "Could not add callback for nonexistent service: " << name;
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+
+    if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+        LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")";
+        return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
+    }
+
+    if (serviceIt->second.binder != service) {
+        LOG(WARNING) << "Tried to register client callback for " << name
+            << " but a different service is registered under this name.";
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+
+    if (OK != IInterface::asBinder(cb)->linkToDeath(this)) {
+        LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name;
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+
+    mNameToClientCallback[name].push_back(cb);
+
+    return Status::ok();
+}
+
+void ServiceManager::removeClientCallback(const wp<IBinder>& who,
+                                          ClientCallbackMap::iterator* it) {
+    std::vector<sp<IClientCallback>>& listeners = (*it)->second;
+
+    for (auto lit = listeners.begin(); lit != listeners.end();) {
+        if (IInterface::asBinder(*lit) == who) {
+            lit = listeners.erase(lit);
+        } else {
+            ++lit;
+        }
+    }
+
+    if (listeners.empty()) {
+        *it = mNameToClientCallback.erase(*it);
+    } else {
+        (*it)++;
+    }
+}
+
+ssize_t ServiceManager::Service::getNodeStrongRefCount() {
+    sp<BpBinder> bpBinder = binder->remoteBinder();
+    if (bpBinder == nullptr) return -1;
+
+    return ProcessState::self()->getStrongRefCountForNodeByHandle(bpBinder->handle());
+}
+
+void ServiceManager::handleClientCallbacks() {
+    for (const auto& [name, service] : mNameToService) {
+        handleServiceClientCallback(name);
+    }
+}
+
+ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) {
+    auto serviceIt = mNameToService.find(serviceName);
+    if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {
+        return -1;
+    }
+
+    Service& service = serviceIt->second;
+    ssize_t count = service.getNodeStrongRefCount();
+
+    // binder driver doesn't support this feature
+    if (count == -1) return count;
+
+    bool hasClients = count > 1; // this process holds a strong count
+
+    if (service.guaranteeClient) {
+        // we have no record of this client
+        if (!service.hasClients && !hasClients) {
+            sendClientCallbackNotifications(serviceName, true);
+        }
+
+        // guarantee is temporary
+        service.guaranteeClient = false;
+    }
+
+    if (hasClients && !service.hasClients) {
+        // client was retrieved in some other way
+        sendClientCallbackNotifications(serviceName, true);
+    }
+
+    // there are no more clients, but the callback has not been called yet
+    if (!hasClients && service.hasClients) {
+        sendClientCallbackNotifications(serviceName, false);
+    }
+
+    return count;
+}
+
+void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) {
+    auto serviceIt = mNameToService.find(serviceName);
+    if (serviceIt == mNameToService.end()) {
+        LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName;
+        return;
+    }
+    Service& service = serviceIt->second;
+
+    CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients
+        << " so we can't tell clients again that we have client: " << hasClients;
+
+    LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients;
+
+    auto ccIt = mNameToClientCallback.find(serviceName);
+    CHECK(ccIt != mNameToClientCallback.end())
+        << "sendClientCallbackNotifications could not find callbacks for service ";
+
+    for (const auto& callback : ccIt->second) {
+        callback->onClients(service.binder, hasClients);
+    }
+
+    service.hasClients = hasClients;
+}
+
+Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IBinder>& binder) {
+    if (binder == nullptr) {
+        return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+    }
+
+    auto ctx = mAccess->getCallingContext();
+    if (!mAccess->canAdd(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    auto serviceIt = mNameToService.find(name);
+    if (serviceIt == mNameToService.end()) {
+        LOG(WARNING) << "Tried to unregister " << name
+            << ", but that service wasn't registered to begin with.";
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+
+    if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) {
+        LOG(WARNING) << "Only a server can unregister itself (for " << name << ")";
+        return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION);
+    }
+
+    sp<IBinder> storedBinder = serviceIt->second.binder;
+
+    if (binder != storedBinder) {
+        LOG(WARNING) << "Tried to unregister " << name
+            << ", but a different service is registered under this name.";
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+
+    int clients = handleServiceClientCallback(name);
+
+    // clients < 0: feature not implemented or other error. Assume clients.
+    // Otherwise:
+    // - kernel driver will hold onto one refcount (during this transaction)
+    // - servicemanager has a refcount (guaranteed by this transaction)
+    // So, if clients > 2, then at least one other service on the system must hold a refcount.
+    if (clients < 0 || clients > 2) {
+        // client callbacks are either disabled or there are other clients
+        LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients;
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+
+    mNameToService.erase(name);
+
+    return Status::ok();
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 7dcdaa4..77f5250 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -17,12 +17,14 @@
 #pragma once
 
 #include <android/os/BnServiceManager.h>
+#include <android/os/IClientCallback.h>
 #include <android/os/IServiceCallback.h>
 
 #include "Access.h"
 
 namespace android {
 
+using os::IClientCallback;
 using os::IServiceCallback;
 
 class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient {
@@ -40,9 +42,13 @@
                                             const sp<IServiceCallback>& callback) override;
     binder::Status unregisterForNotifications(const std::string& name,
                                               const sp<IServiceCallback>& callback) override;
-    binder::Status isDeclared(const std::string& name, bool* outReturn) override;
 
+    binder::Status isDeclared(const std::string& name, bool* outReturn) override;
+    binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
+                                          const sp<IClientCallback>& cb) override;
+    binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
     void binderDied(const wp<IBinder>& who) override;
+    void handleClientCallbacks();
 
 protected:
     virtual void tryStartService(const std::string& name);
@@ -52,20 +58,35 @@
         sp<IBinder> binder; // not null
         bool allowIsolated;
         int32_t dumpPriority;
+        bool hasClients = false; // notifications sent on true -> false.
+        bool guaranteeClient = false; // forces the client check to true
+        pid_t debugPid = 0; // the process in which this service runs
+
+        // the number of clients of the service, including servicemanager itself
+        ssize_t getNodeStrongRefCount();
     };
 
-    using CallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+    using ServiceCallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>;
+    using ClientCallbackMap = std::map<std::string, std::vector<sp<IClientCallback>>>;
     using ServiceMap = std::map<std::string, Service>;
 
-    // removes a callback from mNameToCallback, removing it if the vector is empty
+    // removes a callback from mNameToRegistrationCallback, removing it if the vector is empty
     // this updates iterator to the next location
-    void removeCallback(const wp<IBinder>& who,
-                        CallbackMap::iterator* it,
+    void removeRegistrationCallback(const wp<IBinder>& who,
+                        ServiceCallbackMap::iterator* it,
                         bool* found);
+    ssize_t handleServiceClientCallback(const std::string& serviceName);
+     // Also updates mHasClients (of what the last callback was)
+    void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
+    // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
+    // this updates the iterator to the next location
+    void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
+
     sp<IBinder> tryGetService(const std::string& name, bool startIfNotFound);
 
-    CallbackMap mNameToCallback;
     ServiceMap mNameToService;
+    ServiceCallbackMap mNameToRegistrationCallback;
+    ClientCallbackMap mNameToClientCallback;
 
     std::unique_ptr<Access> mAccess;
 };
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 4b12fc6..2618906 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -18,18 +18,101 @@
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
+#include <sys/timerfd.h>
+#include <utils/Looper.h>
 #include <utils/StrongPointer.h>
 
 #include "Access.h"
 #include "ServiceManager.h"
 
 using ::android::Access;
+using ::android::sp;
+using ::android::Looper;
+using ::android::LooperCallback;
+using ::android::ProcessState;
 using ::android::IPCThreadState;
 using ::android::ProcessState;
 using ::android::ServiceManager;
 using ::android::os::IServiceManager;
 using ::android::sp;
 
+class BinderCallback : public LooperCallback {
+public:
+    static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
+        sp<BinderCallback> cb = new BinderCallback;
+
+        int binder_fd = -1;
+        IPCThreadState::self()->setupPolling(&binder_fd);
+        LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
+
+        // Flush after setupPolling(), to make sure the binder driver
+        // knows about this thread handling commands.
+        IPCThreadState::self()->flushCommands();
+
+        int ret = looper->addFd(binder_fd,
+                                Looper::POLL_CALLBACK,
+                                Looper::EVENT_INPUT,
+                                cb,
+                                nullptr /*data*/);
+        LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");
+
+        return cb;
+    }
+
+    int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
+        IPCThreadState::self()->handlePolledCommands();
+        return 1;  // Continue receiving callbacks.
+    }
+};
+
+// LooperCallback for IClientCallback
+class ClientCallbackCallback : public LooperCallback {
+public:
+    static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) {
+        sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager);
+
+        int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/);
+        LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno);
+
+        itimerspec timespec {
+            .it_interval = {
+                .tv_sec = 5,
+                .tv_nsec = 0,
+            },
+            .it_value = {
+                .tv_sec = 5,
+                .tv_nsec = 0,
+            },
+        };
+
+        int timeRes = timerfd_settime(fdTimer, 0 /*flags*/, &timespec, nullptr);
+        LOG_ALWAYS_FATAL_IF(timeRes < 0, "Failed to timerfd_settime: res: %d err: %d", timeRes, errno);
+
+        int addRes = looper->addFd(fdTimer,
+                                   Looper::POLL_CALLBACK,
+                                   Looper::EVENT_INPUT,
+                                   cb,
+                                   nullptr);
+        LOG_ALWAYS_FATAL_IF(addRes != 1, "Failed to add client callback FD to Looper");
+
+        return cb;
+    }
+
+    int handleEvent(int fd, int /*events*/, void* /*data*/) override {
+        uint64_t expirations;
+        int ret = read(fd, &expirations, sizeof(expirations));
+        if (ret != sizeof(expirations)) {
+            ALOGE("Read failed to callback FD: ret: %d err: %d", ret, errno);
+        }
+
+        mManager->handleClientCallbacks();
+        return 1;  // Continue receiving callbacks.
+    }
+private:
+    ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {}
+    sp<ServiceManager> mManager;
+};
+
 int main(int argc, char** argv) {
     if (argc > 2) {
         LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
@@ -49,7 +132,14 @@
     IPCThreadState::self()->setTheContextObject(manager);
     ps->becomeContextManager(nullptr, nullptr);
 
-    IPCThreadState::self()->joinThreadPool();
+    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
+
+    BinderCallback::setupTo(looper);
+    ClientCallbackCallback::setupTo(looper, manager);
+
+    while(true) {
+        looper->pollAll(-1);
+    }
 
     // should not be reached
     return EXIT_FAILURE;
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 3310722..05f4340 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -645,10 +645,14 @@
  */
 void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
 
+#if __ANDROID_API__ >= 30
 /**
  * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
+ *
+ * Available since API level 30.
  */
-int32_t AConfiguration_getScreenRound(AConfiguration* config);
+int32_t AConfiguration_getScreenRound(AConfiguration* config) __INTRODUCED_IN(30);
+#endif
 
 /**
  * Set the current screen round in the configuration.
diff --git a/include/binder/ActivityManager.h b/include/binder/ActivityManager.h
deleted file mode 120000
index 018f7a5..0000000
--- a/include/binder/ActivityManager.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/ActivityManager.h
\ No newline at end of file
diff --git a/include/binder/AppOpsManager.h b/include/binder/AppOpsManager.h
deleted file mode 120000
index 4658269..0000000
--- a/include/binder/AppOpsManager.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/AppOpsManager.h
\ No newline at end of file
diff --git a/include/binder/BpBinder.h b/include/binder/BpBinder.h
deleted file mode 120000
index bc1f3d5..0000000
--- a/include/binder/BpBinder.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/BpBinder.h
\ No newline at end of file
diff --git a/include/binder/BufferedTextOutput.h b/include/binder/BufferedTextOutput.h
deleted file mode 120000
index fcad4fa..0000000
--- a/include/binder/BufferedTextOutput.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/BufferedTextOutput.h
\ No newline at end of file
diff --git a/include/binder/Debug.h b/include/binder/Debug.h
deleted file mode 120000
index d76a7f1..0000000
--- a/include/binder/Debug.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/Debug.h
\ No newline at end of file
diff --git a/include/binder/IActivityManager.h b/include/binder/IActivityManager.h
deleted file mode 120000
index 4a868e0..0000000
--- a/include/binder/IActivityManager.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IActivityManager.h
\ No newline at end of file
diff --git a/include/binder/IAppOpsCallback.h b/include/binder/IAppOpsCallback.h
deleted file mode 120000
index d587a0c..0000000
--- a/include/binder/IAppOpsCallback.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IAppOpsCallback.h
\ No newline at end of file
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
deleted file mode 120000
index 9e1c15a..0000000
--- a/include/binder/IAppOpsService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IAppOpsService.h
\ No newline at end of file
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
deleted file mode 120000
index 689b540..0000000
--- a/include/binder/IBatteryStats.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IBatteryStats.h
\ No newline at end of file
diff --git a/include/binder/IMediaResourceMonitor.h b/include/binder/IMediaResourceMonitor.h
deleted file mode 120000
index d23a4da..0000000
--- a/include/binder/IMediaResourceMonitor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IMediaResourceMonitor.h
\ No newline at end of file
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
deleted file mode 120000
index 6f33c58..0000000
--- a/include/binder/IPermissionController.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IPermissionController.h
\ No newline at end of file
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
deleted file mode 120000
index be0933f..0000000
--- a/include/binder/IProcessInfoService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IProcessInfoService.h
\ No newline at end of file
diff --git a/include/binder/IResultReceiver.h b/include/binder/IResultReceiver.h
deleted file mode 120000
index b10d19a..0000000
--- a/include/binder/IResultReceiver.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IResultReceiver.h
\ No newline at end of file
diff --git a/include/binder/IShellCallback.h b/include/binder/IShellCallback.h
deleted file mode 120000
index 8931195..0000000
--- a/include/binder/IShellCallback.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IShellCallback.h
\ No newline at end of file
diff --git a/include/binder/IUidObserver.h b/include/binder/IUidObserver.h
deleted file mode 120000
index 1382897..0000000
--- a/include/binder/IUidObserver.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IUidObserver.h
\ No newline at end of file
diff --git a/include/binder/IpPrefix.h b/include/binder/IpPrefix.h
deleted file mode 120000
index 655c774..0000000
--- a/include/binder/IpPrefix.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/IpPrefix.h
\ No newline at end of file
diff --git a/include/binder/MemoryBase.h b/include/binder/MemoryBase.h
deleted file mode 120000
index 3fd3e99..0000000
--- a/include/binder/MemoryBase.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/MemoryBase.h
\ No newline at end of file
diff --git a/include/binder/PermissionController.h b/include/binder/PermissionController.h
deleted file mode 120000
index b6e1928..0000000
--- a/include/binder/PermissionController.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/PermissionController.h
\ No newline at end of file
diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h
deleted file mode 120000
index e67eb19..0000000
--- a/include/binder/ProcessInfoService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/ProcessInfoService.h
\ No newline at end of file
diff --git a/include/binder/SafeInterface.h b/include/binder/SafeInterface.h
deleted file mode 120000
index 7cefe94..0000000
--- a/include/binder/SafeInterface.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/SafeInterface.h
\ No newline at end of file
diff --git a/include/binder/TextOutput.h b/include/binder/TextOutput.h
deleted file mode 120000
index 2abd209..0000000
--- a/include/binder/TextOutput.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libs/binder/include/binder/TextOutput.h
\ No newline at end of file
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 6479109..a9c2311 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -178,6 +178,10 @@
 
           this->callbacks_.key_authorized(arg, id);
           this->dispatched_prompt_ = std::nullopt;
+
+          // We need to dispatch pending prompts here upon success as well,
+          // since we might have multiple queued prompts.
+          DispatchPendingPrompt();
         } else if (packet[0] == 'N' && packet[1] == 'O') {
           CHECK_EQ(2UL, packet.length());
           // TODO: Do we want a callback if the key is denied?
diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp
index 98d8e8a..8062be6 100644
--- a/libs/android_runtime_lazy/android_runtime_lazy.cpp
+++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp
@@ -15,6 +15,7 @@
  */
 #define LOG_TAG "ANDROID_RUNTIME_LAZY"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_os_Parcel.h"
 #include "android_util_Binder.h"
 
 #include <dlfcn.h>
@@ -28,12 +29,18 @@
 std::once_flag loadFlag;
 
 typedef JNIEnv* (*getJNIEnv_t)();
+
+// android_util_Binder.h
 typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
 typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val);
 
+// android_os_Parcel.h
+typedef Parcel* (*parcelForJavaObject_t)(JNIEnv* env, jobject obj);
+
 getJNIEnv_t _getJNIEnv;
 ibinderForJavaObject_t _ibinderForJavaObject;
 javaObjectForIBinder_t _javaObjectForIBinder;
+parcelForJavaObject_t _parcelForJavaObject;
 
 void load() {
     std::call_once(loadFlag, []() {
@@ -64,6 +71,13 @@
             ALOGW("Could not find javaObjectForIBinder.");
             // no return
         }
+
+        _parcelForJavaObject = reinterpret_cast<parcelForJavaObject_t>(
+            dlsym(handle, "_ZN7android19parcelForJavaObjectEP7_JNIEnvP8_jobject"));
+        if (_parcelForJavaObject == nullptr) {
+            ALOGW("Could not find parcelForJavaObject.");
+            // no return
+        }
     });
 }
 
@@ -95,4 +109,12 @@
     return _javaObjectForIBinder(env, val);
 }
 
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) {
+    load();
+    if (_parcelForJavaObject == nullptr) {
+        return nullptr;
+    }
+    return _parcelForJavaObject(env, obj);
+}
+
 } // namespace android
diff --git a/libs/android_runtime_lazy/include/android_os_Parcel.h b/libs/android_runtime_lazy/include/android_os_Parcel.h
new file mode 100644
index 0000000..19b094d
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_os_Parcel.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include "jni.h"
+
+namespace android {
+
+// The name of this file is same with the file in frameworks/base/core/jni/
+// This is intentional to make the client use these exported functions
+// in the same way with the original.
+
+Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
+
+} // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 7ee4882..079dd82 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -90,6 +90,7 @@
         "IResultReceiver.cpp",
         "IServiceManager.cpp",
         "IShellCallback.cpp",
+        "LazyServiceRegistrar.cpp",
         "MemoryBase.cpp",
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
@@ -160,6 +161,7 @@
     name: "libbinder_aidl",
     srcs: [
         "aidl/android/content/pm/IPackageManagerNative.aidl",
+        "aidl/android/os/IClientCallback.aidl",
         "aidl/android/os/IServiceCallback.aidl",
         "aidl/android/os/IServiceManager.aidl",
     ],
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index bac8b66..5ca9156 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -271,6 +271,8 @@
             std::unique_lock<std::mutex> lock(mMutex);
             mBinder = binder;
             lock.unlock();
+            // Flushing here helps ensure the service's ref count remains accurate
+            IPCThreadState::self()->flushCommands();
             mCv.notify_one();
             return Status::ok();
         }
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
new file mode 100644
index 0000000..dc9482c
--- /dev/null
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlLazyServiceRegistrar"
+
+#include <binder/LazyServiceRegistrar.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <android/os/BnClientCallback.h>
+#include <android/os/IServiceManager.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace binder {
+namespace internal {
+
+using AidlServiceManager = android::os::IServiceManager;
+
+class ClientCounterCallback : public ::android::os::BnClientCallback {
+public:
+    ClientCounterCallback() : mNumConnectedServices(0) {}
+
+    bool registerService(const sp<IBinder>& service, const std::string& name,
+                         bool allowIsolated, int dumpFlags);
+
+protected:
+    Status onClients(const sp<IBinder>& service, bool clients) override;
+
+private:
+    /**
+     * Unregisters all services that we can. If we can't unregister all, re-register other
+     * services.
+     */
+    void tryShutdown();
+
+    /**
+     * Counter of the number of services that currently have at least one client.
+     */
+    size_t mNumConnectedServices;
+
+    struct Service {
+        sp<IBinder> service;
+        std::string name;
+        bool allowIsolated;
+        int dumpFlags;
+    };
+    /**
+     * Number of services that have been registered.
+     */
+    std::vector<Service> mRegisteredServices;
+};
+
+bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
+                                            bool allowIsolated, int dumpFlags) {
+    auto manager = interface_cast<AidlServiceManager>(
+                    ProcessState::self()->getContextObject(nullptr));
+
+    ALOGI("Registering service %s", name.c_str());
+
+    if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
+        ALOGE("Failed to register service %s", name.c_str());
+        return false;
+    }
+
+    if (!manager->registerClientCallback(name, service, this).isOk())
+    {
+      ALOGE("Failed to add client callback for service %s", name.c_str());
+      return false;
+    }
+
+    mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags});
+
+    return true;
+}
+
+/**
+ * onClients is oneway, so no need to worry about multi-threading. Note that this means multiple
+ * invocations could occur on different threads however.
+ */
+Status ClientCounterCallback::onClients(const sp<IBinder>& service, bool clients) {
+    if (clients) {
+        mNumConnectedServices++;
+    } else {
+        mNumConnectedServices--;
+    }
+
+    ALOGI("Process has %zu (of %zu available) client(s) in use after notification %s has clients: %d",
+          mNumConnectedServices, mRegisteredServices.size(),
+          String8(service->getInterfaceDescriptor()).string(), clients);
+
+    if (mNumConnectedServices == 0) {
+        tryShutdown();
+    }
+
+    return Status::ok();
+}
+
+void ClientCounterCallback::tryShutdown() {
+    ALOGI("Trying to shut down the service. No clients in use for any service in process.");
+
+    // This makes the same assumption as IServiceManager.cpp. Could dedupe if used in more places.
+    auto manager = interface_cast<AidlServiceManager>(
+            ProcessState::self()->getContextObject(nullptr));
+
+    auto unRegisterIt = mRegisteredServices.begin();
+    for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
+        auto& entry = (*unRegisterIt);
+
+        bool success = manager->tryUnregisterService(entry.name, entry.service).isOk();
+
+        if (!success) {
+            ALOGI("Failed to unregister service %s", entry.name.c_str());
+            break;
+        }
+    }
+
+    if (unRegisterIt == mRegisteredServices.end()) {
+        ALOGI("Unregistered all clients and exiting");
+        exit(EXIT_SUCCESS);
+    }
+
+    for (auto reRegisterIt = mRegisteredServices.begin(); reRegisterIt != unRegisterIt;
+         reRegisterIt++) {
+        auto& entry = (*reRegisterIt);
+
+        // re-register entry
+        if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) {
+            // Must restart. Otherwise, clients will never be able to get a hold of this service.
+            ALOGE("Bad state: could not re-register services");
+        }
+    }
+}
+
+}  // namespace internal
+
+LazyServiceRegistrar::LazyServiceRegistrar() {
+    mClientCC = std::make_shared<internal::ClientCounterCallback>();
+}
+
+LazyServiceRegistrar& LazyServiceRegistrar::getInstance() {
+    static auto registrarInstance = new LazyServiceRegistrar();
+    return *registrarInstance;
+}
+
+status_t LazyServiceRegistrar::registerService(const sp<IBinder>& service, const std::string& name,
+                                               bool allowIsolated, int dumpFlags) {
+    if (!mClientCC->registerService(service, name, allowIsolated, dumpFlags)) {
+        return UNKNOWN_ERROR;
+    }
+    return OK;
+}
+
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index b3afd81..55419eb 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -19,6 +19,9 @@
       "name": "binderStabilityTest"
     },
     {
+      "name": "libbinder_ndk_unit_test"
+    },
+    {
       "name": "CtsNdkBinderTestCases"
     }
   ]
diff --git a/libs/binder/aidl/android/os/IClientCallback.aidl b/libs/binder/aidl/android/os/IClientCallback.aidl
new file mode 100644
index 0000000..36d7ee6
--- /dev/null
+++ b/libs/binder/aidl/android/os/IClientCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+oneway interface IClientCallback {
+    /**
+     * This is called when there is a transition between having >= 1 clients and having 0 clients
+     * (or vice versa).
+     *
+     * Upon receiving hasClients false, if the process decides to exit, it is recommended to try to
+     * unregister using IServiceManager's tryUnregister before quitting in case another client
+     * associates.
+     *
+     * @param registered binder 'server' registered with IServiceManager's registerClientCallback
+     * @param hasClients whether there are currently clients
+     *     true - when there are >= 1 clients. This must be called as soon as IServiceManager::get
+     *         is called (no race).
+     *     false - when there are 0 clients. This may be delayed if it is thought that another
+     *         may be used again soon.
+     */
+    void onClients(IBinder registered, boolean hasClients);
+}
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index b965881..ff15460 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.os.IClientCallback;
 import android.os.IServiceCallback;
 
 /**
@@ -96,4 +97,15 @@
      * manifest.
      */
     boolean isDeclared(@utf8InCpp String name);
+
+    /**
+     * Request a callback when the number of clients of the service changes.
+     * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
+     */
+    void registerClientCallback(@utf8InCpp String name, IBinder service, IClientCallback callback);
+
+    /**
+     * Attempt to unregister and remove a service. Will fail if the service is still in use.
+     */
+    void tryUnregisterService(@utf8InCpp String name, IBinder service);
 }
diff --git a/libs/binder/include/binder/Enums.h b/libs/binder/include/binder/Enums.h
new file mode 100644
index 0000000..aec6f70
--- /dev/null
+++ b/libs/binder/include/binder/Enums.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <iterator>
+#include <type_traits>
+
+namespace android {
+
+namespace internal {
+
+// Never instantiated. Used as a placeholder for template variables.
+template <typename T>
+struct invalid_type;
+
+// AIDL generates specializations of this for enums.
+template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
+constexpr invalid_type<EnumType> enum_values;
+} // namespace internal
+
+// Usage: for (const auto v : enum_range<EnumType>() ) { ... }
+template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
+struct enum_range {
+    constexpr auto begin() const { return std::begin(internal::enum_values<EnumType>); }
+    constexpr auto end() const { return std::end(internal::enum_values<EnumType>); }
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 8d72a6b..79d9b79 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -109,7 +109,27 @@
 
 
 #define __IINTF_CONCAT(x, y) (x ## y)
+
+#ifndef DO_NOT_CHECK_MANUAL_BINDER_INTERFACES
+
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
+    static_assert(internal::allowedManualInterface(NAME),               \
+                  "b/64223827: Manually written binder interfaces are " \
+                  "considered error prone and frequently have bugs. "   \
+                  "The preferred way to add interfaces is to define "   \
+                  "an .aidl file to auto-generate the interface. If "   \
+                  "an interface must be manually written, add its "     \
+                  "name to the whitelist.");                            \
+    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)    \
+
+#else
+
+#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
+    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)    \
+
+#endif
+
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
     const ::android::StaticString16                                     \
         I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
     const ::android::String16 I##INTERFACE::descriptor(                 \
@@ -192,6 +212,122 @@
 
 // ----------------------------------------------------------------------
 
+namespace internal {
+constexpr const char* const kManualInterfaces[] = {
+  "android.app.IActivityManager",
+  "android.app.IUidObserver",
+  "android.drm.IDrm",
+  "android.dvr.IVsyncCallback",
+  "android.dvr.IVsyncService",
+  "android.gfx.tests.ICallback",
+  "android.gfx.tests.IIPCTest",
+  "android.gfx.tests.ISafeInterfaceTest",
+  "android.graphicsenv.IGpuService",
+  "android.gui.DisplayEventConnection",
+  "android.gui.IConsumerListener",
+  "android.gui.IGraphicBufferConsumer",
+  "android.gui.IRegionSamplingListener",
+  "android.gui.ITransactionComposerListener",
+  "android.gui.SensorEventConnection",
+  "android.gui.SensorServer",
+  "android.hardware.ICamera",
+  "android.hardware.ICameraClient",
+  "android.hardware.ICameraRecordingProxy",
+  "android.hardware.ICameraRecordingProxyListener",
+  "android.hardware.ICrypto",
+  "android.hardware.IOMXObserver",
+  "android.hardware.ISoundTrigger",
+  "android.hardware.ISoundTriggerClient",
+  "android.hardware.ISoundTriggerHwService",
+  "android.hardware.IStreamListener",
+  "android.hardware.IStreamSource",
+  "android.input.IInputFlinger",
+  "android.input.ISetInputWindowsListener",
+  "android.media.IAudioFlinger",
+  "android.media.IAudioFlingerClient",
+  "android.media.IAudioPolicyService",
+  "android.media.IAudioPolicyServiceClient",
+  "android.media.IAudioService",
+  "android.media.IAudioTrack",
+  "android.media.IDataSource",
+  "android.media.IDrmClient",
+  "android.media.IEffect",
+  "android.media.IEffectClient",
+  "android.media.IMediaAnalyticsService",
+  "android.media.IMediaCodecList",
+  "android.media.IMediaDrmService",
+  "android.media.IMediaExtractor",
+  "android.media.IMediaExtractorService",
+  "android.media.IMediaHTTPConnection",
+  "android.media.IMediaHTTPService",
+  "android.media.IMediaLogService",
+  "android.media.IMediaMetadataRetriever",
+  "android.media.IMediaPlayer",
+  "android.media.IMediaPlayerClient",
+  "android.media.IMediaPlayerService",
+  "android.media.IMediaRecorder",
+  "android.media.IMediaRecorderClient",
+  "android.media.IMediaResourceMonitor",
+  "android.media.IMediaSource",
+  "android.media.IRemoteDisplay",
+  "android.media.IRemoteDisplayClient",
+  "android.media.IResourceManagerClient",
+  "android.media.IResourceManagerService",
+  "android.os.IComplexTypeInterface",
+  "android.os.IPermissionController",
+  "android.os.IPingResponder",
+  "android.os.IPowerManager",
+  "android.os.IProcessInfoService",
+  "android.os.ISchedulingPolicyService",
+  "android.os.IStringConstants",
+  "android.os.storage.IObbActionListener",
+  "android.os.storage.IStorageEventListener",
+  "android.os.storage.IStorageManager",
+  "android.os.storage.IStorageShutdownObserver",
+  "android.service.vr.IPersistentVrStateCallbacks",
+  "android.service.vr.IVrManager",
+  "android.service.vr.IVrStateCallbacks",
+  "android.ui.ISurfaceComposer",
+  "android.ui.ISurfaceComposerClient",
+  "android.utils.IMemory",
+  "android.utils.IMemoryHeap",
+  "com.android.car.procfsinspector.IProcfsInspector",
+  "com.android.internal.app.IAppOpsCallback",
+  "com.android.internal.app.IAppOpsService",
+  "com.android.internal.app.IBatteryStats",
+  "com.android.internal.os.IResultReceiver",
+  "com.android.internal.os.IShellCallback",
+  "drm.IDrmManagerService",
+  "drm.IDrmServiceListener",
+  "IAAudioClient",
+  "IAAudioService",
+  "VtsFuzzer",
+  nullptr,
+};
+
+constexpr const char* const kDownstreamManualInterfaces[] = {
+  // Add downstream interfaces here.
+  nullptr,
+};
+
+constexpr bool equals(const char* a, const char* b) {
+  if (*a != *b) return false;
+  if (*a == '\0') return true;
+  return equals(a + 1, b + 1);
+}
+
+constexpr bool inList(const char* a, const char* const* whitelist) {
+  if (*whitelist == nullptr) return false;
+  if (equals(a, *whitelist)) return true;
+  return inList(a, whitelist + 1);
+}
+
+constexpr bool allowedManualInterface(const char* name) {
+  return inList(name, kManualInterfaces) ||
+         inList(name, kDownstreamManualInterfaces);
+}
+
+} // namespace internal
 } // namespace android
 
 #endif // ANDROID_IINTERFACE_H
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
new file mode 100644
index 0000000..efdecc4
--- /dev/null
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace binder {
+namespace internal {
+class ClientCounterCallback;
+}  // namespace internal
+
+/** Exits when all services registered through this object have 0 clients */
+class LazyServiceRegistrar {
+   public:
+     static LazyServiceRegistrar& getInstance();
+     status_t registerService(const sp<IBinder>& service,
+                              const std::string& name = "default",
+                              bool allowIsolated = false,
+                              int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+
+   private:
+     std::shared_ptr<internal::ClientCounterCallback> mClientCC;
+     LazyServiceRegistrar();
+};
+
+}  // namespace binder
+}  // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index c0ea6d7..e66e425 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -50,6 +50,7 @@
         "ibinder.cpp",
         "ibinder_jni.cpp",
         "parcel.cpp",
+        "parcel_jni.cpp",
         "process.cpp",
         "stability.cpp",
         "status.cpp",
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index 946ccb7..2b61cf1 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -34,6 +34,7 @@
 
 #include <unistd.h>
 #include <cstddef>
+#include <string>
 
 namespace ndk {
 
@@ -228,6 +229,13 @@
      */
     const char* getMessage() const { return AStatus_getMessage(get()); }
 
+    std::string getDescription() const {
+        const char* cStr = AStatus_getDescription(get());
+        std::string ret = cStr;
+        AStatus_deleteDescription(cStr);
+        return ret;
+    }
+
     /**
      * Convenience methods for creating scoped statuses.
      */
diff --git a/libs/binder/ndk/include_ndk/android/binder_enums.h b/libs/binder/ndk/include_ndk/android/binder_enums.h
new file mode 100644
index 0000000..ee819c0
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_enums.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_enums.h
+ * @brief Helpers for AIDL enum types.
+ */
+
+#pragma once
+
+#include <iterator>
+#include <type_traits>
+
+namespace ndk {
+
+namespace internal {
+/**
+ * Never instantiated. Used as a placeholder for template variables.
+ */
+template <typename T>
+struct invalid_type;
+
+/**
+ * AIDL generates specializations of this for enums.
+ */
+template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
+constexpr invalid_type<EnumType> enum_values;
+}  // namespace internal
+
+/**
+ * Iterable interface to enumerate all values of AIDL enum types.
+ */
+template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
+struct enum_range {
+    /**
+     * Return an iterator pointing to the first enum value.
+     */
+    constexpr auto begin() const { return std::begin(internal::enum_values<EnumType>); }
+    /**
+     * Return an iterator pointing to one past the last enum value.
+     */
+    constexpr auto end() const { return std::end(internal::enum_values<EnumType>); }
+};
+
+}  // namespace ndk
+
+/** @} */
\ No newline at end of file
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index be3029c..cd1ff1f 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -36,13 +36,13 @@
 /**
  * Converts an android.os.IBinder object into an AIBinder* object.
  *
- * If either env or the binder is null, null is returned. If this binder object was originally an
+ * If the binder is null, null is returned. If this binder object was originally an
  * AIBinder object, the original object is returned. The returned object has one refcount
  * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
  *
  * Available since API level 29.
  *
- * \param env Java environment.
+ * \param env Java environment. Must not be null.
  * \param binder android.os.IBinder java object.
  *
  * \return an AIBinder object representing the Java binder object. If either parameter is null, or
@@ -54,12 +54,12 @@
 /**
  * Converts an AIBinder* object into an android.os.IBinder object.
  *
- * If either env or the binder is null, null is returned. If this binder object was originally an
- * IBinder object, the original java object will be returned.
+ * If the binder is null, null is returned. If this binder object was originally an IBinder object,
+ * the original java object will be returned.
  *
  * Available since API level 29.
  *
- * \param env Java environment.
+ * \param env Java environment. Must not be null.
  * \param binder the object to convert.
  *
  * \return an android.os.IBinder object or null if the parameters were null.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
new file mode 100644
index 0000000..65e1704
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel_jni.h
+ * @brief Conversions between AParcel and android.os.Parcel
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= 30
+
+/**
+ * Converts an android.os.Parcel object into an AParcel* object.
+ *
+ * If the parcel is null, null is returned.
+ *
+ * Available since API level 30.
+ *
+ * \param env Java environment. Must not be null.
+ * \param parcel android.os.Parcel java object.
+ *
+ * \return an AParcel object representing the Java parcel object. If either parameter is null, this
+ * will return null. This must be deleted with AParcel_delete. This does not take ownership of the
+ * jobject and is only good for as long as the jobject is alive.
+ */
+__attribute__((warn_unused_result)) AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject parcel)
+        __INTRODUCED_IN(30);
+
+#endif  //__ANDROID_API__ >= 30
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index 7871667..df5df13 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -421,13 +421,76 @@
 }
 
 /**
+ * Convenience API for writing a non-null parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
+    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+    if (status != STATUS_OK) {
+        return status;
+    }
+    return p.writeToParcel(parcel);
+}
+
+/**
+ * Convenience API for reading a non-null parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
+    int32_t null;
+    binder_status_t status = AParcel_readInt32(parcel, &null);
+    if (status != STATUS_OK) {
+        return status;
+    }
+    if (null == 0) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return p->readFromParcel(parcel);
+}
+
+/**
+ * Convenience API for writing a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
+                                                              const std::optional<P>& p) {
+    if (p == std::nullopt) {
+        return AParcel_writeInt32(parcel, 0);  // null
+    }
+    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+    if (status != STATUS_OK) {
+        return status;
+    }
+    return p->writeToParcel(parcel);
+}
+
+/**
+ * Convenience API for reading a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
+                                                             std::optional<P>* p) {
+    int32_t null;
+    binder_status_t status = AParcel_readInt32(parcel, &null);
+    if (status != STATUS_OK) {
+        return status;
+    }
+    if (null == 0) {
+        *p = std::nullopt;
+        return STATUS_OK;
+    }
+    *p = std::optional<P>(P{});
+    return (*p)->readFromParcel(parcel);
+}
+
+/**
  * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
  */
 template <typename P>
 binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
                                                         size_t index) {
     const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
-    return vector->at(index).writeToParcel(parcel);
+    return AParcel_writeParcelable(parcel, vector->at(index));
 }
 
 /**
@@ -437,7 +500,7 @@
 binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
                                                        size_t index) {
     std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
-    return vector->at(index).readFromParcel(parcel);
+    return AParcel_readParcelable(parcel, &vector->at(index));
 }
 
 /**
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 78d70f8..ab9a144 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -247,6 +247,25 @@
 const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
+ * Get human-readable description for debugging.
+ *
+ * Available since API level 30.
+ *
+ * \param status the status being queried.
+ *
+ * \return a description, must be deleted with AStatus_deleteDescription.
+ */
+__attribute__((warn_unused_result)) const char* AStatus_getDescription(const AStatus* status)
+        __INTRODUCED_IN(30);
+
+/**
+ * Delete description.
+ *
+ * \param description value from AStatus_getDescription
+ */
+void AStatus_deleteDescription(const char* description) __INTRODUCED_IN(30);
+
+/**
  * Deletes memory associated with the status instance.
  *
  * Available since API level 29.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index d59d6e4..f3158d7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -103,6 +103,9 @@
   global:
     AIBinder_getExtension;
     AIBinder_setExtension;
+    AStatus_getDescription;
+    AStatus_deleteDescription;
+    AParcel_fromJavaParcel;
 
     AIBinder_markSystemStability; # apex
     AIBinder_markVendorStability; # llndk
diff --git a/libs/binder/ndk/parcel_jni.cpp b/libs/binder/ndk/parcel_jni.cpp
new file mode 100644
index 0000000..53b2d7c
--- /dev/null
+++ b/libs/binder/ndk/parcel_jni.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_parcel_jni.h>
+#include "parcel_internal.h"
+
+#include <android_os_Parcel.h>
+
+using ::android::Parcel;
+using ::android::parcelForJavaObject;
+
+AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject jbinder) {
+    if (jbinder == nullptr) {
+        return nullptr;
+    }
+
+    Parcel* parcel = parcelForJavaObject(env, jbinder);
+
+    if (parcel == nullptr) {
+        return nullptr;
+    }
+
+    return new AParcel(nullptr /*binder*/, parcel, false /*shouldOwn*/);
+}
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
deleted file mode 100755
index a0c49fb..0000000
--- a/libs/binder/ndk/runtests.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-if [ -z $ANDROID_BUILD_TOP ]; then
-  echo "You need to source and lunch before you can use this script"
-  exit 1
-fi
-
-set -ex
-
-function run_libbinder_ndk_test() {
-    adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
-
-    # avoid getService 1s delay for most runs, non-critical
-    sleep 0.1
-
-    adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
-        adb shell killall libbinder_ndk_test_server
-}
-
-[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
-    MODULES-IN-frameworks-native-libs-binder-ndk
-
-adb root
-adb wait-for-device
-adb sync data
-
-# very simple unit tests, tests things outside of the NDK as well
-run_libbinder_ndk_test
-
-# CTS tests (much more comprehensive, new tests should ideally go here)
-atest android.binder.cts
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index 1f75b0b..87e1341 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -66,6 +66,17 @@
     return status->get()->exceptionMessage().c_str();
 }
 
+const char* AStatus_getDescription(const AStatus* status) {
+    android::String8 description = status->get()->toString8();
+    char* cStr = new char[description.size() + 1];
+    memcpy(cStr, description.c_str(), description.size() + 1);
+    return cStr;
+}
+
+void AStatus_deleteDescription(const char* description) {
+    delete[] const_cast<char*>(description);
+}
+
 void AStatus_delete(AStatus* status) {
     delete status;
 }
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index ebd08b2..8c8382d 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -56,16 +56,10 @@
 // specifically the parts which are outside of the NDK. Actual users should
 // also instead use AIDL to generate these stubs. See android.binder.cts.
 cc_test {
-    name: "libbinder_ndk_test_client",
+    name: "libbinder_ndk_unit_test",
     defaults: ["test_libbinder_ndk_test_defaults"],
-    srcs: ["main_client.cpp"],
-}
-
-cc_test {
-    name: "libbinder_ndk_test_server",
-    defaults: ["test_libbinder_ndk_test_defaults"],
-    srcs: ["main_server.cpp"],
-    gtest: false,
+    srcs: ["libbinder_ndk_unit_test.cpp"],
+    test_suites: ["general-tests"],
 }
 
 cc_test {
@@ -85,13 +79,12 @@
         "libbinder_ndk",
         "libutils",
     ],
-    test_suites: ["device-tests"],
+    test_suites: ["general-tests"],
 }
 
 aidl_interface {
     name: "IBinderVendorDoubleLoadTest",
-    // TODO(b/119771576): only vendor is needed
-    vendor_available: true,
+    vendor: true,
     srcs: [
         "IBinderVendorDoubleLoadTest.aidl",
     ],
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
index d3ccdc2..ad78e31 100644
--- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -105,7 +105,8 @@
 
         std::string outString;
         ScopedAStatus status = server->RepeatString("foo", &outString);
-        EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get())) << serviceName;
+        EXPECT_EQ(STATUS_OK, AStatus_getExceptionCode(status.get()))
+                << serviceName << " " << status.getDescription();
         EXPECT_EQ("foo", outString) << serviceName;
     }
 }
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
similarity index 86%
rename from libs/binder/ndk/test/main_client.cpp
rename to libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 8467734..8aba411 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 #include <iface/iface.h>
 
+#include <sys/prctl.h>
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
@@ -29,6 +30,34 @@
 
 constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
 
+class MyFoo : public IFoo {
+    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+        *out = 2 * in;
+        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+        return STATUS_OK;
+    }
+
+    binder_status_t die() override {
+        LOG(FATAL) << "IFoo::die called!";
+        return STATUS_UNKNOWN_ERROR;
+    }
+};
+
+int service(const char* instance) {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    // Strong reference to MyFoo kept by service manager.
+    binder_status_t status = (new MyFoo)->addService(instance);
+
+    if (status != STATUS_OK) {
+        LOG(FATAL) << "Could not register: " << status << " " << instance;
+    }
+
+    ABinderProcess_joinThreadPool();
+
+    return 1;  // should not return
+}
+
 // This is too slow
 // TEST(NdkBinder, GetServiceThatDoesntExist) {
 //     sp<IFoo> foo = IFoo::getService("asdfghkl;");
@@ -87,14 +116,14 @@
     EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
 
     foo = nullptr;
-    AIBinder_decStrong(binder);
-    binder = nullptr;
 
     std::unique_lock<std::mutex> lock(deathMutex);
     EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
     EXPECT_TRUE(deathRecieved);
 
     AIBinder_DeathRecipient_delete(recipient);
+    AIBinder_decStrong(binder);
+    binder = nullptr;
 }
 
 TEST(NdkBinder, RetrieveNonNdkService) {
@@ -199,6 +228,15 @@
 int main(int argc, char* argv[]) {
     ::testing::InitGoogleTest(&argc, argv);
 
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return service(IFoo::kInstanceNameToDieFor);
+    }
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+        return service(IFoo::kSomeInstanceName);
+    }
+
     ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
     ABinderProcess_startThreadPool();
 
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
deleted file mode 100644
index a6e17e8..0000000
--- a/libs/binder/ndk/test/main_server.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android/binder_process.h>
-#include <iface/iface.h>
-
-using ::android::sp;
-
-class MyFoo : public IFoo {
-    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
-        *out = 2 * in;
-        LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
-        return STATUS_OK;
-    }
-
-    binder_status_t die() override {
-        LOG(FATAL) << "IFoo::die called!";
-        return STATUS_UNKNOWN_ERROR;
-    }
-};
-
-int service(const char* instance) {
-    ABinderProcess_setThreadPoolMaxThreadCount(0);
-
-    // Strong reference to MyFoo kept by service manager.
-    binder_status_t status = (new MyFoo)->addService(instance);
-
-    if (status != STATUS_OK) {
-        LOG(FATAL) << "Could not register: " << status << " " << instance;
-    }
-
-    ABinderProcess_joinThreadPool();
-
-    return 1;  // should not return
-}
-
-int main() {
-    if (fork() == 0) {
-        return service(IFoo::kInstanceNameToDieFor);
-    }
-
-    return service(IFoo::kSomeInstanceName);
-}
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 28cb138..b1943a4 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -8,19 +8,26 @@
         "liblog",
         "libnetdutils"
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
         "-Wextra",
     ],
+    export_include_dirs: ["."],
 }
 
 cc_test {
     name: "libtimeinstate_test",
     srcs: ["testtimeinstate.cpp"],
     shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
         "libtimeinstate",
+        "libnetdutils",
     ],
+    header_libs: ["bpf_prog_headers"],
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5fd4a95..1465296 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,12 +17,16 @@
 #define LOG_TAG "libtimeinstate"
 
 #include "cputimeinstate.h"
+#include <bpf_timeinstate.h>
 
 #include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
+#include <sys/sysinfo.h>
 
 #include <mutex>
+#include <numeric>
+#include <optional>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -37,44 +41,38 @@
 #include <libbpf.h>
 #include <log/log.h>
 
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
 namespace android {
 namespace bpf {
 
-struct time_key_t {
-    uint32_t uid;
-    uint32_t freq;
-};
-
-struct val_t {
-    uint64_t ar[100];
-};
-
 static std::mutex gInitializedMutex;
 static bool gInitialized = false;
+static std::mutex gTrackingMutex;
+static bool gTracking = false;
 static uint32_t gNPolicies = 0;
+static uint32_t gNCpus = 0;
 static std::vector<std::vector<uint32_t>> gPolicyFreqs;
 static std::vector<std::vector<uint32_t>> gPolicyCpus;
 static std::set<uint32_t> gAllFreqs;
-static unique_fd gMapFd;
+static unique_fd gTisMapFd;
+static unique_fd gConcurrentMapFd;
 
-static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
     std::string data;
 
-    if (!android::base::ReadFileToString(path, &data)) return false;
+    if (!android::base::ReadFileToString(path, &data)) return {};
 
     auto strings = android::base::Split(data, " \n");
+    std::vector<uint32_t> ret;
     for (const auto &s : strings) {
         if (s.empty()) continue;
         uint32_t n;
-        if (!android::base::ParseUint(s, &n)) return false;
-        out->emplace_back(n);
+        if (!android::base::ParseUint(s, &n)) return {};
+        ret.emplace_back(n);
     }
-    return true;
+    return ret;
 }
 
 static int isPolicyFile(const struct dirent *d) {
@@ -89,10 +87,22 @@
     return policyN1 - policyN2;
 }
 
+static int bpf_obj_get_wronly(const char *pathname) {
+    union bpf_attr attr;
+
+    memset(&attr, 0, sizeof(attr));
+    attr.pathname = ptr_to_u64((void *)pathname);
+    attr.file_flags = BPF_F_WRONLY;
+
+    return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
 static bool initGlobals() {
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
 
+    gNCpus = get_nprocs_conf();
+
     struct dirent **dirlist;
     const char basepath[] = "/sys/devices/system/cpu/cpufreq";
     int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
@@ -111,21 +121,28 @@
         for (const auto &name : {"available", "boost"}) {
             std::string path =
                     StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
-            if (!readNumbersFromFile(path, &freqs)) return false;
+            auto nums = readNumbersFromFile(path);
+            if (!nums) continue;
+            freqs.insert(freqs.end(), nums->begin(), nums->end());
         }
+        if (freqs.empty()) return false;
         std::sort(freqs.begin(), freqs.end());
         gPolicyFreqs.emplace_back(freqs);
 
         for (auto freq : freqs) gAllFreqs.insert(freq);
 
-        std::vector<uint32_t> cpus;
         std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
-        if (!readNumbersFromFile(path, &cpus)) return false;
-        gPolicyCpus.emplace_back(cpus);
+        auto cpus = readNumbersFromFile(path);
+        if (!cpus) return false;
+        gPolicyCpus.emplace_back(*cpus);
     }
 
-    gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
-    if (gMapFd < 0) return false;
+    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+    if (gTisMapFd < 0) return false;
+
+    gConcurrentMapFd =
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+    if (gConcurrentMapFd < 0) return false;
 
     gInitialized = true;
     return true;
@@ -145,97 +162,289 @@
 // process dies then it must be called again to resume tracking.
 // This function should *not* be called while tracking is already active; doing so is unnecessary
 // and can lead to accounting errors.
-bool startTrackingUidCpuFreqTimes() {
-    return attachTracepointProgram("sched", "sched_switch") &&
+bool startTrackingUidTimes() {
+    std::lock_guard<std::mutex> guard(gTrackingMutex);
+    if (!initGlobals()) return false;
+    if (gTracking) return true;
+
+    unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    if (cpuPolicyFd < 0) return false;
+
+    for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
+        for (auto &cpu : gPolicyCpus[i]) {
+            if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
+        }
+    }
+
+    unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    if (freqToIdxFd < 0) return false;
+    freq_idx_key_t key;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        key.policy = i;
+        for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) {
+            key.freq = gPolicyFreqs[i][j];
+            // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq.
+            // The uid_times map still uses 0-based indexes, and the sched_switch program handles
+            // conversion between them, so this does not affect our map reading code.
+            uint32_t idx = j + 1;
+            if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
+        }
+    }
+
+    unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    if (cpuLastUpdateFd < 0) return false;
+    std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
+    uint32_t zero = 0;
+    if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
+
+    unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    if (nrActiveFd < 0) return false;
+    if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
+
+    unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    if (policyNrActiveFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
+    }
+
+    unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    if (policyFreqIdxFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+    }
+
+    gTracking = attachTracepointProgram("sched", "sched_switch") &&
             attachTracepointProgram("power", "cpu_frequency");
+    return gTracking;
 }
 
-// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
-// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
-// using the format:
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
+    if (!gInitialized && !initGlobals()) return {};
+    return gPolicyFreqs;
+}
+
+// Retrieve the times in ns that uid spent running at each CPU frequency.
+// Return contains no value on error, otherwise it contains a vector of vectors using the format:
 // [[t0_0, t0_1, ...],
 //  [t1_0, t1_1, ...], ...]
 // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
-bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
-    if (!gInitialized && !initGlobals()) return false;
-    time_key_t key = {.uid = uid, .freq = 0};
+std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
+    if (!gInitialized && !initGlobals()) return {};
 
-    freqTimes->clear();
-    freqTimes->resize(gNPolicies);
-    std::vector<uint32_t> idxs(gNPolicies, 0);
+    std::vector<std::vector<uint64_t>> out;
+    uint32_t maxFreqCount = 0;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+        out.emplace_back(freqList.size(), 0);
+    }
 
-    val_t value;
-    for (uint32_t freq : gAllFreqs) {
-        key.freq = freq;
-        int ret = findMapEntry(gMapFd, &key, &value);
-        if (ret) {
-            if (errno == ENOENT)
-                memset(&value.ar, 0, sizeof(value.ar));
-            else
-                return false;
+    std::vector<tis_val_t> vals(gNCpus);
+    time_key_t key = {.uid = uid};
+    for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
+        key.bucket = i;
+        if (findMapEntry(gTisMapFd, &key, vals.data())) {
+            if (errno != ENOENT) return {};
+            continue;
         }
-        for (uint32_t i = 0; i < gNPolicies; ++i) {
-            if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
-            uint64_t time = 0;
-            for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
-            idxs[i] += 1;
-            (*freqTimes)[i].emplace_back(time);
+
+        auto offset = i * FREQS_PER_ENTRY;
+        auto nextOffset = (i + 1) * FREQS_PER_ENTRY;
+        for (uint32_t j = 0; j < gNPolicies; ++j) {
+            if (offset >= gPolicyFreqs[j].size()) continue;
+            auto begin = out[j].begin() + offset;
+            auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end();
+
+            for (const auto &cpu : gPolicyCpus[j]) {
+                std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
+            }
         }
     }
 
-    return true;
+    return out;
 }
 
-// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
-// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
-// vectors of vectors using the format:
+// Retrieve the times in ns that each uid spent running at each CPU freq.
+// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
+// using the format:
 // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
 //   uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
 // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
-bool getUidsCpuFreqTimes(
-        std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
-    if (!gInitialized && !initGlobals()) return false;
-
-    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
-    if (fd < 0) return false;
-    BpfMap<time_key_t, val_t> m(fd);
-
-    std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
-    for (uint32_t i = 0; i < gNPolicies; ++i) {
-        std::unordered_map<uint32_t, uint32_t> freqIdxs;
-        for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
-        policyFreqIdxs.emplace_back(freqIdxs);
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+getUidsCpuFreqTimes() {
+    if (!gInitialized && !initGlobals()) return {};
+    time_key_t key, prevKey;
+    std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
+    if (getFirstMapKey(gTisMapFd, &key)) {
+        if (errno == ENOENT) return map;
+        return std::nullopt;
     }
 
-    auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
-                                             const BpfMap<time_key_t, val_t> &) {
-        if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
-            (*freqTimeMap)[key.uid].resize(gNPolicies);
-            for (uint32_t i = 0; i < gNPolicies; ++i) {
-                (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
+    std::vector<std::vector<uint64_t>> mapFormat;
+    for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+
+    std::vector<tis_val_t> vals(gNCpus);
+    do {
+        if (findMapEntry(gTisMapFd, &key, vals.data())) return {};
+        if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
+
+        auto offset = key.bucket * FREQS_PER_ENTRY;
+        auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY;
+        for (uint32_t i = 0; i < gNPolicies; ++i) {
+            if (offset >= gPolicyFreqs[i].size()) continue;
+            auto begin = map[key.uid][i].begin() + offset;
+            auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY :
+                map[key.uid][i].end();
+            for (const auto &cpu : gPolicyCpus[i]) {
+                std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
             }
         }
+        prevKey = key;
+    } while (!getNextMapKey(gTisMapFd, &prevKey, &key));
+    if (errno != ENOENT) return {};
+    return map;
+}
+
+static bool verifyConcurrentTimes(const concurrent_time_t &ct) {
+    uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0);
+    uint64_t policySum = 0;
+    for (const auto &vec : ct.policy) {
+        policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0);
+    }
+    return activeSum == policySum;
+}
+
+// Retrieve the times in ns that uid spent running concurrently with each possible number of other
+// tasks on each cluster (policy times) and overall (active times).
+// Return contains no value on error, otherwise it contains a concurrent_time_t with the format:
+// {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]}
+// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
+// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster
+std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) {
+    if (!gInitialized && !initGlobals()) return {};
+    concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
+    for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
+    std::vector<concurrent_val_t> vals(gNCpus);
+    time_key_t key = {.uid = uid};
+    for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+        if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
+            if (errno != ENOENT) return {};
+            continue;
+        }
+        auto offset = key.bucket * CPUS_PER_ENTRY;
+        auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
+
+        auto activeBegin = ret.active.begin() + offset;
+        auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end();
+
+        for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
+            std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
+                           std::plus<uint64_t>());
+        }
 
-        for (size_t policy = 0; policy < gNPolicies; ++policy) {
+        for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
+            if (offset >= gPolicyCpus[policy].size()) continue;
+            auto policyBegin = ret.policy[policy].begin() + offset;
+            auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
+                                                                     : ret.policy[policy].end();
+
             for (const auto &cpu : gPolicyCpus[policy]) {
-                auto freqIdx = policyFreqIdxs[policy][key.freq];
-                (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
+                std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin,
+                               std::plus<uint64_t>());
             }
         }
-        return android::netdutils::status::ok;
-    };
-    return isOk(m.iterateWithValue(fn));
+    }
+    if (!verifyConcurrentTimes(ret) && retry)  return getUidConcurrentTimes(uid, false);
+    return ret;
+}
+
+// Retrieve the times in ns that each uid spent running concurrently with each possible number of
+// other tasks on each cluster (policy times) and overall (active times).
+// Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's
+// using the format:
+// { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...}
+// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
+// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster.
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() {
+    if (!gInitialized && !initGlobals()) return {};
+    time_key_t key, prevKey;
+    std::unordered_map<uint32_t, concurrent_time_t> ret;
+    if (getFirstMapKey(gConcurrentMapFd, &key)) {
+        if (errno == ENOENT) return ret;
+        return {};
+    }
+
+    concurrent_time_t retFormat = {.active = std::vector<uint64_t>(gNCpus, 0)};
+    for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0);
+
+    std::vector<concurrent_val_t> vals(gNCpus);
+    std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd;
+
+    do {
+        if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {};
+        if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat);
+
+        auto offset = key.bucket * CPUS_PER_ENTRY;
+        auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
+
+        activeBegin = ret[key.uid].active.begin();
+        activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end();
+
+        for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
+            std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
+                           std::plus<uint64_t>());
+        }
+
+        for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
+            if (offset >= gPolicyCpus[policy].size()) continue;
+            policyBegin = ret[key.uid].policy[policy].begin() + offset;
+            policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
+                                                                : ret[key.uid].policy[policy].end();
+
+            for (const auto &cpu : gPolicyCpus[policy]) {
+                std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin,
+                               std::plus<uint64_t>());
+            }
+        }
+        prevKey = key;
+    } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key));
+    if (errno != ENOENT) return {};
+    for (const auto &[key, value] : ret) {
+        if (!verifyConcurrentTimes(value)) {
+            auto val = getUidConcurrentTimes(key, false);
+            if (val.has_value()) ret[key] = val.value();
+        }
+    }
+    return ret;
 }
 
 // Clear all time in state data for a given uid. Returns false on error, true otherwise.
-bool clearUidCpuFreqTimes(uint32_t uid) {
+// This is only suitable for clearing data when an app is uninstalled; if called on a UID with
+// running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that
+// UID.
+bool clearUidTimes(uint32_t uid) {
     if (!gInitialized && !initGlobals()) return false;
-    time_key_t key = {.uid = uid, .freq = 0};
 
-    std::vector<uint32_t> idxs(gNPolicies, 0);
-    for (auto freq : gAllFreqs) {
-        key.freq = freq;
-        if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
+    time_key_t key = {.uid = uid};
+
+    uint32_t maxFreqCount = 0;
+    for (const auto &freqList : gPolicyFreqs) {
+        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+    }
+
+    tis_val_t zeros = {0};
+    std::vector<tis_val_t> vals(gNCpus, zeros);
+    for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+        if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT)
+            return false;
+        if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false;
+    }
+
+    concurrent_val_t czeros = {.policy = {0}, .active = {0}};
+    std::vector<concurrent_val_t> cvals(gNCpus, czeros);
+    for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+        if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT)
+            return false;
+        if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false;
     }
     return true;
 }
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 9f6103e..49469d8 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -22,10 +22,20 @@
 namespace android {
 namespace bpf {
 
-bool startTrackingUidCpuFreqTimes();
-bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
-bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
-bool clearUidCpuFreqTimes(unsigned int uid);
+bool startTrackingUidTimes();
+std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+    getUidsCpuFreqTimes();
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
+
+struct concurrent_time_t {
+    std::vector<uint64_t> active;
+    std::vector<std::vector<uint64_t>> policy;
+};
+
+std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true);
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes();
+bool clearUidTimes(unsigned int uid);
 
 } // namespace bpf
 } // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 9837865..23d87fd 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,57 +1,381 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
+
+#include <bpf_timeinstate.h>
+
+#include <sys/sysinfo.h>
+
+#include <numeric>
 #include <unordered_map>
 #include <vector>
 
 #include <gtest/gtest.h>
 
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
 #include <cputimeinstate.h>
+#include <libbpf.h>
 
 namespace android {
 namespace bpf {
 
+static constexpr uint64_t NSEC_PER_SEC = 1000000000;
+static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
+
 using std::vector;
 
-TEST(TimeInStateTest, SingleUid) {
-    vector<vector<uint64_t>> times;
-    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
-    EXPECT_FALSE(times.empty());
+TEST(TimeInStateTest, SingleUidTimeInState) {
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+    EXPECT_FALSE(times->empty());
 }
 
-TEST(TimeInStateTest, AllUid) {
+TEST(TimeInStateTest, SingleUidConcurrentTimes) {
+    auto concurrentTimes = getUidConcurrentTimes(0);
+    ASSERT_TRUE(concurrentTimes.has_value());
+    ASSERT_FALSE(concurrentTimes->active.empty());
+    ASSERT_FALSE(concurrentTimes->policy.empty());
+
+    uint64_t policyEntries = 0;
+    for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size();
+    ASSERT_EQ(concurrentTimes->active.size(), policyEntries);
+}
+
+static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) {
+    size_t maxPolicyCpus = 0;
+    for (const auto &vec : concurrentTime.policy) {
+        maxPolicyCpus = std::max(maxPolicyCpus, vec.size());
+    }
+    uint64_t policySum = 0;
+    for (size_t i = 0; i < maxPolicyCpus; ++i) {
+        for (const auto &vec : concurrentTime.policy) {
+            if (i < vec.size()) policySum += vec[i];
+        }
+        ASSERT_LE(concurrentTime.active[i], policySum);
+        policySum -= concurrentTime.active[i];
+    }
+    policySum = 0;
+    for (size_t i = 0; i < concurrentTime.active.size(); ++i) {
+        for (const auto &vec : concurrentTime.policy) {
+            if (i < vec.size()) policySum += vec[vec.size() - 1 - i];
+        }
+        auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i];
+        // This check is slightly flaky because we may read a map entry in the middle of an update
+        // when active times have been updated but policy times have not. This happens infrequently
+        // and can be distinguished from more serious bugs by re-running the test: if the underlying
+        // data itself is inconsistent, the test will fail every time.
+        ASSERT_LE(activeSum, policySum);
+        policySum -= activeSum;
+    }
+}
+
+static void TestUidTimesConsistent(const std::vector<std::vector<uint64_t>> &timeInState,
+                                   const struct concurrent_time_t &concurrentTime) {
+    ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime));
+    ASSERT_EQ(timeInState.size(), concurrentTime.policy.size());
+    uint64_t policySum = 0;
+    for (uint32_t i = 0; i < timeInState.size(); ++i) {
+        uint64_t tisSum =
+                std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0);
+        uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(),
+                                                 concurrentTime.policy[i].end(), (uint64_t)0);
+        if (tisSum < concurrentSum)
+            ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC);
+        else
+            ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC);
+        policySum += concurrentSum;
+    }
+    uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(),
+                                         (uint64_t)0);
+    EXPECT_EQ(activeSum, policySum);
+}
+
+TEST(TimeInStateTest, SingleUidTimesConsistent) {
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+
+    auto concurrentTimes = getUidConcurrentTimes(0);
+    ASSERT_TRUE(concurrentTimes.has_value());
+
+    ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes));
+}
+
+TEST(TimeInStateTest, AllUidTimeInState) {
     vector<size_t> sizes;
-    std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
-    ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+    auto map = getUidsCpuFreqTimes();
+    ASSERT_TRUE(map.has_value());
 
-    ASSERT_FALSE(map.empty());
+    ASSERT_FALSE(map->empty());
 
-    auto firstEntry = map.begin()->second;
+    auto firstEntry = map->begin()->second;
     for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
 
-    for (const auto &vec : map) {
+    for (const auto &vec : *map) {
         ASSERT_EQ(vec.second.size(), sizes.size());
         for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
     }
 }
 
+TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
+    auto map = getUidsCpuFreqTimes();
+    ASSERT_TRUE(map.has_value());
+    ASSERT_FALSE(map->empty());
+
+    for (const auto &kv : *map) {
+        uint32_t uid = kv.first;
+        auto times1 = kv.second;
+        auto times2 = getUidCpuFreqTimes(uid);
+        ASSERT_TRUE(times2.has_value());
+
+        ASSERT_EQ(times1.size(), times2->size());
+        for (uint32_t i = 0; i < times1.size(); ++i) {
+            ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+            for (uint32_t j = 0; j < times1[i].size(); ++j) {
+                ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+            }
+        }
+    }
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimes) {
+    auto map = getUidsConcurrentTimes();
+    ASSERT_TRUE(map.has_value());
+    ASSERT_FALSE(map->empty());
+
+    auto firstEntry = map->begin()->second;
+    for (const auto &kv : *map) {
+        ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
+        ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
+        for (size_t i = 0; i < kv.second.policy.size(); ++i) {
+            ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+        }
+    }
+}
+
+TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+    auto map = getUidsConcurrentTimes();
+    ASSERT_TRUE(map.has_value());
+    for (const auto &kv : *map) {
+        uint32_t uid = kv.first;
+        auto times1 = kv.second;
+        auto times2 = getUidConcurrentTimes(uid);
+        ASSERT_TRUE(times2.has_value());
+        for (uint32_t i = 0; i < times1.active.size(); ++i) {
+            ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+        }
+        for (uint32_t i = 0; i < times1.policy.size(); ++i) {
+            for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
+                ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+            }
+        }
+    }
+}
+
+void TestCheckDelta(uint64_t before, uint64_t after) {
+    // Times should never decrease
+    ASSERT_LE(before, after);
+    // UID can't have run for more than ~1s on each CPU
+    ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
+}
+
+TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
+    auto map1 = getUidsCpuFreqTimes();
+    ASSERT_TRUE(map1.has_value());
+    sleep(1);
+    auto map2 = getUidsCpuFreqTimes();
+    ASSERT_TRUE(map2.has_value());
+
+    for (const auto &kv : *map1) {
+        uint32_t uid = kv.first;
+        auto times = kv.second;
+        ASSERT_NE(map2->find(uid), map2->end());
+        for (uint32_t policy = 0; policy < times.size(); ++policy) {
+            for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) {
+                auto before = times[policy][freqIdx];
+                auto after = (*map2)[uid][policy][freqIdx];
+                ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+            }
+        }
+    }
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
+    auto map1 = getUidsConcurrentTimes();
+    ASSERT_TRUE(map1.has_value());
+    ASSERT_FALSE(map1->empty());
+    sleep(1);
+    auto map2 = getUidsConcurrentTimes();
+    ASSERT_TRUE(map2.has_value());
+    ASSERT_FALSE(map2->empty());
+
+    for (const auto &kv : *map1) {
+        uint32_t uid = kv.first;
+        auto times = kv.second;
+        ASSERT_NE(map2->find(uid), map2->end());
+        for (uint32_t i = 0; i < times.active.size(); ++i) {
+            auto before = times.active[i];
+            auto after = (*map2)[uid].active[i];
+            ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+        }
+        for (uint32_t policy = 0; policy < times.policy.size(); ++policy) {
+            for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) {
+                auto before = times.policy[policy][idx];
+                auto after = (*map2)[uid].policy[policy][idx];
+                ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+            }
+        }
+    }
+}
+
+TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
+    auto map = getUidsCpuFreqTimes();
+    ASSERT_TRUE(map.has_value());
+
+    bool foundLargeValue = false;
+    for (const auto &kv : *map) {
+        for (const auto &timeVec : kv.second) {
+            for (const auto &time : timeVec) {
+                ASSERT_LE(time, NSEC_PER_YEAR);
+                if (time > UINT32_MAX) foundLargeValue = true;
+            }
+        }
+    }
+    // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+    // uint64_t as expected, we should have some times higher than that.
+    ASSERT_TRUE(foundLargeValue);
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
+    auto concurrentMap = getUidsConcurrentTimes();
+    ASSERT_TRUE(concurrentMap);
+
+    bool activeFoundLargeValue = false;
+    bool policyFoundLargeValue = false;
+    for (const auto &kv : *concurrentMap) {
+        for (const auto &time : kv.second.active) {
+            ASSERT_LE(time, NSEC_PER_YEAR);
+            if (time > UINT32_MAX) activeFoundLargeValue = true;
+        }
+        for (const auto &policyTimeVec : kv.second.policy) {
+            for (const auto &time : policyTimeVec) {
+                ASSERT_LE(time, NSEC_PER_YEAR);
+                if (time > UINT32_MAX) policyFoundLargeValue = true;
+            }
+        }
+    }
+    // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+    // uint64_t as expected, we should have some times higher than that.
+    ASSERT_TRUE(activeFoundLargeValue);
+    ASSERT_TRUE(policyFoundLargeValue);
+}
+
+TEST(TimeInStateTest, AllUidTimesConsistent) {
+    auto tisMap = getUidsCpuFreqTimes();
+    ASSERT_TRUE(tisMap.has_value());
+
+    auto concurrentMap = getUidsConcurrentTimes();
+    ASSERT_TRUE(concurrentMap.has_value());
+
+    ASSERT_EQ(tisMap->size(), concurrentMap->size());
+    for (const auto &kv : *tisMap) {
+        uint32_t uid = kv.first;
+        auto times = kv.second;
+        ASSERT_NE(concurrentMap->find(uid), concurrentMap->end());
+
+        auto concurrentTimes = (*concurrentMap)[uid];
+        ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes));
+    }
+}
+
 TEST(TimeInStateTest, RemoveUid) {
-    vector<vector<uint64_t>> times, times2;
-    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
-    ASSERT_FALSE(times.empty());
+    uint32_t uid = 0;
+    {
+        // Find an unused UID
+        auto times = getUidsCpuFreqTimes();
+        ASSERT_TRUE(times.has_value());
+        ASSERT_FALSE(times->empty());
+        for (const auto &kv : *times) uid = std::max(uid, kv.first);
+        ++uid;
+    }
+    {
+        // Add a map entry for our fake UID by copying a real map entry
+        android::base::unique_fd fd{
+                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+        ASSERT_GE(fd, 0);
+        time_key_t k;
+        ASSERT_FALSE(getFirstMapKey(fd, &k));
+        std::vector<tis_val_t> vals(get_nprocs_conf());
+        ASSERT_FALSE(findMapEntry(fd, &k, vals.data()));
+        uint32_t copiedUid = k.uid;
+        k.uid = uid;
+        ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
+
+        android::base::unique_fd fd2{
+                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+        k.uid = copiedUid;
+        k.bucket = 0;
+        std::vector<concurrent_val_t> cvals(get_nprocs_conf());
+        ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data()));
+        k.uid = uid;
+        ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST));
+    }
+    auto times = getUidCpuFreqTimes(uid);
+    ASSERT_TRUE(times.has_value());
+    ASSERT_FALSE(times->empty());
+
+    auto concurrentTimes = getUidConcurrentTimes(0);
+    ASSERT_TRUE(concurrentTimes.has_value());
+    ASSERT_FALSE(concurrentTimes->active.empty());
+    ASSERT_FALSE(concurrentTimes->policy.empty());
 
     uint64_t sum = 0;
-    for (size_t i = 0; i < times.size(); ++i) {
-        for (auto x : times[i]) sum += x;
+    for (size_t i = 0; i < times->size(); ++i) {
+        for (auto x : (*times)[i]) sum += x;
     }
     ASSERT_GT(sum, (uint64_t)0);
 
-    ASSERT_TRUE(clearUidCpuFreqTimes(0));
-
-    ASSERT_TRUE(getUidCpuFreqTimes(0, &times2));
-    ASSERT_EQ(times2.size(), times.size());
-    for (size_t i = 0; i < times.size(); ++i) {
-        ASSERT_EQ(times2[i].size(), times[i].size());
-        for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+    uint64_t activeSum = 0;
+    for (size_t i = 0; i < concurrentTimes->active.size(); ++i) {
+        activeSum += concurrentTimes->active[i];
     }
+    ASSERT_GT(activeSum, (uint64_t)0);
+
+    ASSERT_TRUE(clearUidTimes(uid));
+
+    auto allTimes = getUidsCpuFreqTimes();
+    ASSERT_TRUE(allTimes.has_value());
+    ASSERT_FALSE(allTimes->empty());
+    ASSERT_EQ(allTimes->find(uid), allTimes->end());
+
+    auto allConcurrentTimes = getUidsConcurrentTimes();
+    ASSERT_TRUE(allConcurrentTimes.has_value());
+    ASSERT_FALSE(allConcurrentTimes->empty());
+    ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
+}
+
+TEST(TimeInStateTest, GetCpuFreqs) {
+    auto freqs = getCpuFreqs();
+    ASSERT_TRUE(freqs.has_value());
+
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+
+    ASSERT_EQ(freqs->size(), times->size());
+    for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
 }
 
 } // namespace bpf
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 250f902..0ede8b1 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -16,7 +16,9 @@
 #include <set>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <dumputils/dump_utils.h>
 #include <log/log.h>
@@ -32,7 +34,6 @@
         "/system/bin/mediametrics", // media.metrics
         "/system/bin/mediaserver",
         "/system/bin/netd",
-        "/system/bin/vold",
         "/system/bin/sdcard",
         "/system/bin/statsd",
         "/system/bin/surfaceflinger",
@@ -42,11 +43,19 @@
         NULL,
 };
 
+
+// Native processes to dump on debuggable builds.
+static const char* debuggable_native_processes_to_dump[] = {
+        "/system/bin/vold",
+        NULL,
+};
+
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
         "android.hardware.audio@2.0::IDevicesFactory",
         "android.hardware.audio@4.0::IDevicesFactory",
         "android.hardware.audio@5.0::IDevicesFactory",
+        "android.hardware.audio@6.0::IDevicesFactory",
         "android.hardware.biometrics.face@1.0::IBiometricsFace",
         "android.hardware.bluetooth@1.0::IBluetoothHci",
         "android.hardware.camera.provider@2.4::ICameraProvider",
@@ -65,13 +74,34 @@
         NULL,
 };
 
-bool should_dump_hal_interface(const char* interface) {
+/* list of extra hal interfaces to dump containing process during native dumps */
+// This is filled when dumpstate is called.
+static std::set<const std::string> extra_hal_interfaces_to_dump;
+
+static void read_extra_hals_to_dump_from_property() {
+    // extra hals to dump are already filled
+    if (extra_hal_interfaces_to_dump.size() > 0) {
+        return;
+    }
+    std::string value = android::base::GetProperty("ro.dump.hals.extra", "");
+    std::vector<std::string> tokens = android::base::Split(value, ",");
+    for (const auto &token : tokens) {
+        std::string trimmed_token = android::base::Trim(token);
+        if (trimmed_token.length() == 0) {
+            continue;
+        }
+        extra_hal_interfaces_to_dump.insert(trimmed_token);
+    }
+}
+
+// check if interface is included in either default hal list or extra hal list
+bool should_dump_hal_interface(const std::string& interface) {
     for (const char** i = hal_interfaces_to_dump; *i; i++) {
-        if (!strcmp(*i, interface)) {
+        if (interface == *i) {
             return true;
         }
     }
-    return false;
+    return extra_hal_interfaces_to_dump.find(interface) != extra_hal_interfaces_to_dump.end();
 }
 
 bool should_dump_native_traces(const char* path) {
@@ -80,6 +110,15 @@
             return true;
         }
     }
+
+    if (android::base::GetBoolProperty("ro.debuggable", false)) {
+        for (const char** p = debuggable_native_processes_to_dump; *p; p++) {
+            if (!strcmp(*p, path)) {
+                return true;
+            }
+        }
+    }
+
     return false;
 }
 
@@ -91,13 +130,15 @@
     sp<IServiceManager> manager = IServiceManager::getService();
     std::set<int> pids;
 
+    read_extra_hals_to_dump_from_property();
+
     Return<void> ret = manager->debugDump([&](auto& hals) {
         for (const auto &info : hals) {
             if (info.pid == static_cast<int>(IServiceManager::PidConstant::NO_PID)) {
                 continue;
             }
 
-            if (!should_dump_hal_interface(info.interfaceName.c_str())) {
+            if (!should_dump_hal_interface(info.interfaceName)) {
                 continue;
             }
 
diff --git a/libs/gralloc/OWNERS b/libs/gralloc/OWNERS
new file mode 100644
index 0000000..67743cd
--- /dev/null
+++ b/libs/gralloc/OWNERS
@@ -0,0 +1,2 @@
+marissaw@google.com
+vhau@google.com
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 92ab410..3efb1b6 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -981,6 +981,17 @@
         item.mGraphicBuffer.clear();
     }
 
+    // Update and get FrameEventHistory.
+    nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    NewFrameEventsEntry newFrameEventsEntry = {
+        currentFrameNumber,
+        postedTime,
+        requestedPresentTimestamp,
+        std::move(acquireFenceTime)
+    };
+    addAndGetFrameTimestamps(&newFrameEventsEntry,
+            getFrameTimestamps ? &output->frameTimestamps : nullptr);
+
     // Call back without the main BufferQueue lock held, but with the callback
     // lock held so we can ensure that callbacks occur in order
 
@@ -1010,17 +1021,6 @@
         mCallbackCondition.notify_all();
     }
 
-    // Update and get FrameEventHistory.
-    nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
-    NewFrameEventsEntry newFrameEventsEntry = {
-        currentFrameNumber,
-        postedTime,
-        requestedPresentTimestamp,
-        std::move(acquireFenceTime)
-    };
-    addAndGetFrameTimestamps(&newFrameEventsEntry,
-            getFrameTimestamps ? &output->frameTimestamps : nullptr);
-
     // Wait without lock held
     if (connectedApi == NATIVE_WINDOW_API_EGL) {
         // Waiting here allows for two full buffers to be queued but not a
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 73150dc..c13401d 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,7 +1,12 @@
+adyabr@google.com
+akrulec@google.com
+alecmouri@google.com
 jessehall@google.com
 jwcai@google.com
 lpy@google.com
 marissaw@google.com
 mathias@google.com
 racarr@google.com
+steventhomas@google.com
 stoza@google.com
+vhau@google.com
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 139987e..abc9103 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -577,7 +577,8 @@
     uint32_t len = static_cast<uint32_t>(string8.length());
     FlattenableUtils::write(buffer, size, len);
     memcpy(static_cast<char*>(buffer), string8.string(), len);
-    FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+    FlattenableUtils::advance(buffer, size, len);
+    size -= FlattenableUtils::align<4>(buffer);
 }
 
 bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& outputString8) {
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 42b578c..080336b 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -32,12 +32,6 @@
     sanitize: {
         integer_overflow: true,
         misc_undefined: ["bounds"],
-        diag: {
-            misc_undefined: ["bounds"],
-            no_recover: [
-                "bounds",
-            ],
-        },
     },
 
     srcs: [
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index f1aa89c..5f1c71e 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,9 +61,9 @@
 
 GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
-size_t GraphicBufferAllocator::getTotalSize() const {
+uint64_t GraphicBufferAllocator::getTotalSize() const {
     Mutex::Autolock _l(sLock);
-    size_t total = 0;
+    uint64_t total = 0;
     for (size_t i = 0; i < sAllocList.size(); ++i) {
         total += sAllocList.valueAt(i).size;
     }
@@ -73,7 +73,7 @@
 void GraphicBufferAllocator::dump(std::string& result) const {
     Mutex::Autolock _l(sLock);
     KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
-    size_t total = 0;
+    uint64_t total = 0;
     result.append("Allocated buffers:\n");
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 25d4512..faec978 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -49,7 +49,7 @@
 
     status_t free(buffer_handle_t handle);
 
-    size_t getTotalSize() const;
+    uint64_t getTotalSize() const;
 
     void dump(std::string& res) const;
     static void dumpToSystemLog();
diff --git a/libs/vr/OWNERS b/libs/vr/OWNERS
index ec2d712..098c80e 100644
--- a/libs/vr/OWNERS
+++ b/libs/vr/OWNERS
@@ -1,4 +1,4 @@
 hendrikw@google.com
 jwcai@google.com
 steventhomas@google.com
-
+patplunkett@google.com
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 1a9d727..23a4224 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -53,6 +53,8 @@
         "libpdx",
         "liblog",
         "libutils",
+    ],
+    shared_libs: [
         "libvndksupport",
     ],
 }
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index eb90c8b..3c741ab 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -161,6 +161,10 @@
     ],
     ldflags: ["-Wl,--exclude-libs=ALL"],
     export_include_dirs: ["EGL/include"],
+    stubs: {
+        symbol_file: "libEGL.map.txt",
+        versions: ["29"],
+    },
 }
 
 cc_test {
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index da9bb49..41fcf1b 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -91,8 +91,8 @@
 rm src/*.class
 
 # Add UnsupportedAppUsage.java to known sources.
-mkdir -p out/android/annotation
-cp ../../../../base/core/java/android/annotation/UnsupportedAppUsage.java out/android/annotation
+mkdir -p out/android/compat/annotation
+cp ../../../../../tools/platform-compat/annotation/src/java/android/compat/annotation/UnsupportedAppUsage.java out/android/compat/annotation
 
 pushd out > /dev/null
 mkdir classes
@@ -114,7 +114,7 @@
                     android/opengl/GLES31.java \
                     android/opengl/GLES31Ext.java \
                     android/opengl/GLES32.java \
-                    android/annotation/UnsupportedAppUsage.java
+                    android/compat/annotation/UnsupportedAppUsage.java
 popd > /dev/null
 JAVA_RESULT=$?
 if [ $JAVA_RESULT -ne 0 ]; then
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index 12728f5..9932556 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -18,7 +18,7 @@
 
 package android.opengl;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
index c2711aa..7db1101 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
@@ -19,7 +19,7 @@
 
 package android.opengl;
 
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
 
 /** OpenGL ES 2.0
  */
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 69d8c89..f2bc65d 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,4 +5,6 @@
 lpy@google.com
 marissaw@google.com
 racarr@google.com
-stoza@google.com
\ No newline at end of file
+steventhomas@google.com
+stoza@google.com
+vhau@google.com
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index aea602b..d3942e8 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -2,6 +2,7 @@
     class core animation
     user system
     group graphics drmrpc readproc
+    capabilities SYS_NICE
     onrestart restart zygote
     writepid /dev/stune/foreground/tasks
     socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 766d9ff..1419119 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -708,20 +708,6 @@
 
     const InstanceData& instance_data = GetData(pdev);
 
-    // TODO(jessehall): Fill out the set of supported formats. Longer term, add
-    // a new gralloc method to query whether a (format, usage) pair is
-    // supported, and check that for each gralloc format that corresponds to a
-    // Vulkan format. Shorter term, just add a few more formats to the ones
-    // hardcoded below.
-
-    const VkSurfaceFormatKHR kFormats[] = {
-        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-    };
-    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
-    uint32_t total_num_formats = kNumFormats;
-
     bool wide_color_support = false;
     Surface& surface = *SurfaceFromHandle(surface_handle);
     int err = native_window_get_wide_color_support(surface.window.get(),
@@ -735,43 +721,72 @@
         wide_color_support &&
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
 
-    const VkSurfaceFormatKHR kWideColorFormats[] = {
-        {VK_FORMAT_R8G8B8A8_UNORM,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-        {VK_FORMAT_R8G8B8A8_SRGB,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
-        {VK_FORMAT_A2B10G10R10_UNORM_PACK32,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-    };
-    const uint32_t kNumWideColorFormats =
-        sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
+    AHardwareBuffer_Desc desc = {};
+    desc.width = 1;
+    desc.height = 1;
+    desc.layers = 1;
+    desc.usage = surface.consumer_usage |
+                 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                 AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
+
+    // We must support R8G8B8A8
+    std::vector<VkSurfaceFormatKHR> all_formats = {
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+
     if (wide_color_support) {
-        total_num_formats += kNumWideColorFormats;
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        if (wide_color_support) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+                                   VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT});
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+                                   VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT});
+        }
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(
+            VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                               VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        if (wide_color_support) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                                   VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+        }
     }
 
     VkResult result = VK_SUCCESS;
     if (formats) {
-        uint32_t out_count = 0;
-        uint32_t transfer_count = 0;
-        if (*count < total_num_formats)
+        uint32_t transfer_count = all_formats.size();
+        if (transfer_count > *count) {
+            transfer_count = *count;
             result = VK_INCOMPLETE;
-        transfer_count = std::min(*count, kNumFormats);
-        std::copy(kFormats, kFormats + transfer_count, formats);
-        out_count += transfer_count;
-        if (wide_color_support) {
-            transfer_count = std::min(*count - out_count, kNumWideColorFormats);
-            std::copy(kWideColorFormats, kWideColorFormats + transfer_count,
-                      formats + out_count);
-            out_count += transfer_count;
         }
-        *count = out_count;
+        std::copy(all_formats.begin(), all_formats.begin() + transfer_count,
+                  formats);
+        *count = transfer_count;
     } else {
-        *count = total_num_formats;
+        *count = all_formats.size();
     }
+
     return result;
 }