DO NOT MERGE - Merge pi-dev@5234907 into stage-aosp-master

Bug: 120848293
Change-Id: Icba28487cde3a6e33898450eaf53ee2be58a3dc8
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 4459cef..a282424 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -105,6 +105,12 @@
     chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
     chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill/enable
     chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/enable
+    chmod 0666 /sys/kernel/tracing/events/oom/oom_score_adj_update/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/task/task_rename/enable
+    chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable
+    chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
@@ -138,6 +144,12 @@
     chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
     chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
 
+    # filemap events for iorapd
+    chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+    chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+
 # Tracing disabled by default
     write /sys/kernel/debug/tracing/tracing_on 0
     write /sys/kernel/tracing/tracing_on 0
@@ -163,7 +175,7 @@
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu5/trace
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu6/trace
-    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu7/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu7/trace
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu8/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu8/trace
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 9aa1075..ee32cb4 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -57,7 +57,6 @@
         export_aidl_headers: true,
     },
     srcs: [
-        "binder/android/os/DumpstateOptions.cpp",
         ":dumpstate_aidl",
     ],
     export_include_dirs: ["binder"],
@@ -68,7 +67,6 @@
     srcs: [
         "binder/android/os/IDumpstateListener.aidl",
         "binder/android/os/IDumpstateToken.aidl",
-        //"binder/android/os/DumpstateOptions.aidl",
         "binder/android/os/IDumpstate.aidl",
     ],
     path: "binder",
@@ -99,8 +97,9 @@
         "utils.cpp",
     ],
     static_libs: [
+        "libincidentcompanion",
         "libdumpsys",
-        "libserviceutils"
+        "libserviceutils",
     ],
 }
 
@@ -158,3 +157,22 @@
     ],
     static_libs: ["libgmock"],
 }
+
+
+// =======================#
+// dumpstate_test_fixture #
+// =======================#
+cc_test {
+
+    name: "dumpstate_test_fixture",
+    test_suites: ["device-tests"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+    srcs: ["tests/dumpstate_test_fixture.cpp"],
+    data: ["tests/testdata/**/*"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
deleted file mode 100644
index ea5fbf1..0000000
--- a/cmds/dumpstate/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# =======================#
-# dumpstate_test_fixture #
-# =======================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test_fixture
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := \
-       -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES := \
-        tests/dumpstate_test_fixture.cpp
-
-LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 6596fa2..768cb4f 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -18,8 +18,9 @@
 
 #include "DumpstateService.h"
 
-#include <android-base/stringprintf.h>
+#include <memory>
 
+#include <android-base/stringprintf.h>
 #include "android/os/BnDumpstate.h"
 
 #include "DumpstateInternal.h"
@@ -31,28 +32,37 @@
 
 namespace {
 
+struct DumpstateInfo {
+  public:
+    Dumpstate* ds = nullptr;
+    int32_t calling_uid = -1;
+    std::string calling_package;
+};
+
 static binder::Status exception(uint32_t code, const std::string& msg) {
     MYLOGE("%s (%d) ", msg.c_str(), code);
     return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
 }
 
-static binder::Status error(uint32_t code, const std::string& msg) {
-    MYLOGE("%s (%d) ", msg.c_str(), code);
-    return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
+// Creates a bugreport and exits, thus preserving the oneshot nature of the service.
+// Note: takes ownership of data.
+[[noreturn]] static void* dumpstate_thread_main(void* data) {
+    std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
+    ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
+    MYLOGD("Finished taking a bugreport. Exiting.\n");
+    exit(0);
 }
 
-static void* callAndNotify(void* data) {
-    Dumpstate& ds = *static_cast<Dumpstate*>(data);
-    // TODO(111441001): Return status on listener.
-    ds.Run();
-    MYLOGE("Finished Run()\n");
-    return nullptr;
+[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
+    listener->onError(error_code);
+    exit(0);
 }
 
 class DumpstateToken : public BnDumpstateToken {};
-}
 
-DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
+}  // namespace
+
+DumpstateService::DumpstateService() : ds_(nullptr) {
 }
 
 char const* DumpstateService::getServiceName() {
@@ -71,6 +81,8 @@
     return android::OK;
 }
 
+// Note: this method is part of the old flow and is not expected to be used in combination
+// with startBugreport.
 binder::Status DumpstateService::setListener(const std::string& name,
                                              const sp<IDumpstateListener>& listener,
                                              bool getSectionDetails,
@@ -85,25 +97,49 @@
         return binder::Status::ok();
     }
     std::lock_guard<std::mutex> lock(lock_);
-    if (ds_.listener_ != nullptr) {
-        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_.listener_name_.c_str());
+    if (ds_ == nullptr) {
+        ds_ = &(Dumpstate::GetInstance());
+    }
+    if (ds_->listener_ != nullptr) {
+        MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
         return binder::Status::ok();
     }
 
-    ds_.listener_name_ = name;
-    ds_.listener_ = listener;
-    ds_.report_section_ = getSectionDetails;
+    ds_->listener_name_ = name;
+    ds_->listener_ = listener;
+    ds_->report_section_ = getSectionDetails;
     *returned_token = new DumpstateToken();
 
     return binder::Status::ok();
 }
 
-binder::Status DumpstateService::startBugreport(const android::base::unique_fd& bugreport_fd,
+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,
                                                 int bugreport_mode,
                                                 const sp<IDumpstateListener>& listener) {
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
+    // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
+    // time.
+    std::lock_guard<std::mutex> lock(lock_);
+    if (ds_ != nullptr) {
+        MYLOGE("Error! There is already a bugreport in progress. Returning.");
+        if (listener != nullptr) {
+            listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+        }
+        return exception(binder::Status::EX_SERVICE_SPECIFIC,
+                         "There is already a bugreport in progress");
+    }
+
+    // From here on, all conditions that indicate we are done with this incoming request should
+    // result in exiting the service to free it up for next invocation.
+    if (listener == nullptr) {
+        MYLOGE("Invalid input: no listener");
+        exit(0);
+    }
+
     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
@@ -111,58 +147,79 @@
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
         bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
-        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
-                         StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
+        MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode);
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
     }
 
     if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
-        return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Invalid file descriptor");
+        // TODO(b/111441001): screenshot fd should be optional
+        MYLOGE("Invalid filedescriptor");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
     }
 
     std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
     options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
                         screenshot_fd);
 
-    std::lock_guard<std::mutex> lock(lock_);
-    // TODO(b/111441001): Disallow multiple simultaneous bugreports.
-    ds_.SetOptions(std::move(options));
-    if (listener != nullptr) {
-        ds_.listener_ = listener;
-    }
+    ds_ = &(Dumpstate::GetInstance());
+    ds_->SetOptions(std::move(options));
+    ds_->listener_ = listener;
+
+    DumpstateInfo* ds_info = new DumpstateInfo();
+    ds_info->ds = ds_;
+    ds_info->calling_uid = calling_uid;
+    ds_info->calling_package = calling_package;
 
     pthread_t thread;
-    status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_);
+    status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info);
     if (err != 0) {
-        return error(err, "Could not create a background thread.");
+        delete ds_info;
+        ds_info = nullptr;
+        MYLOGE("Could not create a thread");
+        signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
     }
     return binder::Status::ok();
 }
 
+binder::Status DumpstateService::cancelBugreport() {
+    // This is a no-op since the cancellation is done from java side via setting sys properties.
+    // See BugreportManagerServiceImpl.
+    // TODO(b/111441001): maybe make native and java sides use different binder interface
+    // to avoid these annoyances.
+    return binder::Status::ok();
+}
+
 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
-    dprintf(fd, "id: %d\n", ds_.id_);
-    dprintf(fd, "pid: %d\n", ds_.pid_);
-    dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
-    dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
-    dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
+    if (ds_ == nullptr) {
+        dprintf(fd, "Bugreport not in progress yet");
+        return NO_ERROR;
+    }
+    std::string destination = ds_->options_->bugreport_fd.get() != -1
+                                  ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get())
+                                  : ds_->bugreport_internal_dir_.c_str();
+    dprintf(fd, "id: %d\n", ds_->id_);
+    dprintf(fd, "pid: %d\n", ds_->pid_);
+    dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
+    dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
+    dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
     dprintf(fd, "progress:\n");
-    ds_.progress_->Dump(fd, "  ");
-    dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
-    dprintf(fd, "version: %s\n", ds_.version_.c_str());
-    dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
-    dprintf(fd, "bugreport_internal_dir_: %s\n", ds_.bugreport_internal_dir_.c_str());
-    dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
-    dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
-    dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
-    dprintf(fd, "path: %s\n", ds_.path_.c_str());
-    dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
-    dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
-    dprintf(fd, "name: %s\n", ds_.name_.c_str());
-    dprintf(fd, "now: %ld\n", ds_.now_);
-    dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
-    dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
-    dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
-    dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
+    ds_->progress_->Dump(fd, "  ");
+    dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "version: %s\n", ds_->version_.c_str());
+    dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
+    dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
+    dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
+    dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
+    dprintf(fd, "path: %s\n", ds_->path_.c_str());
+    dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+    dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
+    dprintf(fd, "name: %s\n", ds_->name_.c_str());
+    dprintf(fd, "now: %ld\n", ds_->now_);
+    dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
+    dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
+    dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
+    dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
 
     return NO_ERROR;
 }
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 1705317..68eda47 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -42,12 +42,20 @@
                                bool getSectionDetails,
                                sp<IDumpstateToken>* returned_token) override;
 
-    binder::Status startBugreport(const android::base::unique_fd& bugreport_fd,
+    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,
                                   const sp<IDumpstateListener>& listener) override;
 
+    // No-op
+    binder::Status cancelBugreport();
+
   private:
-    Dumpstate& ds_;
+    // Dumpstate object which contains all the bugreporting logic.
+    // Note that dumpstate is a oneshot service, so this object is meant to be used at most for
+    // one bugreport.
+    // This service does not own this object.
+    Dumpstate* ds_;
     std::mutex lock_;
 };
 
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 6ac17d8..c818c05 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -14,7 +14,8 @@
 mmm -j frameworks/native/cmds/dumpstate
 ```
 
-If you're working on device-specific code, you might need to build them as well. Example:
+If you're working on device-specific code, you might need to build them as well.
+Example:
 
 ```
 mmm -j frameworks/native/cmds/dumpstate device/acme/secret_device/dumpstate/ hardware/interfaces/dumpstate
@@ -23,20 +24,23 @@
 ## To build, deploy, and take a bugreport
 
 ```
-mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb shell am bug-report
+mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb push ${OUT}/system/lib64/*dumpstate*.so /system/lib64/ && adb shell am bug-report
 ```
 
-Make sure that the device is remounted before running the above command.
-* If you're working with `userdebug` variant, you may need to run the following to remount your device:
+Make sure that the device is remounted before running the above command. * If
+you're working with `userdebug` variant, you may need to run the following to
+remount your device:
 
-  ```
+```
   adb root && adb remount -R && adb wait-for-device && adb root && adb remount
-  ```
-* If you're working with `eng` variant, you may need to run the following to remount your device:
+```
 
-  ```
-  adb root && adb remount
-  ```
+*   If you're working with `eng` variant, you may need to run the following to
+    remount your device:
+
+    ```
+    adb root && adb remount
+    ```
 
 ## To build, deploy, and run unit tests
 
@@ -49,7 +53,7 @@
 Then run:
 
 ```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
 ```
 
 And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
@@ -82,7 +86,6 @@
 adb shell setprop dumpstate.version split-dumpsys && adb shell dumpstate -v
 ```
 
-
 Then to restore the default version:
 
 ```
@@ -91,8 +94,9 @@
 
 ## Code style and formatting
 
-Use the style defined at the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
-and make sure to run the following command prior to `repo upload`:
+Use the style defined at the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
+make sure to run the following command prior to `repo upload`:
 
 ```
 git clang-format --style=file HEAD~
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
deleted file mode 100644
index 5654190..0000000
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
+++ /dev/null
@@ -1,46 +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/os/DumpstateOptions.h>
-
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-namespace android {
-namespace os {
-
-status_t DumpstateOptions::readFromParcel(const ::android::Parcel* parcel) {
-    if (status_t err = parcel->readBool(&get_section_details)) {
-        return err;
-    }
-    if (status_t err = parcel->readUtf8FromUtf16(&name)) {
-        return err;
-    }
-    return android::OK;
-}
-
-status_t DumpstateOptions::writeToParcel(::android::Parcel* parcel) const {
-    if (status_t err = parcel->writeBool(get_section_details)) {
-        return err;
-    }
-    if (status_t err = parcel->writeUtf8AsUtf16(name)) {
-        return err;
-    }
-    return android::OK;
-}
-
-}  // namespace os
-}  // namespace android
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.h b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
deleted file mode 100644
index a748e3c..0000000
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.h
+++ /dev/null
@@ -1,39 +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.
- */
-
-#ifndef ANDROID_OS_DUMPSTATE_OPTIONS_H_
-#define ANDROID_OS_DUMPSTATE_OPTIONS_H_
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-struct DumpstateOptions : public android::Parcelable {
-    // If true the caller can get callbacks with per-section progress details.
-    bool get_section_details = false;
-
-    // Name of the caller.
-    std::string name;
-
-    status_t writeToParcel(android::Parcel* parcel) const override;
-    status_t readFromParcel(const android::Parcel* parcel) override;
-};
-
-}  // namespace os
-}  // namespace android
-
-#endif  // ANDROID_OS_DUMPSTATE_OPTIONS_H_
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index d24c953..37ff442 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -18,7 +18,6 @@
 
 import android.os.IDumpstateListener;
 import android.os.IDumpstateToken;
-import android.os.DumpstateOptions;
 
 /**
   * Binder interface for the currently running dumpstate process.
@@ -37,6 +36,9 @@
     IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
                                 boolean getSectionDetails);
 
+    // NOTE: If you add to or change these modes, please also change the corresponding enums
+    // in system server, in BugreportParams.java.
+
     // These modes encapsulate a set of run time options for generating bugreports.
     // Takes a bugreport without user interference.
     const int BUGREPORT_MODE_FULL = 0;
@@ -59,14 +61,29 @@
     // Default mode.
     const int BUGREPORT_MODE_DEFAULT = 6;
 
+    // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
     /*
      * Starts a bugreport in the background.
      *
+     *<p>Shows the user a dialog to get consent for sharing the bugreport with the calling
+     * application. If they deny {@link IDumpstateListener#onError} will be called. If they
+     * consent and bugreport generation is successful artifacts will be copied to the given fds and
+     * {@link IDumpstateListener#onFinished} will be called. If there
+     * are errors in bugreport generation {@link IDumpstateListener#onError} will be called.
+     *
+     * @param callingUid UID of the original application that requested the report.
+     * @param callingPackage package of the original application that requested the report.
      * @param bugreportFd the file to which the zipped bugreport should be written
      * @param screenshotFd the file to which screenshot should be written; optional
      * @param bugreportMode the mode that specifies other run time options; must be one of above
      * @param listener callback for updates; optional
      */
-    void startBugreport(FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode,
-                        IDumpstateListener listener);
+    void startBugreport(int callingUid, @utf8InCpp String callingPackage,
+                        FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+                        int bugreportMode, IDumpstateListener listener);
+
+    /*
+     * Cancels the bugreport currently in progress.
+     */
+    void cancelBugreport();
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 2966c86..42858e0 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -19,6 +19,11 @@
 /**
   * Listener for dumpstate events.
   *
+  * <p>When bugreport creation is complete one of {@code onError} or {@code onFinished} is called.
+  *
+  * <p>These methods are synchronous by design in order to make dumpstate's lifecycle simpler
+  * to handle.
+  *
   * {@hide}
   */
 interface IDumpstateListener {
@@ -27,7 +32,10 @@
      *
      * @param progress the progress in [0, 100]
      */
-    oneway void onProgress(int progress);
+    void onProgress(int progress);
+
+    // NOTE: If you add to or change these error codes, please also change the corresponding enums
+    // in system server, in BugreportManager.java.
 
     /* Options specified are invalid or incompatible */
     const int BUGREPORT_ERROR_INVALID_INPUT = 1;
@@ -35,20 +43,24 @@
     /* Bugreport encountered a runtime error */
     const int BUGREPORT_ERROR_RUNTIME_ERROR = 2;
 
+    /* User denied consent to share the bugreport with the specified app */
+    const int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3;
+
+    /* The request to get user consent timed out */
+    const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
+
+    /* There is currently a bugreport running. The caller should try again later. */
+    const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+
     /**
      * Called on an error condition with one of the error codes listed above.
      */
-    oneway void onError(int errorCode);
+    void onError(int errorCode);
 
     /**
-     * Called when taking bugreport finishes successfully
-     *
-     * @param durationMs time capturing bugreport took in milliseconds
-     * @param title title for the bugreport; helpful in reminding the user why they took it
-     * @param description detailed description for the bugreport
+     * Called when taking bugreport finishes successfully.
      */
-     oneway void onFinished(long durationMs, @utf8InCpp String title,
-                            @utf8InCpp String description);
+    void onFinished();
 
     // TODO(b/111441001): Remove old methods when not used anymore.
     void onProgressUpdated(int progress);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 712f861..06dc58f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -51,6 +51,7 @@
 #include <android-base/unique_fd.h>
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/os/IIncidentCompanion.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <dumpsys.h>
@@ -83,15 +84,19 @@
 using android::UNKNOWN_ERROR;
 using android::Vector;
 using android::base::StringPrintf;
+using android::os::IDumpstateListener;
 using android::os::dumpstate::CommandOptions;
 using android::os::dumpstate::DumpFileToFd;
 using android::os::dumpstate::DumpstateSectionReporter;
 using android::os::dumpstate::GetPidByName;
 using android::os::dumpstate::PropertiesHelper;
 
+typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
+
 /* read before root is shed */
 static char cmdline_buf[16384] = "(unknown)";
 static const char *dump_traces_path = nullptr;
+static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
 
 // TODO: variables and functions below should be part of dumpstate object
 
@@ -108,6 +113,7 @@
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
+#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
 #define WLUTIL "/vendor/xbin/wlutil"
 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
 
@@ -135,10 +141,6 @@
     return fd;
 }
 
-static int OpenForWrite(std::string path) {
-    return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
-                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-}
 
 static int OpenForRead(std::string path) {
     return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
@@ -156,7 +158,7 @@
 }
 
 static bool CopyFileToFd(const std::string& input_file, int out_fd) {
-    MYLOGD("Going to copy bugreport file (%s) to %d\n", ds.path_.c_str(), out_fd);
+    MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
 
     // Obtain a handle to the source file.
     android::base::unique_fd in_fd(OpenForRead(input_file));
@@ -164,21 +166,17 @@
         if (CopyFile(in_fd.get(), out_fd)) {
             return true;
         }
-        MYLOGE("Failed to copy zip file: %s\n", strerror(errno));
+        MYLOGE("Failed to copy file: %s\n", strerror(errno));
     }
     return false;
 }
 
-static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
-    if (input_file == output_file) {
-        MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
-               output_file.c_str());
+static bool UnlinkAndLogOnError(const std::string& file) {
+    if (unlink(file.c_str())) {
+        MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
         return false;
     }
-
-    MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
-    android::base::unique_fd out_fd(OpenForWrite(output_file));
-    return CopyFileToFd(input_file, out_fd.get());
+    return true;
 }
 
 }  // namespace
@@ -463,9 +461,7 @@
             if (!ds.AddZipEntry("anrd_trace.txt", path)) {
                 MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
             } else {
-                if (remove(path)) {
-                    MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
-                }
+                android::os::UnlinkAndLogOnError(path);
                 return true;
             }
         } else {
@@ -475,47 +471,6 @@
     return false;
 }
 
-static void dump_systrace() {
-    if (!ds.IsZipping()) {
-        MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
-        return;
-    }
-    std::string systrace_path = ds.GetPath("-systrace.txt");
-    if (systrace_path.empty()) {
-        MYLOGE("Not dumping systrace because path is empty\n");
-        return;
-    }
-    const char* path = "/sys/kernel/debug/tracing/tracing_on";
-    long int is_tracing;
-    if (read_file_as_long(path, &is_tracing)) {
-        return; // error already logged
-    }
-    if (is_tracing <= 0) {
-        MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
-        return;
-    }
-
-    MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
-            systrace_path.c_str());
-    if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
-                   CommandOptions::WithTimeout(120).Build())) {
-        MYLOGE("systrace timed out, its zip entry will be incomplete\n");
-        // TODO: RunCommand tries to kill the process, but atrace doesn't die
-        // peacefully; ideally, we should call strace to stop itself, but there is no such option
-        // yet (just a --async_stop, which stops and dump
-        // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
-        //   MYLOGE("could not stop systrace ");
-        // }
-    }
-    if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
-        MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
-    } else {
-        if (remove(systrace_path.c_str())) {
-            MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
-        }
-    }
-}
-
 static bool skip_not_stat(const char *path) {
     static const char stat[] = "/stat";
     size_t len = strlen(path);
@@ -713,6 +668,32 @@
     return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
 }
 
+Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
+    std::lock_guard<std::mutex> lock(lock_);
+    result_ = APPROVED;
+    MYLOGD("User approved consent to share bugreport\n");
+    return android::binder::Status::ok();
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
+    std::lock_guard<std::mutex> lock(lock_);
+    result_ = DENIED;
+    MYLOGW("User denied consent to share bugreport\n");
+    return android::binder::Status::ok();
+}
+
+UserConsentResult Dumpstate::ConsentCallback::getResult() {
+    std::lock_guard<std::mutex> lock(lock_);
+    return result_;
+}
+
+uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
+    return Nanotime() - start_time_;
+}
+
 void Dumpstate::PrintHeader() const {
     std::string build, fingerprint, radio, bootloader, network;
     char date[80];
@@ -785,6 +766,17 @@
                ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
     }
+    bool finished_entry = false;
+    auto finish_entry = [this, &finished_entry] {
+        if (!finished_entry) {
+            // This should only be called when we're going to return an earlier error,
+            // which would've been logged. This may imply the file is already corrupt
+            // and any further logging from FinishEntry is more likely to mislead than
+            // not.
+            this->zip_writer_->FinishEntry();
+        }
+    };
+    auto scope_guard = android::base::make_scope_guard(finish_entry);
     auto start = std::chrono::steady_clock::now();
     auto end = start + timeout;
     struct pollfd pfd = {fd, POLLIN};
@@ -801,11 +793,11 @@
 
             int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
             if (rc < 0) {
-                MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
-                       strerror(errno));
+                MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
+                       entry_name.c_str(), strerror(errno));
                 return -errno;
             } else if (rc == 0) {
-                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
                        entry_name.c_str(), strerror(errno), timeout.count());
                 return TIMED_OUT;
             }
@@ -826,6 +818,7 @@
     }
 
     err = zip_writer_->FinishEntry();
+    finished_entry = true;
     if (err != 0) {
         MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
@@ -999,6 +992,8 @@
 
     AddAnrTraceDir(add_to_zip, anr_traces_dir);
 
+    RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
+
     // Slow traces for slow operations.
     struct stat st;
     int i = 0;
@@ -1346,6 +1341,7 @@
     DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
     DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
 
+    RunDumpsys("WINSCOPE TRACE", {"window", "trace"});
     /* Add window and surface trace files. */
     if (!PropertiesHelper::IsUserBuild()) {
         ds.AddDir(WMTRACE_DATA_DIR, false);
@@ -1440,12 +1436,8 @@
 
 /* Dumps state for the default case. Returns true if everything went fine. */
 static bool DumpstateDefault() {
-    // Dumps systrace right away, otherwise it will be filled with unnecessary events.
-    // First try to dump anrd trace if the daemon is running. Otherwise, dump
-    // the raw trace.
-    if (!dump_anrd_trace()) {
-        dump_systrace();
-    }
+    // Try to dump anrd trace if the daemon is running.
+    dump_anrd_trace();
 
     // Invoking the following dumpsys calls before dump_traces() to try and
     // keep the system stats as close to its initial state as possible.
@@ -1469,15 +1461,24 @@
     add_mountinfo();
     DumpIpTablesAsRoot();
 
-    // Capture any IPSec policies in play.  No keys are exposed here.
+    // Capture any IPSec policies in play. No keys are exposed here.
     RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
 
+    // Dump IPsec stats. No keys are exposed here.
+    DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
+
     // Run ss as root so we can see socket marks.
     RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
 
     // Run iotop as root to show top 100 IO threads
     RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
 
+    // Gather shared memory buffer info if the product implements it
+    struct stat st;
+    if (!stat("/product/bin/dmabuf_dump", &st)) {
+        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
+    }
+
     if (!DropRootUser()) {
         return false;
     }
@@ -1596,13 +1597,8 @@
     for (int i = 0; i < NUM_OF_DUMPS; i++) {
         paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
                                         kDumpstateBoardFiles[i].c_str()));
-        remover.emplace_back(android::base::make_scope_guard(std::bind(
-            [](std::string path) {
-                if (remove(path.c_str()) != 0 && errno != ENOENT) {
-                    MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
-                }
-            },
-            paths[i])));
+        remover.emplace_back(android::base::make_scope_guard(
+            std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
     }
 
     sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
@@ -1714,6 +1710,7 @@
             "progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
+            "  -w: start binder service and make it wait for a call to startBugreport\n"
             "  -v: prints the dumpstate header and exit\n");
 }
 
@@ -1762,9 +1759,7 @@
     ds.zip_file.reset(nullptr);
 
     MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
-    if (remove(tmp_path_.c_str()) != 0) {
-        MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
-    }
+    android::os::UnlinkAndLogOnError(tmp_path_);
 
     return true;
 }
@@ -1845,16 +1840,9 @@
 static void PrepareToWriteToFile() {
     MaybeResolveSymlink(&ds.bugreport_internal_dir_);
 
-    std::string base_name_part1 = "bugreport";
-    if (!ds.options_->use_outfile.empty()) {
-        ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
-        base_name_part1 = basename(ds.options_->use_outfile.c_str());
-    }
-
     std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
     std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
-    ds.base_name_ =
-        StringPrintf("%s-%s-%s", base_name_part1.c_str(), device_name.c_str(), build_id.c_str());
+    ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
     if (ds.options_->do_add_date) {
         char date[80];
         strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
@@ -1877,17 +1865,16 @@
 
     std::string destination = ds.options_->bugreport_fd.get() != -1
                                   ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
-                                  : ds.bugreport_dir_.c_str();
+                                  : ds.bugreport_internal_dir_.c_str();
     MYLOGD(
         "Bugreport dir: %s\n"
-        "Internal Bugreport dir: %s\n"
         "Base name: %s\n"
         "Suffix: %s\n"
         "Log path: %s\n"
         "Temporary path: %s\n"
         "Screenshot path: %s\n",
-        destination.c_str(), ds.bugreport_internal_dir_.c_str(), ds.base_name_.c_str(),
-        ds.name_.c_str(), ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
+        destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
+        ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
 
     if (ds.options_->do_zip_file) {
         ds.path_ = ds.GetPath(".zip");
@@ -1953,19 +1940,6 @@
                     ds.path_ = new_path;
                 }
             }
-            // The zip file lives in an internal directory. Copy it over to output.
-            bool copy_succeeded = false;
-            if (ds.options_->bugreport_fd.get() != -1) {
-                copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->bugreport_fd.get());
-            } else {
-                ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
-                copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
-            }
-            if (copy_succeeded) {
-                if (remove(ds.path_.c_str())) {
-                    MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
-                }
-            }
         }
     }
     if (do_text_file) {
@@ -1991,8 +1965,8 @@
 /* Broadcasts that we are done with the bugreport */
 static void SendBugreportFinishedBroadcast() {
     // TODO(b/111441001): use callback instead of broadcast.
-    if (!ds.final_path_.empty()) {
-        MYLOGI("Final bugreport path: %s\n", ds.final_path_.c_str());
+    if (!ds.path_.empty()) {
+        MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
         // clang-format off
 
         std::vector<std::string> am_args = {
@@ -2000,7 +1974,7 @@
              "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
              "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
              "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
-             "--es", "android.intent.extra.BUGREPORT", ds.final_path_,
+             "--es", "android.intent.extra.BUGREPORT", ds.path_,
              "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
         };
         // clang-format on
@@ -2022,7 +1996,7 @@
         if (ds.options_->is_remote_mode) {
             am_args.push_back("--es");
             am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
-            am_args.push_back(SHA256_file_hash(ds.final_path_));
+            am_args.push_back(SHA256_file_hash(ds.path_));
             SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
         } else {
             SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
@@ -2160,7 +2134,6 @@
     MYLOGI("wifi_only: %d\n", options.wifi_only);
     MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
     MYLOGI("fd: %d\n", options.bugreport_fd.get());
-    MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
     MYLOGI("extra_options: %s\n", options.extra_options.c_str());
     MYLOGI("args: %s\n", options.args.c_str());
     MYLOGI("notification_title: %s\n", options.notification_title.c_str());
@@ -2186,12 +2159,14 @@
 Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
     RunStatus status = RunStatus::OK;
     int c;
-    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
         switch (c) {
             // clang-format off
             case 'd': do_add_date = true;            break;
             case 'z': do_zip_file = true;            break;
-            case 'o': use_outfile = optarg;          break;
+            // o=use_outfile not supported anymore.
+            // TODO(b/111441001): Remove when all callers have migrated.
+            case 'o': break;
             case 's': use_socket = true;             break;
             case 'S': use_control_socket = true;     break;
             case 'v': show_header_only = true;       break;
@@ -2201,6 +2176,9 @@
             case 'R': is_remote_mode = true;         break;
             case 'B': do_broadcast = true;           break;
             case 'V':                                break;  // compatibility no-op
+            case 'w':
+                // This was already processed
+                break;
             case 'h':
                 status = RunStatus::HELP;
                 break;
@@ -2232,9 +2210,7 @@
         return false;
     }
 
-    bool has_out_file_options = !use_outfile.empty() || bugreport_fd.get() != -1;
-    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
-        !has_out_file_options) {
+    if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
         return false;
     }
 
@@ -2256,6 +2232,32 @@
     options_ = std::move(options);
 }
 
+Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
+    Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
+    if (listener_ != nullptr) {
+        switch (status) {
+            case Dumpstate::RunStatus::OK:
+                listener_->onFinished();
+                break;
+            case Dumpstate::RunStatus::HELP:
+                break;
+            case Dumpstate::RunStatus::INVALID_INPUT:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+                break;
+            case Dumpstate::RunStatus::ERROR:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+                break;
+            case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
+                break;
+            case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
+                listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+                break;
+        }
+    }
+    return status;
+}
+
 /*
  * Dumps relevant information to a bugreport based on the given options.
  *
@@ -2274,10 +2276,11 @@
  * If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
  * gets added to the archive.
  *
- * Bugreports are first generated in a local directory and later copied to the caller's fd or
- * directory.
+ * Bugreports are first generated in a local directory and later copied to the caller's fd if
+ * supplied.
  */
-Dumpstate::RunStatus Dumpstate::Run() {
+Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
+                                            const std::string& calling_package) {
     LogDumpOptions(*options_);
     if (!options_->ValidateOptions()) {
         MYLOGE("Invalid options specified\n");
@@ -2315,8 +2318,14 @@
         return RunStatus::OK;
     }
 
+    if (options_->bugreport_fd.get() != -1) {
+        // If the output needs to be copied over to the caller's fd, get user consent.
+        android::String16 package(calling_package.c_str());
+        CheckUserConsent(calling_uid, package);
+    }
+
     // Redirect output if needed
-    bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
+    bool is_redirecting = options_->OutputToFile();
 
     // TODO: temporarily set progress until it's part of the Dumpstate constructor
     std::string stats_path =
@@ -2334,6 +2343,7 @@
 
     register_sig_handler();
 
+    // TODO(b/111441001): maybe skip if already started?
     if (options_->do_start_service) {
         MYLOGI("Starting 'dumpstate' service\n");
         android::status_t ret;
@@ -2466,11 +2476,40 @@
         TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
     }
 
-    /* rename or zip the (now complete) .tmp file to its final location */
-    if (!options_->use_outfile.empty()) {
+    // Rename, and/or zip the (now complete) .tmp file within the internal directory.
+    if (options_->OutputToFile()) {
         FinalizeFile();
     }
 
+    // Share the final file with the caller if the user has consented.
+    Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
+    if (options_->bugreport_fd.get() != -1) {
+        status = CopyBugreportIfUserConsented();
+        if (status != Dumpstate::RunStatus::OK &&
+            status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+            // Do an early return if there were errors. We make an exception for consent
+            // timing out because it's possible the user got distracted. In this case the
+            // bugreport is not shared but made available for manual retrieval.
+            MYLOGI("User denied consent. Returning\n");
+            return status;
+        }
+        if (options_->do_fb && options_->screenshot_fd.get() != -1) {
+            bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
+                                                            options_->screenshot_fd.get());
+            if (copy_succeeded) {
+                android::os::UnlinkAndLogOnError(screenshot_path_);
+            }
+        }
+        if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+            MYLOGI(
+                "Did not receive user consent yet."
+                " Will not copy the bugreport artifacts to caller.\n");
+            // TODO(b/111441001):
+            // 1. cancel outstanding requests
+            // 2. check for result more frequently
+        }
+    }
+
     /* vibrate a few but shortly times to let user know it's finished */
     if (options_->do_vibrate) {
         for (int i = 0; i < 3; i++) {
@@ -2482,6 +2521,7 @@
     /* tell activity manager we're done */
     if (options_->do_broadcast) {
         SendBugreportFinishedBroadcast();
+        // Note that listener_ is notified in Run();
     }
 
     MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
@@ -2501,17 +2541,95 @@
     tombstone_data_.clear();
     anr_data_.clear();
 
-    return RunStatus::OK;
+    return (consent_callback_ != nullptr &&
+            consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
+               ? USER_CONSENT_TIMED_OUT
+               : RunStatus::OK;
+}
+
+void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
+    consent_callback_ = new ConsentCallback();
+    const String16 incidentcompanion("incidentcompanion");
+    sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+    if (ics != nullptr) {
+        MYLOGD("Checking user consent via incidentcompanion service\n");
+        android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
+            calling_uid, calling_package, 0x1 /* FLAG_CONFIRMATION_DIALOG */,
+            consent_callback_.get());
+    } else {
+        MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
+    }
+}
+
+void Dumpstate::CleanupFiles() {
+    android::os::UnlinkAndLogOnError(tmp_path_);
+    android::os::UnlinkAndLogOnError(screenshot_path_);
+    android::os::UnlinkAndLogOnError(path_);
+}
+
+Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
+    MYLOGD("User denied consent; deleting files and returning\n");
+    CleanupFiles();
+    return USER_CONSENT_DENIED;
+}
+
+Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
+    // If the caller has asked to copy the bugreport over to their directory, we need explicit
+    // user consent.
+    UserConsentResult consent_result = consent_callback_->getResult();
+    if (consent_result == UserConsentResult::UNAVAILABLE) {
+        // User has not responded yet.
+        uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
+        if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
+            uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
+            MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
+            sleep(delay_seconds);
+        }
+        consent_result = consent_callback_->getResult();
+    }
+    if (consent_result == UserConsentResult::DENIED) {
+        // User has explicitly denied sharing with the app. To be safe delete the
+        // internal bugreport & tmp files.
+        return HandleUserConsentDenied();
+    }
+    if (consent_result == UserConsentResult::APPROVED) {
+        bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
+        if (copy_succeeded) {
+            android::os::UnlinkAndLogOnError(path_);
+        }
+        return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
+    } else if (consent_result == UserConsentResult::UNAVAILABLE) {
+        // consent_result is still UNAVAILABLE. The user has likely not responded yet.
+        // Since we do not have user consent to share the bugreport it does not get
+        // copied over to the calling app but remains in the internal directory from
+        // where the user can manually pull it.
+        return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
+    }
+    // Unknown result; must be a programming error.
+    MYLOGE("Unknown user consent result:%d\n", consent_result);
+    return Dumpstate::RunStatus::ERROR;
+}
+
+Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
+    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
+    Dumpstate::RunStatus status = options->Initialize(argc, argv);
+    if (status == Dumpstate::RunStatus::OK) {
+        SetOptions(std::move(options));
+        // When directly running dumpstate binary, the output is not expected to be written
+        // to any external file descriptor.
+        assert(options_->bugreport_fd.get() == -1);
+
+        // calling_uid and calling_package are for user consent to share the bugreport with
+        // an app; they are irrelvant here because bugreport is only written to a local
+        // directory, and not shared.
+        status = Run(-1 /* calling_uid */, "" /* calling_package */);
+    }
+    return status;
 }
 
 /* Main entry point for dumpstate binary. */
 int run_main(int argc, char* argv[]) {
-    std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
-    Dumpstate::RunStatus status = options->Initialize(argc, argv);
-    if (status == Dumpstate::RunStatus::OK) {
-        ds.SetOptions(std::move(options));
-        status = ds.Run();
-    }
+    Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
 
     switch (status) {
         case Dumpstate::RunStatus::OK:
@@ -2524,9 +2642,10 @@
             ShowUsage();
             exit(1);
         case Dumpstate::RunStatus::ERROR:
-            exit(2);
-        default:
-            fprintf(stderr, "Unknown status: %d\n", status);
+            FALLTHROUGH_INTENDED;
+        case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+            FALLTHROUGH_INTENDED;
+        case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
             exit(2);
     }
 }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 529111e..9803f00 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
 
 #include <android-base/macros.h>
 #include <android-base/unique_fd.h>
+#include <android/os/BnIncidentAuthListener.h>
 #include <android/os/IDumpstate.h>
 #include <android/os/IDumpstateListener.h>
 #include <utils/StrongPointer.h>
@@ -192,7 +193,7 @@
     friend class DumpstateTest;
 
   public:
-    enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+    enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
 
     // The mode under which the bugreport should be run. Each mode encapsulates a few options.
     enum BugreportMode {
@@ -319,7 +320,9 @@
     struct DumpOptions;
 
     /* Main entry point for running a complete bugreport. */
-    RunStatus Run();
+    RunStatus Run(int32_t calling_uid, const std::string& calling_package);
+
+    RunStatus ParseCommandlineAndRun(int argc, char* argv[]);
 
     /* Sets runtime options. */
     void SetOptions(std::unique_ptr<DumpOptions> options);
@@ -331,6 +334,7 @@
         bool do_add_date = false;
         bool do_zip_file = false;
         bool do_vibrate = true;
+        // Writes bugreport content to a socket; only flatfile format is supported.
         bool use_socket = false;
         bool use_control_socket = false;
         bool do_fb = false;
@@ -342,13 +346,10 @@
         bool wifi_only = false;
         // Whether progress updates should be published.
         bool do_progress_updates = false;
-        // File descriptor to output zip file. Takes precedence over use_outfile.
+        // File descriptor to output zip file.
         android::base::unique_fd bugreport_fd;
         // File descriptor to screenshot file.
-        // TODO(b/111441001): Use this fd.
         android::base::unique_fd screenshot_fd;
-        // Partial path to output file.
-        std::string use_outfile;
         // TODO: rename to MODE.
         // Extra options passed as system property.
         std::string extra_options;
@@ -367,6 +368,13 @@
 
         /* Returns true if the options set so far are consistent. */
         bool ValidateOptions() const;
+
+        /* Returns if options specified require writing bugreport to a file */
+        bool OutputToFile() const {
+            // If we are not writing to socket, we will write to a file. If bugreport_fd is
+            // specified, it is preferred. If not bugreport is written to /bugreports.
+            return !use_socket;
+        }
     };
 
     // TODO: initialize fields on constructor
@@ -424,13 +432,6 @@
     // Full path of the temporary file containing the screenshot (when requested).
     std::string screenshot_path_;
 
-    // TODO(b/111441001): remove when obsolete.
-    // Full path of the final zip file inside the caller-specified directory, if available.
-    std::string final_path_;
-
-    // The caller-specified directory, if available.
-    std::string bugreport_dir_;
-
     // Pointer to the zipped file.
     std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
 
@@ -448,10 +449,47 @@
     // List of open ANR dump files.
     std::vector<DumpData> anr_data_;
 
+    // A callback to IncidentCompanion service, which checks user consent for sharing the
+    // bugreport with the calling app. If the user has not responded yet to the dialog it will
+    // be neither confirmed nor denied.
+    class ConsentCallback : public android::os::BnIncidentAuthListener {
+      public:
+        ConsentCallback();
+        android::binder::Status onReportApproved() override;
+        android::binder::Status onReportDenied() override;
+
+        enum ConsentResult { APPROVED, DENIED, UNAVAILABLE };
+
+        ConsentResult getResult();
+
+        // Returns the time since creating this listener
+        uint64_t getElapsedTimeMs() const;
+
+      private:
+        ConsentResult result_;
+        uint64_t start_time_;
+        std::mutex lock_;
+    };
+
   private:
+    RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package);
+
+    void CheckUserConsent(int32_t calling_uid, const android::String16& calling_package);
+
+    // Removes the in progress files output files (tmp file, zip/txt file, screenshot),
+    // but leaves the log file alone.
+    void CleanupFiles();
+
+    RunStatus HandleUserConsentDenied();
+
+    // Copies bugreport artifacts over to the caller's directories provided there is user consent.
+    RunStatus CopyBugreportIfUserConsented();
+
     // Used by GetInstance() only.
     explicit Dumpstate(const std::string& version = VERSION_CURRENT);
 
+    android::sp<ConsentCallback> consent_callback_;
+
     DISALLOW_COPY_AND_ASSIGN(Dumpstate);
 };
 
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 2e72574..14937b8 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -17,3 +17,9 @@
     class main
     disabled
     oneshot
+
+# bugreportd starts dumpstate binder service and makes it wait for a listener to connect.
+service bugreportd /system/bin/dumpstate -w
+    class main
+    disabled
+    oneshot
diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp
index 78aad11..68d3733 100644
--- a/cmds/dumpstate/main.cpp
+++ b/cmds/dumpstate/main.cpp
@@ -14,8 +14,55 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dumpstate"
+
+#include <binder/IPCThreadState.h>
+
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
 #include "dumpstate.h"
 
+namespace {
+
+// Returns true if we should start the service and wait for a listener
+// to bind with bugreport options.
+bool ShouldStartServiceAndWait(int argc, char* argv[]) {
+    bool do_wait = false;
+    int c;
+    // Keep flags in sync with Dumpstate::DumpOptions::Initialize.
+    while ((c = getopt(argc, argv, "wdho:svqzpPBRSV:")) != -1 && !do_wait) {
+        switch (c) {
+            case 'w':
+                do_wait = true;
+                break;
+            default:
+                // Ignore all other options
+                break;
+        }
+    }
+
+    // Reset next index used by getopt so getopt can be called called again in Dumpstate::Run to
+    // parse bugreport options.
+    optind = 1;
+    return do_wait;
+}
+
+}  // namespace
+
 int main(int argc, char* argv[]) {
-    return run_main(argc, argv);
+    if (ShouldStartServiceAndWait(argc, argv)) {
+        int ret;
+        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+            MYLOGE("Unable to start 'dumpstate' service: %d", ret);
+            exit(1);
+        }
+        MYLOGI("'dumpstate' service started and will wait for a call to startBugreport()");
+
+        // Waits forever for an incoming connection.
+        // TODO(b/111441001): should this time out?
+        android::IPCThreadState::self()->joinThreadPool();
+        return 0;
+    } else {
+        return run_main(argc, argv);
+    }
 }
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index c57775f..555badd 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -21,6 +21,10 @@
 #include <libgen.h>
 
 #include <android-base/file.h>
+#include <android/os/BnDumpstate.h>
+#include <android/os/BnDumpstateListener.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <cutils/properties.h>
 #include <ziparchive/zip_archive.h>
 
@@ -34,6 +38,24 @@
 
 using ::testing::Test;
 using ::std::literals::chrono_literals::operator""s;
+using android::base::unique_fd;
+
+class DumpstateListener;
+
+namespace {
+
+sp<IDumpstate> GetDumpstateService() {
+    return android::interface_cast<IDumpstate>(
+        android::defaultServiceManager()->getService(String16("dumpstate")));
+}
+
+int OpenForWrite(const std::string& filename) {
+    return TEMP_FAILURE_RETRY(open(filename.c_str(),
+                                   O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+                                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+}
+
+}  // namespace
 
 struct SectionInfo {
     std::string name;
@@ -46,42 +68,71 @@
  * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
  * section details generated by dumpstate are added to a vector to be used by Tests later.
  */
-class DumpstateListener : public IDumpstateListener {
+class DumpstateListener : public BnDumpstateListener {
   public:
-    int outFd_, max_progress_;
-    std::shared_ptr<std::vector<SectionInfo>> sections_;
     DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
-        : outFd_(fd), max_progress_(5000), sections_(sections) {
+        : out_fd_(fd), sections_(sections) {
     }
+
+    DumpstateListener(int fd) : out_fd_(fd) {
+    }
+
     binder::Status onProgress(int32_t progress) override {
-        dprintf(outFd_, "\rIn progress %d", progress);
+        dprintf(out_fd_, "\rIn progress %d", progress);
         return binder::Status::ok();
     }
+
     binder::Status onError(int32_t error_code) override {
-        dprintf(outFd_, "\rError %d", error_code);
+        std::lock_guard<std::mutex> lock(lock_);
+        error_code_ = error_code;
+        dprintf(out_fd_, "\rError code %d", error_code);
         return binder::Status::ok();
     }
-    binder::Status onFinished(int64_t duration_ms, const ::std::string&,
-                              const ::std::string&) override {
-        dprintf(outFd_, "\rFinished in %lld", (long long) duration_ms);
+
+    binder::Status onFinished() override {
+        std::lock_guard<std::mutex> lock(lock_);
+        is_finished_ = true;
+        dprintf(out_fd_, "\rFinished");
         return binder::Status::ok();
     }
+
     binder::Status onProgressUpdated(int32_t progress) override {
-        dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+        dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
         return binder::Status::ok();
     }
+
     binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+        std::lock_guard<std::mutex> lock(lock_);
         max_progress_ = max_progress;
         return binder::Status::ok();
     }
+
     binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
                                      int32_t duration_ms) override {
-        sections_->push_back({name, status, size_bytes, duration_ms});
+        std::lock_guard<std::mutex> lock(lock_);
+        if (sections_.get() != nullptr) {
+            sections_->push_back({name, status, size_bytes, duration_ms});
+        }
         return binder::Status::ok();
     }
-    IBinder* onAsBinder() override {
-        return nullptr;
+
+    bool getIsFinished() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return is_finished_;
     }
+
+    int getErrorCode() {
+        std::lock_guard<std::mutex> lock(lock_);
+        return error_code_;
+    }
+
+  private:
+    int out_fd_;
+    int max_progress_ = 5000;
+    int error_code_ = -1;
+    bool is_finished_ = false;
+    std::shared_ptr<std::vector<SectionInfo>> sections_;
+    std::mutex lock_;
 };
 
 /**
@@ -110,7 +161,7 @@
         ds.listener_name_ = "Smokey";
         ds.report_section_ = true;
         auto start = std::chrono::steady_clock::now();
-        run_main(ARRAY_SIZE(argv), argv);
+        ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
         auto end = std::chrono::steady_clock::now();
         duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
     }
@@ -294,6 +345,148 @@
     SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
 }
 
+class DumpstateBinderTest : public Test {
+  protected:
+    void SetUp() override {
+        // In case there is a stray service, stop it first.
+        property_set("ctl.stop", "bugreportd");
+        // dry_run results in a faster bugreport.
+        property_set("dumpstate.dry_run", "true");
+        // We need to receive some async calls later. Ensure we have binder threads.
+        ProcessState::self()->startThreadPool();
+    }
+
+    void TearDown() override {
+        property_set("ctl.stop", "bugreportd");
+        property_set("dumpstate.dry_run", "");
+
+        unlink("/data/local/tmp/tmp.zip");
+        unlink("/data/local/tmp/tmp.png");
+    }
+
+    // Waits until listener gets the callbacks.
+    void WaitTillExecutionComplete(DumpstateListener* listener) {
+        // Wait till one of finished, error or timeout.
+        static const int kBugreportTimeoutSeconds = 120;
+        int i = 0;
+        while (!listener->getIsFinished() && listener->getErrorCode() == -1 &&
+               i < kBugreportTimeoutSeconds) {
+            sleep(1);
+            i++;
+        }
+    }
+};
+
+TEST_F(DumpstateBinderTest, Baseline) {
+    // In the beginning dumpstate binder service is not running.
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_EQ(ds_binder, nullptr);
+
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+
+    // Now we are able to retrieve dumpstate binder service.
+    ds_binder = GetDumpstateService();
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/bugreports/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/bugreports/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+    android::binder::Status status =
+        ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+                                  Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+    // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
+    // gets expected callbacks.
+    EXPECT_TRUE(status.isOk());
+    WaitTillExecutionComplete(listener.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+
+    // The service should have died on its own, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.get(), -1);
+
+    // 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,
+                                  2000,  // invalid bugreport mode
+                                  listener);
+    EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+
+    // The service should have died, freeing itself up for a new invocation.
+    sleep(2);
+    ds_binder = GetDumpstateService();
+    EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
+    // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+    // and makes it wait.
+    property_set("dumpstate.dry_run", "true");
+    property_set("ctl.start", "bugreportd");
+    sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+    EXPECT_NE(ds_binder, nullptr);
+
+    // Prepare arguments
+    unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+    unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+    EXPECT_NE(bugreport_fd.get(), -1);
+    EXPECT_NE(screenshot_fd.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,
+                                  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,
+                                       Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+    EXPECT_FALSE(status.isOk());
+    WaitTillExecutionComplete(listener2.get());
+    EXPECT_EQ(listener2->getErrorCode(),
+              IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+
+    // Meanwhile the first call works as expected. Service should not die in this case.
+    WaitTillExecutionComplete(listener1.get());
+
+    // Bugreport generation requires user consent, which we cannot get in a test set up,
+    // so instead of getting is_finished_, we are more likely to get a consent error.
+    EXPECT_TRUE(
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+        listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+}
+
 }  // namespace dumpstate
 }  // namespace os
 }  // namespace android
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 98ee1b0..eb73d41 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -61,8 +61,7 @@
   public:
     MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
-    MOCK_METHOD3(onFinished, binder::Status(int64_t duration_ms, const ::std::string& title,
-                                            const ::std::string& description));
+    MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
     MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
     MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
@@ -173,7 +172,6 @@
 
     EXPECT_FALSE(options_.do_add_date);
     EXPECT_FALSE(options_.do_zip_file);
-    EXPECT_EQ("", options_.use_outfile);
     EXPECT_FALSE(options_.use_socket);
     EXPECT_FALSE(options_.use_control_socket);
     EXPECT_FALSE(options_.show_header_only);
@@ -191,7 +189,6 @@
         const_cast<char*>("-S"),
         const_cast<char*>("-d"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -201,7 +198,6 @@
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.use_control_socket);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -228,7 +224,6 @@
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
-    EXPECT_EQ("", options_.use_outfile);
     EXPECT_FALSE(options_.do_add_date);
     EXPECT_FALSE(options_.do_zip_file);
     EXPECT_FALSE(options_.use_control_socket);
@@ -247,7 +242,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
     property_set("dumpstate.options", "bugreportfull");
@@ -259,7 +253,6 @@
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_broadcast);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -279,7 +272,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -294,7 +286,6 @@
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
     EXPECT_FALSE(options_.do_fb);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -312,7 +303,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -327,7 +317,6 @@
     EXPECT_TRUE(options_.is_remote_mode);
     EXPECT_FALSE(options_.do_vibrate);
     EXPECT_FALSE(options_.do_fb);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_FALSE(options_.use_control_socket);
@@ -344,7 +333,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -359,7 +347,6 @@
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_progress_updates);
     EXPECT_TRUE(options_.do_start_service);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -377,7 +364,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -391,7 +377,6 @@
     EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.telephony_only);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -410,7 +395,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -424,7 +408,6 @@
     EXPECT_TRUE(options_.do_broadcast);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.wifi_only);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -444,7 +427,6 @@
         const_cast<char*>("-p"),
         const_cast<char*>("-B"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
     };
     // clang-format on
 
@@ -457,7 +439,6 @@
     EXPECT_TRUE(options_.do_fb);
     EXPECT_TRUE(options_.do_zip_file);
     EXPECT_TRUE(options_.do_broadcast);
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
 
     // Other options retain default values
     EXPECT_TRUE(options_.do_vibrate);
@@ -475,7 +456,6 @@
         const_cast<char*>("dumpstate"),
         const_cast<char*>("-d"),
         const_cast<char*>("-z"),
-        const_cast<char*>("-o abc"),
         const_cast<char*>("-s"),
         const_cast<char*>("-S"),
 
@@ -488,7 +468,6 @@
     EXPECT_TRUE(options_.do_add_date);
     EXPECT_TRUE(options_.do_zip_file);
     // TODO: Maybe we should trim the filename
-    EXPECT_EQ(" abc", std::string(options_.use_outfile));
     EXPECT_TRUE(options_.use_socket);
     EXPECT_TRUE(options_.use_control_socket);
 
@@ -527,7 +506,6 @@
     // Other options retain default values
     EXPECT_FALSE(options_.do_add_date);
     EXPECT_FALSE(options_.do_zip_file);
-    EXPECT_EQ("", options_.use_outfile);
     EXPECT_FALSE(options_.use_socket);
     EXPECT_FALSE(options_.use_control_socket);
 }
@@ -562,15 +540,21 @@
 
 TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
     options_.do_zip_file = true;
+    // Writing to socket = !writing to file.
+    options_.use_socket = true;
     EXPECT_FALSE(options_.ValidateOptions());
-    options_.use_outfile = "a/b/c";
+
+    options_.use_socket = false;
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
 TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
     options_.do_broadcast = true;
+    // Writing to socket = !writing to file.
+    options_.use_socket = true;
     EXPECT_FALSE(options_.ValidateOptions());
-    options_.use_outfile = "a/b/c";
+
+    options_.use_socket = false;
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
@@ -579,13 +563,11 @@
     EXPECT_FALSE(options_.ValidateOptions());
 
     options_.do_zip_file = true;
-    options_.use_outfile = "a/b/c";  // do_zip_file needs outfile
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
 TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
     options_.do_progress_updates = true;
-    options_.use_outfile = "a/b/c";  // do_progress_updates needs outfile
     EXPECT_FALSE(options_.ValidateOptions());
 
     options_.do_broadcast = true;
@@ -599,7 +581,6 @@
     options_.do_broadcast = true;
     options_.do_zip_file = true;
     options_.do_add_date = true;
-    options_.use_outfile = "a/b/c";  // do_broadcast needs outfile
     EXPECT_TRUE(options_.ValidateOptions());
 }
 
@@ -656,8 +637,9 @@
         }
 
         if (update_progress) {
-            message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
-                                                   listener_name.c_str(), progress, max);
+            message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+                                                   listener_name.c_str(), progress, max,
+                                                   (100 * progress / max));
         }
 
         return message;
@@ -816,12 +798,14 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(20));
+    EXPECT_CALL(*listener, onProgress(66));  // 20/30 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
     EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
 
     EXPECT_CALL(*listener, onProgressUpdated(30));
+    EXPECT_CALL(*listener, onProgress(100));  // 35/35 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -830,6 +814,7 @@
     // Run a command that will increase maximum timeout.
     EXPECT_CALL(*listener, onProgressUpdated(31));
     EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+    EXPECT_CALL(*listener, onProgress(83));  // 31/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30);  // 20% increase
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -838,6 +823,7 @@
     // Make sure command ran while in dry_run is counted.
     SetDryRun(true);
     EXPECT_CALL(*listener, onProgressUpdated(35));
+    EXPECT_CALL(*listener, onProgress(94));  // 35/37 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
     EXPECT_THAT(out, IsEmpty());
@@ -854,6 +840,7 @@
 
     // First update should always be sent.
     EXPECT_CALL(*listener, onProgressUpdated(1));
+    EXPECT_CALL(*listener, onProgress(12));  // 1/12 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -866,6 +853,7 @@
 
     // Third update should be sent because it reaches threshold (6 - 1 = 5).
     EXPECT_CALL(*listener, onProgressUpdated(6));
+    EXPECT_CALL(*listener, onProgress(75));  // 6/8 %
     EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
     progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
     EXPECT_THAT(out, StrEq("stdout\n"));
@@ -1105,6 +1093,7 @@
     SetProgress(0, 30);
 
     EXPECT_CALL(*listener, onProgressUpdated(5));
+    EXPECT_CALL(*listener, onProgress(16));  // 5/30 %
     EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
 
     std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 990fd43..528e43d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -949,16 +949,22 @@
         fsync(control_socket_fd_);
     }
 
+    int percent = 100 * progress / max;
     if (listener_ != nullptr) {
-        if (progress % 100 == 0) {
-            // We don't want to spam logcat, so only log multiples of 100.
-            MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+        if (percent % 5 == 0) {
+            // We don't want to spam logcat, so only log multiples of 5.
+            MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+                   percent);
         } else {
             // stderr is ignored on normal invocations, but useful when calling
             // /system/bin/dumpstate directly for debuggging.
-            fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+            fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+                    progress, max, percent);
         }
+        // TODO(b/111441001): Remove in favor of onProgress
         listener_->onProgressUpdated(progress);
+
+        listener_->onProgress(percent);
     }
 }
 
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f68b862..f99588f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -20,8 +20,6 @@
     static_libs: [
         "libserviceutils",
     ],
-
-    clang: true,
 }
 
 //
@@ -36,7 +34,6 @@
     export_include_dirs: ["."],
 }
 
-
 //
 // Executable
 //
@@ -51,4 +48,15 @@
     ],
 }
 
-subdirs = ["tests"]
+cc_binary {
+    name: "dumpsys_vendor",
+    stem: "dumpsys",
+
+    vendor: true,
+
+    defaults: ["dumpsys_defaults"],
+
+    srcs: [
+        "main.cpp",
+    ],
+}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 2e9701f..9d3a234 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -18,6 +18,7 @@
         "dexopt.cpp",
         "globals.cpp",
         "utils.cpp",
+        "view_compiler.cpp",
         ":installd_aidl",
     ],
     header_libs: [
@@ -30,6 +31,7 @@
         "libcutils",
         "liblog",
         "liblogwrap",
+        "libprocessgroup",
         "libselinux",
         "libutils",
     ],
@@ -136,10 +138,23 @@
     ],
     clang: true,
 
-    srcs: ["otapreopt_chroot.cpp"],
+    srcs: [
+        "otapreopt_chroot.cpp",
+        "otapreopt_utils.cpp",
+    ],
     shared_libs: [
         "libbase",
         "liblog",
+        "libprotobuf-cpp-full",
+        "libselinux",
+        "libziparchive",
+    ],
+    static_libs: [
+        "libapex",
+        "libapexd",
+        "lib_apex_manifest_proto",
+        "libavb",
+        "libdm",
     ],
 }
 
@@ -168,6 +183,7 @@
         "libbase",
         "libcutils",
         "liblog",
+        "libprocessgroup",
         "libutils",
     ],
 }
@@ -187,7 +203,9 @@
         "dexopt.cpp",
         "globals.cpp",
         "otapreopt.cpp",
+        "otapreopt_utils.cpp",
         "utils.cpp",
+        "view_compiler.cpp",
     ],
 
     header_libs: ["dex2oat_headers"],
@@ -204,7 +222,28 @@
         "libcutils",
         "liblog",
         "liblogwrap",
+        "libprocessgroup",
         "libselinux",
         "libutils",
     ],
 }
+
+// OTA slot script
+sh_binary {
+    name: "otapreopt_slot",
+    src: "otapreopt_slot.sh",
+    init_rc: ["otapreopt.rc"],
+}
+
+// OTA postinstall script
+sh_binary {
+    name: "otapreopt_script",
+    src: "otapreopt_script.sh",
+    // Let this depend on otapreopt, the chroot tool and the slot script,
+    // so we just have to mention one in a configuration.
+    required: [
+        "otapreopt",
+        "otapreopt_chroot",
+        "otapreopt_slot",
+    ],
+}
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
deleted file mode 100644
index 30de0b3..0000000
--- a/cmds/installd/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# OTA slot script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_slot
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_slot.sh
-LOCAL_INIT_RC := otapreopt.rc
-
-include $(BUILD_PREBUILT)
-
-# OTA postinstall script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_script
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_script.sh
-
-# Let this depend on otapreopt, the chroot tool and the slot script, so we just have to mention one
-# in a configuration.
-LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
-
-include $(BUILD_PREBUILT)
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2439dff..ccffd29 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -41,6 +41,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -60,6 +61,7 @@
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
 #include "utils.h"
+#include "view_compiler.h"
 
 #include "CacheTracker.h"
 #include "MatchExtensionGen.h"
@@ -75,6 +77,9 @@
 namespace android {
 namespace installd {
 
+// An uuid used in unit tests.
+static constexpr const char* kTestUuid = "TEST";
+
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
 
@@ -162,6 +167,15 @@
     }
 }
 
+binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+    if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
+        return ok();
+    } else {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                StringPrintf("UUID must be null or \"%s\", got: %s", kTestUuid, uuid->c_str()));
+    }
+}
+
 binder::Status checkArgumentPackageName(const std::string& packageName) {
     if (is_valid_package_name(packageName.c_str())) {
         return ok();
@@ -214,6 +228,13 @@
     }                                                       \
 }
 
+#define CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(uuid) {         \
+    auto status = checkArgumentUuidTestOrNull(uuid);        \
+    if (!status.isOk()) {                                   \
+        return status;                                      \
+    }                                                       \
+}                                                           \
+
 #define CHECK_ARGUMENT_PACKAGE_NAME(packageName) {          \
     binder::Status status =                                 \
             checkArgumentPackageName((packageName));        \
@@ -745,6 +766,233 @@
     return ok();
 }
 
+static int32_t copy_directory_recursive(const char* from, const char* to) {
+    char *argv[] = {
+        (char*) kCpPath,
+        (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+        (char*) "-p", /* preserve timestamps, ownership, and permissions */
+        (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+        (char*) "-P", /* Do not follow symlinks [default] */
+        (char*) "-d", /* don't dereference symlinks */
+        (char*) from,
+        (char*) to
+    };
+
+    LOG(DEBUG) << "Copying " << from << " to " << to;
+    return android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+}
+
+binder::Status InstalldNativeService::snapshotAppData(
+        const std::unique_ptr<std::string>& volumeUuid,
+        const std::string& packageName, int32_t user, int32_t storageFlags,
+        int64_t* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    binder::Status res = ok();
+    // Default result to 0, it will be populated with inode of ce data snapshot
+    // if FLAG_STORAGE_CE has been passed.
+    if (_aidl_return != nullptr) *_aidl_return = 0;
+
+    bool clear_ce_on_exit = false;
+    bool clear_de_on_exit = false;
+
+    auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
+        if (clear_de_on_exit) {
+            auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
+            }
+        }
+
+        if (clear_ce_on_exit) {
+            auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+                LOG(WARNING) << "Failed to delete app data snapshot: " << to;
+            }
+        }
+    };
+
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    // The app may not have any data at all, in which case it's OK to skip here.
+    auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
+    if (access(from_ce.c_str(), F_OK) != 0) {
+        LOG(INFO) << "Missing source " << from_ce;
+        return ok();
+    }
+
+    // ce_data_inode is not needed when FLAG_CLEAR_CACHE_ONLY is set.
+    binder::Status clear_cache_result = clearAppData(volumeUuid, packageName, user,
+            storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
+    if (!clear_cache_result.isOk()) {
+        // It should be fine to continue snapshot if we for some reason failed
+        // to clear cache.
+        LOG(WARNING) << "Failed to clear cache of app " << packageName;
+    }
+
+    // ce_data_inode is not needed when FLAG_CLEAR_CODE_CACHE_ONLY is set.
+    binder::Status clear_code_cache_result = clearAppData(volumeUuid, packageName, user,
+            storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY, 0);
+    if (!clear_code_cache_result.isOk()) {
+        // It should be fine to continue snapshot if we for some reason failed
+        // to clear code_cache.
+        LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
+    }
+
+    if (storageFlags & FLAG_STORAGE_DE) {
+        auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
+        auto to = create_data_misc_de_rollback_path(volume_uuid, user);
+
+        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
+        if (rd != 0) {
+            res = error(rd, "Failed clearing existing snapshot " + to);
+            return res;
+        }
+
+        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            clear_de_on_exit = true;
+            return res;
+        }
+    }
+
+    if (storageFlags & FLAG_STORAGE_CE) {
+        auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
+        auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
+
+        int rd = delete_dir_contents(to, true /* ignore_if_missing */);
+        if (rd != 0) {
+            res = error(rd, "Failed clearing existing snapshot " + to);
+            return res;
+        }
+
+        int rc = copy_directory_recursive(from.c_str(), to.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from + " to " + to);
+            clear_ce_on_exit = true;
+            return res;
+        }
+        if (_aidl_return != nullptr) {
+            auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+                    package_name);
+            rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
+            if (rc != 0) {
+                res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
+                clear_ce_on_exit = true;
+                return res;
+            }
+        }
+    }
+
+    return res;
+}
+
+binder::Status InstalldNativeService::restoreAppDataSnapshot(
+        const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
+        const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
+        const int32_t user, int32_t storageFlags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
+            user, package_name);
+    auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
+            user, package_name);
+
+    const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
+        (access(from_ce.c_str(), F_OK) == 0);
+    const bool needs_de_rollback = (storageFlags & FLAG_STORAGE_DE) &&
+        (access(from_de.c_str(), F_OK) == 0);
+
+    if (!needs_ce_rollback && !needs_de_rollback) {
+        return ok();
+    }
+
+    // We know we're going to rollback one of the CE or DE data, so we clear
+    // application data first. Note that it's possible that we're asked to
+    // restore both CE & DE data but that one of the restores fail. Leaving the
+    // app with no data in those cases is arguably better than leaving the app
+    // with mismatched / stale data.
+    LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
+    binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
+    if (!res.isOk()) {
+        return res;
+    }
+
+    if (needs_ce_rollback) {
+        auto to_ce = create_data_user_ce_path(volume_uuid, user);
+        int rc = copy_directory_recursive(from_ce.c_str(), to_ce.c_str());
+        if (rc != 0) {
+            res = error(rc, "Failed copying " + from_ce + " to " + to_ce);
+            return res;
+        }
+    }
+
+    if (needs_de_rollback) {
+        auto to_de = create_data_user_de_path(volume_uuid, user);
+        int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str());
+        if (rc != 0) {
+            if (needs_ce_rollback) {
+                auto ce_data = create_data_user_ce_package_path(volume_uuid, user, package_name);
+                LOG(WARNING) << "de_data rollback failed. Erasing rolled back ce_data " << ce_data;
+                if (delete_dir_contents(ce_data.c_str(), 1, nullptr) != 0) {
+                    LOG(WARNING) << "Failed to delete rolled back ce_data " << ce_data;
+                }
+            }
+            res = error(rc, "Failed copying " + from_de + " to " + to_de);
+            return res;
+        }
+    }
+
+    // Finally, restore the SELinux label on the app data.
+    return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
+}
+
+binder::Status InstalldNativeService::destroyAppDataSnapshot(
+        const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
+        const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+    const char* package_name = packageName.c_str();
+
+    if (storageFlags & FLAG_STORAGE_DE) {
+        auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
+                user, package_name);
+
+        int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
+        if (res != 0) {
+            return error(res, "Failed clearing snapshot " + de_snapshot_path);
+        }
+    }
+
+    if (storageFlags & FLAG_STORAGE_CE) {
+        auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
+                user, package_name, ceSnapshotInode);
+        int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
+        if (res != 0) {
+            return error(res, "Failed clearing snapshot " + ce_snapshot_path);
+        }
+    }
+    return ok();
+}
+
+
 binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
         const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
         const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -769,19 +1017,7 @@
         auto to = create_data_app_package_path(to_uuid, data_app_name);
         auto to_parent = create_data_app_path(to_uuid);
 
-        char *argv[] = {
-            (char*) kCpPath,
-            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
-            (char*) "-p", /* preserve timestamps, ownership, and permissions */
-            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
-            (char*) "-P", /* Do not follow symlinks [default] */
-            (char*) "-d", /* don't dereference symlinks */
-            (char*) from.c_str(),
-            (char*) to_parent.c_str()
-        };
-
-        LOG(DEBUG) << "Copying " << from << " to " << to;
-        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+        int rc = copy_directory_recursive(from.c_str(), to_parent.c_str());
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             goto fail;
@@ -809,25 +1045,11 @@
             goto fail;
         }
 
-        char *argv[] = {
-            (char*) kCpPath,
-            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
-            (char*) "-p", /* preserve timestamps, ownership, and permissions */
-            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
-            (char*) "-P", /* Do not follow symlinks [default] */
-            (char*) "-d", /* don't dereference symlinks */
-            nullptr,
-            nullptr
-        };
-
         {
             auto from = create_data_user_de_package_path(from_uuid, user, package_name);
             auto to = create_data_user_de_path(to_uuid, user);
-            argv[6] = (char*) from.c_str();
-            argv[7] = (char*) to.c_str();
 
-            LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+            int rc = copy_directory_recursive(from.c_str(), to.c_str());
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -836,11 +1058,8 @@
         {
             auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
             auto to = create_data_user_ce_path(to_uuid, user);
-            argv[6] = (char*) from.c_str();
-            argv[7] = (char*) to.c_str();
 
-            LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+            int rc = copy_directory_recursive(from.c_str(), to.c_str());
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -1831,6 +2050,17 @@
     return res ? error(res, error_msg) : ok();
 }
 
+binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
+                                                     const std::string& packageName,
+                                                     const std ::string& outDexFile, int uid,
+                                                     bool* _aidl_return) {
+    const char* apk_path = apkPath.c_str();
+    const char* package_name = packageName.c_str();
+    const char* out_dex_file = outDexFile.c_str();
+    *_aidl_return = android::installd::view_compiler(apk_path, package_name, out_dex_file, uid);
+    return *_aidl_return ? ok() : error("viewcompiler failed");
+}
+
 binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
     ENFORCE_UID(AID_SYSTEM);
     std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -1876,8 +2106,14 @@
         return error("Failed to stat " + _pkgdir);
     }
 
+    char *con = nullptr;
+    if (lgetfilecon(pkgdir, &con) < 0) {
+        return error("Failed to lgetfilecon " + _pkgdir);
+    }
+
     if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
-        return error("Failed to chown " + _pkgdir);
+        res = error("Failed to chown " + _pkgdir);
+        goto out;
     }
 
     if (chmod(pkgdir, 0700) < 0) {
@@ -1909,7 +2145,13 @@
         goto out;
     }
 
+    if (lsetfilecon(libsymlink, con) < 0) {
+        res = error("Failed to lsetfilecon " + _libsymlink);
+        goto out;
+    }
+
 out:
+    free(con);
     if (chmod(pkgdir, s.st_mode) < 0) {
         auto msg = "Failed to cleanup chmod " + _pkgdir;
         if (res.isOk()) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 367f2c1..578132d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -60,6 +60,16 @@
 
     binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
 
+    binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
+            const std::string& packageName, const int32_t user, int32_t storageFlags,
+            int64_t* _aidl_return);
+    binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
+            const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
+            const std::string& seInfo, const int32_t user, int32_t storageFlags);
+    binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
+            const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
+            int32_t storageFlags);
+
     binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
             const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
             int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -89,6 +99,9 @@
             const std::unique_ptr<std::string>& dexMetadataPath,
             const std::unique_ptr<std::string>& compilationReason);
 
+    binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
+                                  const std::string& outDexFile, int uid, bool* _aidl_return);
+
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
     binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3de5c79..287f2d9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -14,6 +14,15 @@
     },
     {
       "name": "installd_utils_test"
+    },
+    {
+      "name": "CtsUsesLibraryHostTestCases"
+    },
+    {
+      "name": "CtsClassloaderSplitsHostTestCases"
+    },
+    {
+      "name": "CtsCompilationTestCases"
     }
   ]
 }
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 91e20b7..377074a 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -55,6 +55,8 @@
             @nullable @utf8InCpp String profileName,
             @nullable @utf8InCpp String dexMetadataPath,
             @nullable @utf8InCpp String compilationReason);
+    boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
+            @utf8InCpp String outDexFile, int uid);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
@@ -102,4 +104,14 @@
     boolean prepareAppProfile(@utf8InCpp String packageName,
         int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
         @nullable @utf8InCpp String dexMetadata);
+
+    long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+            int userId, int storageFlags);
+    void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+            int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+    void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+            int userId, long ceSnapshotInode, int storageFlags);
+
+    const int FLAG_STORAGE_DE = 0x1;
+    const int FLAG_STORAGE_CE = 0x2;
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 32c1313..acc0647 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -43,6 +43,7 @@
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
+#include <processgroup/sched_policy.h>
 #include <selinux/android.h>
 #include <system/thread_defs.h>
 
@@ -313,9 +314,15 @@
         bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
                                 vold_decrypt == "1";
 
-        const std::string resolve_startup_string_arg =
+        std::string resolve_startup_string_arg =
+                MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
+                                 "--resolve-startup-const-strings=%s");
+        if (resolve_startup_string_arg.empty()) {
+          // If empty, fall back to system property.
+          resolve_startup_string_arg =
                 MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
                                  "--resolve-startup-const-strings=%s");
+        }
 
         const std::string image_block_size_arg =
                 MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
@@ -332,8 +339,7 @@
             MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
 
         // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-        const char* dex2oat_bin = "/system/bin/dex2oat";
-        constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+        const char* dex2oat_bin = kDex2oatPath;
         // Do not use dex2oatd for release candidates (give dex2oat more soak time).
         bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
         if (is_debug_runtime() ||
@@ -346,6 +352,8 @@
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
 
+        std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+
         // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
         // use arraysize instead.
         std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
@@ -360,7 +368,7 @@
         std::string dex2oat_image_fd;
         std::string target_sdk_version_arg;
         if (target_sdk_version != 0) {
-            StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+            target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
         }
         std::string class_loader_context_arg;
         if (class_loader_context != nullptr) {
@@ -431,6 +439,7 @@
         AddArg(instruction_set_variant_arg);
         AddArg(instruction_set_features_arg);
 
+        AddRuntimeArg(boot_image);
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
@@ -462,7 +471,7 @@
         if (disable_cdex) {
             AddArg(kDisableCompactDexFlag);
         }
-        AddArg(target_sdk_version_arg);
+        AddRuntimeArg(target_sdk_version_arg);
         if (enable_hidden_api_checks) {
             AddRuntimeArg("-Xhidden-api-checks");
         }
@@ -627,27 +636,6 @@
     }
 }
 
-static void drop_capabilities(uid_t uid) {
-    if (setgid(uid) != 0) {
-        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
-        exit(DexoptReturnCodes::kSetGid);
-    }
-    if (setuid(uid) != 0) {
-        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
-        exit(DexoptReturnCodes::kSetUid);
-    }
-    // drop capabilities
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    if (capset(&capheader, &capdata[0]) < 0) {
-        PLOG(ERROR) << "capset failed";
-        exit(DexoptReturnCodes::kCapSet);
-    }
-}
-
 static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
 static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
 static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
@@ -662,8 +650,7 @@
                   const std::vector<std::string>& dex_locations,
                   bool copy_and_update,
                   bool store_aggregation_counters) {
-        const char* profman_bin =
-                is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+        const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
 
         if (copy_and_update) {
             CHECK_EQ(1u, profile_fds.size());
@@ -1479,9 +1466,7 @@
                     const char* class_loader_context) {
         CHECK_GE(zip_fd, 0);
         const char* dexoptanalyzer_bin =
-                is_debug_runtime()
-                        ? "/system/bin/dexoptanalyzerd"
-                        : "/system/bin/dexoptanalyzer";
+            is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
 
         std::string dex_file_arg = "--dex-file=" + dex_file;
         std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
@@ -1976,6 +1961,11 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
+        // Clear BOOTCLASSPATH.
+        // Let dex2oat use the BCP from boot image, excluding updatable BCP
+        // modules for AOT to avoid app recompilation after their upgrades.
+        unsetenv("BOOTCLASSPATH");
+
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 0db11e1..5902659 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -32,6 +32,16 @@
 static constexpr int DEX2OAT_FOR_BOOT_IMAGE      = 2;
 static constexpr int DEX2OAT_FOR_FILTER          = 3;
 
+#define ANDROID_RUNTIME_APEX_BIN "/apex/com.android.runtime/bin"
+// Location of binaries in the Android Runtime APEX.
+static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
+static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
+static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
+#undef ANDROID_RUNTIME_APEX_BIN
+
 // Clear the reference profile identified by the given profile name.
 bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name);
 // Clear the current profile identified by the given profile name (for single user).
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index b2e7047..de7b249 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,7 +26,6 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -58,7 +57,6 @@
 #define REPLY_MAX     256   /* largest reply allowed */
 
 using android::base::EndsWith;
-using android::base::Join;
 using android::base::Split;
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -440,7 +438,7 @@
                           const char* isa) const {
         // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
         std::vector<std::string> cmd;
-        cmd.push_back("/system/bin/dex2oat");
+        cmd.push_back(kDex2oatPath);
         cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
         for (const std::string& boot_part : Split(boot_cp, ":")) {
             cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
@@ -619,61 +617,6 @@
     // Helpers, mostly taken from ART //
     ////////////////////////////////////
 
-    // Wrapper on fork/execv to run a command in a subprocess.
-    static bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
-        const std::string command_line = Join(arg_vector, ' ');
-
-        CHECK_GE(arg_vector.size(), 1U) << command_line;
-
-        // Convert the args to char pointers.
-        const char* program = arg_vector[0].c_str();
-        std::vector<char*> args;
-        for (size_t i = 0; i < arg_vector.size(); ++i) {
-            const std::string& arg = arg_vector[i];
-            char* arg_str = const_cast<char*>(arg.c_str());
-            CHECK(arg_str != nullptr) << i;
-            args.push_back(arg_str);
-        }
-        args.push_back(nullptr);
-
-        // Fork and exec.
-        pid_t pid = fork();
-        if (pid == 0) {
-            // No allocation allowed between fork and exec.
-
-            // Change process groups, so we don't get reaped by ProcessManager.
-            setpgid(0, 0);
-
-            execv(program, &args[0]);
-
-            PLOG(ERROR) << "Failed to execv(" << command_line << ")";
-            // _exit to avoid atexit handlers in child.
-            _exit(1);
-        } else {
-            if (pid == -1) {
-                *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
-                        command_line.c_str(), strerror(errno));
-                return false;
-            }
-
-            // wait for subprocess to finish
-            int status;
-            pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
-            if (got_pid != pid) {
-                *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
-                        "wanted %d, got %d: %s",
-                        command_line.c_str(), pid, got_pid, strerror(errno));
-                return false;
-            }
-            if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-                *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
-                        command_line.c_str());
-                return false;
-            }
-        }
-        return true;
-    }
-
     // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
     static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
         constexpr size_t kPageSize = PAGE_SIZE;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index e90cf3b..670abea 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <linux/unistd.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 
 #include <sstream>
@@ -24,6 +25,9 @@
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <selinux/android.h>
+
+#include <apexd.h>
 
 #include "installd_constants.h"
 #include "otapreopt_utils.h"
@@ -37,6 +41,23 @@
 namespace android {
 namespace installd {
 
+// Configuration for bind-mounted Bionic artifacts.
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+
 static void CloseDescriptor(int fd) {
     if (fd >= 0) {
         int result = close(fd);
@@ -54,6 +75,62 @@
     }
 }
 
+static std::vector<apex::ApexFile> ActivateApexPackages() {
+    // The logic here is (partially) copied and adapted from
+    // system/apex/apexd/apexd_main.cpp.
+    //
+    // Only scan the APEX directory under /system (within the chroot dir).
+    apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+    return apex::getActivePackages();
+}
+
+static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
+    for (const apex::ApexFile& apex_file : active_packages) {
+        const std::string& package_path = apex_file.GetPath();
+        apex::Status status = apex::deactivatePackage(package_path);
+        if (!status.Ok()) {
+            LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+        }
+    }
+}
+
+// Copied from system/core/init/mount_namespace.cpp.
+static bool BindMount(const std::string& source, const std::string& mount_point,
+                      bool recursive = false) {
+    unsigned long mountflags = MS_BIND;
+    if (recursive) {
+        mountflags |= MS_REC;
+    }
+    if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+        PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+        return false;
+    }
+    return true;
+}
+
+// Copied from system/core/init/mount_namespace.cpp and and adjusted (bind
+// mounts are not made private, as the /postinstall is already private (see
+// `android::installd::otapreopt_chroot`).
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+                            const std::string& linker_mount_point,
+                            const std::string& lib_mount_dir) {
+    if (access(linker_source.c_str(), F_OK) != 0) {
+        PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there.";
+        return true;
+    }
+    if (!BindMount(linker_source, linker_mount_point)) {
+        return false;
+    }
+    for (const auto& libname : kBionicLibFileNames) {
+        std::string mount_point = lib_mount_dir + libname;
+        std::string source = lib_dir_source + libname;
+        if (!BindMount(source, mount_point)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 // Entry for otapreopt_chroot. Expected parameters are:
 //   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
 // The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -138,6 +215,44 @@
       UNUSED(product_result);
     }
 
+    // Setup APEX mount point and its security context.
+    static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
+    // The following logic is similar to the one in system/core/rootdir/init.rc:
+    //
+    //   mount tmpfs tmpfs /apex nodev noexec nosuid
+    //   chmod 0755 /apex
+    //   chown root root /apex
+    //   restorecon /apex
+    //
+    // except we perform the `restorecon` step just after mounting the tmpfs
+    // filesystem in /postinstall/apex, so that this directory is correctly
+    // labeled (with type `postinstall_apex_mnt_dir`) and may be manipulated in
+    // following operations (`chmod`, `chown`, etc.) following policies
+    // restricted to `postinstall_apex_mnt_dir`:
+    //
+    //   mount tmpfs tmpfs /postinstall/apex nodev noexec nosuid
+    //   restorecon /postinstall/apex
+    //   chmod 0755 /postinstall/apex
+    //   chown root root /postinstall/apex
+    //
+    if (mount("tmpfs", kPostinstallApexDir, "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
+        != 0) {
+        PLOG(ERROR) << "Failed to mount tmpfs in " << kPostinstallApexDir;
+        exit(209);
+    }
+    if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
+        PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
+        exit(214);
+    }
+    if (chmod(kPostinstallApexDir, 0755) != 0) {
+        PLOG(ERROR) << "Failed to chmod " << kPostinstallApexDir << " to 0755";
+        exit(210);
+    }
+    if (chown(kPostinstallApexDir, 0, 0) != 0) {
+        PLOG(ERROR) << "Failed to chown " << kPostinstallApexDir << " to root:root";
+        exit(211);
+    }
+
     // Chdir into /postinstall.
     if (chdir("/postinstall") != 0) {
         PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -155,22 +270,55 @@
         exit(205);
     }
 
-    // Now go on and run otapreopt.
+    // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
+    // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
+    std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
 
-    // Incoming:  cmd + status-fd + target-slot + cmd... + null      | Incoming | = argc + 1
-    // Outgoing:  cmd             + target-slot + cmd... + null      | Outgoing | = argc
-    const char** argv = new const char*[argc];
-
-    argv[0] = "/system/bin/otapreopt";
-
-    // The first parameter is the status file descriptor, skip.
-    for (size_t i = 2; i <= static_cast<size_t>(argc); ++i) {
-        argv[i - 1] = arg[i];
+    // Bind-mount Bionic artifacts from the Runtime APEX.
+    // This logic is copied and adapted from system/core/init/mount_namespace.cpp.
+    if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+                         kBionicLibsMountPointDir)) {
+        LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX.";
+        // Clean up and exit.
+        DeactivateApexPackages(active_packages);
+        exit(215);
+    }
+    if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+                         kBionicLibsMountPointDir64)) {
+        LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX.";
+        // Clean up and exit.
+        DeactivateApexPackages(active_packages);
+        exit(216);
     }
 
-    execv(argv[0], static_cast<char * const *>(const_cast<char**>(argv)));
-    PLOG(ERROR) << "execv(OTAPREOPT) failed.";
-    exit(99);
+    // Now go on and run otapreopt.
+
+    // Incoming:  cmd + status-fd + target-slot + cmd...      | Incoming | = argc
+    // Outgoing:  cmd             + target-slot + cmd...      | Outgoing | = argc - 1
+    std::vector<std::string> cmd;
+    cmd.reserve(argc);
+    cmd.push_back("/system/bin/otapreopt");
+
+    // The first parameter is the status file descriptor, skip.
+    for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
+        cmd.push_back(arg[i]);
+    }
+
+    // Fork and execute otapreopt in its own process.
+    std::string error_msg;
+    bool exec_result = Exec(cmd, &error_msg);
+    if (!exec_result) {
+        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+    }
+
+    // Tear down the work down by the apexd logic. (i.e. deactivate packages).
+    DeactivateApexPackages(active_packages);
+
+    if (!exec_result) {
+        exit(213);
+    }
+
+    return 0;
 }
 
 }  // namespace installd
diff --git a/cmds/installd/otapreopt_utils.cpp b/cmds/installd/otapreopt_utils.cpp
new file mode 100644
index 0000000..124f726
--- /dev/null
+++ b/cmds/installd/otapreopt_utils.cpp
@@ -0,0 +1,88 @@
+/*
+ ** 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.
+ */
+
+#include "otapreopt_utils.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+using android::base::Join;
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
+    const std::string command_line = Join(arg_vector, ' ');
+
+    CHECK_GE(arg_vector.size(), 1U) << command_line;
+
+    // Convert the args to char pointers.
+    const char* program = arg_vector[0].c_str();
+    std::vector<char*> args;
+    for (size_t i = 0; i < arg_vector.size(); ++i) {
+        const std::string& arg = arg_vector[i];
+        char* arg_str = const_cast<char*>(arg.c_str());
+        CHECK(arg_str != nullptr) << i;
+        args.push_back(arg_str);
+    }
+    args.push_back(nullptr);
+
+    // Fork and exec.
+    pid_t pid = fork();
+    if (pid == 0) {
+        // No allocation allowed between fork and exec.
+
+        // Change process groups, so we don't get reaped by ProcessManager.
+        setpgid(0, 0);
+
+        execv(program, &args[0]);
+
+        PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+        // _exit to avoid atexit handlers in child.
+        _exit(1);
+    } else {
+        if (pid == -1) {
+            *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
+                    command_line.c_str(), strerror(errno));
+            return false;
+        }
+
+        // wait for subprocess to finish
+        int status;
+        pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (got_pid != pid) {
+            *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
+                    "wanted %d, got %d: %s",
+                    command_line.c_str(), pid, got_pid, strerror(errno));
+            return false;
+        }
+        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+            *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
+                    command_line.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/otapreopt_utils.h b/cmds/installd/otapreopt_utils.h
index 436e554..03a6d87 100644
--- a/cmds/installd/otapreopt_utils.h
+++ b/cmds/installd/otapreopt_utils.h
@@ -18,6 +18,8 @@
 #define OTAPREOPT_UTILS_H_
 
 #include <regex>
+#include <string>
+#include <vector>
 
 namespace android {
 namespace installd {
@@ -28,6 +30,9 @@
     return std::regex_match(input, slot_suffix_match, slot_suffix_regex);
 }
 
+// Wrapper on fork/execv to run a command in a subprocess.
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 739f33f..9c9db0f 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -28,6 +28,7 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
     ],
@@ -50,6 +51,7 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
     ],
@@ -72,6 +74,7 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libprocessgroup",
         "libselinux",
         "libutils",
     ],
diff --git a/cmds/installd/tests/binder_test_utils.h b/cmds/installd/tests/binder_test_utils.h
new file mode 100644
index 0000000..efd1391
--- /dev/null
+++ b/cmds/installd/tests/binder_test_utils.h
@@ -0,0 +1,46 @@
+/*
+ * 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/Status.h>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+#define ASSERT_BINDER_SUCCESS(expr)                                              \
+    ({                                                                           \
+        binder::Status expect_status = (expr);                                   \
+        ASSERT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str();  \
+        expect_status;                                                           \
+    })
+#define ASSERT_BINDER_FAIL(expr)                \
+    ({                                          \
+        binder::Status expect_status = (expr);  \
+        ASSERT_FALSE(expect_status.isOk());     \
+        expect_status;                          \
+    })
+#define EXPECT_BINDER_SUCCESS(expr)                                              \
+    ({                                                                           \
+        binder::Status expect_status = (expr);                                   \
+        EXPECT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str();  \
+        expect_status;                                                           \
+    })
+#define EXPECT_BINDER_FAIL(expr)                \
+    ({                                          \
+        binder::Status expect_status = (expr);  \
+        EXPECT_FALSE(expect_status.isOk());     \
+        expect_status;                          \
+    })
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 79e6859..78edce0 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,9 +23,11 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
-
+#include <binder/Status.h>
 #include <cutils/properties.h>
 
 #include <gtest/gtest.h>
@@ -33,6 +35,7 @@
 #include <selinux/android.h>
 #include <selinux/avc.h>
 
+#include "binder_test_utils.h"
 #include "dexopt.h"
 #include "InstalldNativeService.h"
 #include "globals.h"
@@ -84,6 +87,23 @@
     system(cmd.c_str());
 }
 
+template <typename Visitor>
+static void run_cmd_and_process_output(const std::string& cmd, const Visitor& visitor) {
+    FILE* file = popen(cmd.c_str(), "r");
+    CHECK(file != nullptr) << "Failed to ptrace " << cmd;
+    char* line = nullptr;
+    while (true) {
+        size_t n = 0u;
+        ssize_t value = getline(&line, &n, file);
+        if (value == -1) {
+            break;
+        }
+        visitor(line);
+    }
+    free(line);
+    fclose(file);
+}
+
 static int mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
     int ret = ::mkdir(path.c_str(), mode);
     if (ret != 0) {
@@ -221,7 +241,8 @@
     ::testing::AssertionResult create_mock_app() {
         // Create the oat dir.
         app_oat_dir_ = app_apk_dir_ + "/oat";
-        if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0) {
+        // For debug mode, the directory might already exist. Avoid erroring out.
+        if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) {
             return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
                                                  << " : " << strerror(errno);
         }
@@ -451,11 +472,9 @@
         std::unique_ptr<std::string> compilation_reason_ptr(new std::string("test-reason"));
 
         bool prof_result;
-        binder::Status prof_binder_result = service_->prepareAppProfile(
+        ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
-                /*dex_metadata*/ nullptr, &prof_result);
-
-        ASSERT_TRUE(prof_binder_result.isOk()) << prof_binder_result.toString8().c_str();
+                /*dex_metadata*/ nullptr, &prof_result));
         ASSERT_TRUE(prof_result);
 
         binder::Status result = service_->dexopt(apk_path_,
@@ -629,6 +648,50 @@
                         DEX2OAT_FROM_SCRATCH);
 }
 
+TEST_F(DexoptTest, ResolveStartupConstStrings) {
+    LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
+    const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
+    const std::string previous_value = android::base::GetProperty(property, "");
+    auto restore_property = android::base::make_scope_guard([=]() {
+        android::base::SetProperty(property, previous_value);
+    });
+    std::string odex = GetPrimaryDexArtifact(app_oat_dir_.c_str(), apk_path_, "odex");
+    // Disable the property to start.
+    bool found_disable = false;
+    ASSERT_TRUE(android::base::SetProperty(property, "false")) << property;
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+    run_cmd_and_process_output(
+            "oatdump --header-only --oat-file=" + odex,
+            [&](const std::string& line) {
+        if (line.find("--resolve-startup-const-strings=false") != std::string::npos) {
+            found_disable = true;
+        }
+    });
+    EXPECT_TRUE(found_disable);
+    // Enable the property and inspect that .art artifact is larger.
+    bool found_enable = false;
+    ASSERT_TRUE(android::base::SetProperty(property, "true")) << property;
+    CompilePrimaryDexOk("speed-profile",
+                        DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+                                DEXOPT_GENERATE_APP_IMAGE,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH);
+    run_cmd_and_process_output(
+            "oatdump --header-only --oat-file=" + odex,
+            [&](const std::string& line) {
+        if (line.find("--resolve-startup-const-strings=true") != std::string::npos) {
+            found_enable = true;
+        }
+    });
+    EXPECT_TRUE(found_enable);
+}
+
 class PrimaryDexReCompilationTest : public DexoptTest {
   public:
     virtual void SetUp() {
@@ -760,9 +823,8 @@
     void createProfileSnapshot(int32_t appid, const std::string& package_name,
             bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->createProfileSnapshot(
-                appid, package_name, kPrimaryProfile, apk_path_, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+                appid, package_name, kPrimaryProfile, apk_path_, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -802,9 +864,8 @@
                               const std::string& code_path,
                               bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->mergeProfiles(
-                kTestAppUid, package_name, code_path, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+        ASSERT_BINDER_SUCCESS(service_->mergeProfiles(
+                kTestAppUid, package_name, code_path, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -830,10 +891,9 @@
     void preparePackageProfile(const std::string& package_name, const std::string& profile_name,
             bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->prepareAppProfile(
+        ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
                 package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
-                /*dex_metadata*/ nullptr, &result);
-        ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+                /*dex_metadata*/ nullptr, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
@@ -919,8 +979,7 @@
     SetupProfiles(/*setup_ref*/ true);
     createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
 
-    binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, kPrimaryProfile);
-    ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+    ASSERT_BINDER_SUCCESS(service_->destroyProfileSnapshot(package_name_, kPrimaryProfile));
     struct stat st;
     ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
     ASSERT_EQ(ENOENT, errno);
@@ -978,7 +1037,7 @@
     ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
 
     // Run createAppData again which will offer to fix-up the profile directories.
-    ASSERT_TRUE(service_->createAppData(
+    ASSERT_BINDER_SUCCESS(service_->createAppData(
             volume_uuid_,
             package_name_,
             kTestUserId,
@@ -986,7 +1045,7 @@
             kTestAppUid,
             se_info_,
             kOSdkVersion,
-            &ce_data_inode_).isOk());
+            &ce_data_inode_));
 
     // Check the file access.
     CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
@@ -1032,9 +1091,8 @@
 
     void createBootImageProfileSnapshot(const std::string& classpath, bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->createProfileSnapshot(
-                -1, "android", "android.prof", classpath, &result);
-        ASSERT_TRUE(binder_result.isOk());
+        ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+                -1, "android", "android.prof", classpath, &result));
         ASSERT_EQ(expected_result, result);
 
         if (!expected_result) {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index a5af5d7..ed1a0f4 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -15,16 +15,24 @@
  */
 
 #include <sstream>
+#include <string>
+
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/statvfs.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 
+#include "binder_test_utils.h"
 #include "InstalldNativeService.h"
 #include "dexopt.h"
 #include "globals.h"
@@ -63,27 +71,28 @@
 
 static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
     const std::string fullPath = get_full_path(path);
-    ::mkdir(fullPath.c_str(), mode);
-    ::chown(fullPath.c_str(), owner, group);
-    ::chmod(fullPath.c_str(), mode);
+    EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
+    EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
+    EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
 }
 
 static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
     int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
-    ::fchown(fd, owner, group);
-    ::fchmod(fd, mode);
-    ::close(fd);
+    EXPECT_NE(fd, -1);
+    EXPECT_EQ(::fchown(fd, owner, group), 0);
+    EXPECT_EQ(::fchmod(fd, mode), 0);
+    EXPECT_EQ(::close(fd), 0);
 }
 
 static int stat_gid(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_gid;
 }
 
 static int stat_mode(const char* path) {
     struct stat buf;
-    ::stat(get_full_path(path).c_str(), &buf);
+    EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
     return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
 }
 
@@ -162,8 +171,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 32U);
 
@@ -182,8 +191,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 0U);
 }
@@ -197,8 +206,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_TRUE(service->hashSecondaryDexFile(
-        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+        dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
 
     EXPECT_EQ(result.size(), 0U);
 }
@@ -212,8 +221,8 @@
 
     std::vector<uint8_t> result;
     std::string dexPath = get_full_path("com.example/foo/file");
-    EXPECT_FALSE(service->hashSecondaryDexFile(
-        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+    EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
+        dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
 }
 
 TEST_F(ServiceTest, CalculateOat) {
@@ -240,5 +249,467 @@
     EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
 }
 
+static bool mkdirs(const std::string& path, mode_t mode) {
+    struct stat sb;
+    if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
+        return true;
+    }
+
+    if (!mkdirs(android::base::Dirname(path), mode)) {
+        return false;
+    }
+
+    return (::mkdir(path.c_str(), mode) != -1);
+}
+
+TEST_F(ServiceTest, CreateAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of the CE content but not the DE content.
+  int64_t ce_snapshot_inode;
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+  struct stat buf;
+  memset(&buf, 0, sizeof(buf));
+  ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
+  ASSERT_EQ(ce_snapshot_inode, (int64_t) buf.st_ino);
+
+  std::string ce_content, de_content;
+  // At this point, we should have the CE content but not the DE content.
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_FALSE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+
+  // Modify the CE content, so we can assert later that it's reflected
+  // in the snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE_MODIFIED", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of the DE content but not the CE content.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode));
+  // Only DE content snapshot was requested.
+  ASSERT_EQ(ce_snapshot_inode, 0);
+
+  // At this point, both the CE as well as the DE content should be fully
+  // populated.
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE", de_content);
+
+  // Modify the DE content, so we can assert later that it's reflected
+  // in our final snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE_MODIFIED", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Request a snapshot of both the CE as well as the DE content.
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("TEST_CONTENT_CE_MODIFIED", ce_content);
+  ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
+}
+
+TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  int64_t ce_snapshot_inode;
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+  // No CE content snapshot was performed.
+  ASSERT_EQ(ce_snapshot_inode, 0);
+
+  // The snapshot calls must succeed but there should be no snapshot
+  // created.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+}
+
+TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  // Simulate presence of an existing snapshot
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", rollback_ce_dir + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", rollback_de_dir + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  // Create app data.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_2_CE", fake_package_ce_path + "/file2",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_2_DE", fake_package_de_path + "/file2",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+  // Previous snapshot (with data for file1) must be cleared.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb));
+}
+
+TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
+  // Setup app data to make sure that fails due to wrong volumeUuid being
+  // passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
+          "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+}
+
+TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+  auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
+  auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
+  auto fake_package_de_cache_path = fake_package_de_path + "/cache";
+  auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto deleter = [&fake_package_ce_path, &fake_package_de_path,
+          &rollback_ce_dir, &rollback_de_dir]() {
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      delete_dir_contents_and_dir(rollback_ce_dir, true);
+      delete_dir_contents_and_dir(rollback_de_dir, true);
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_code_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+  // The snapshot call must clear cache.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_ce_code_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_de_cache_path + "/file1").c_str(), &sb));
+  ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
+}
+
+TEST_F(ServiceTest, RestoreAppDataSnapshot) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  // Write contents to the rollback location. We'll write the same files to the
+  // app data location and make sure the restore has overwritten them.
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+
+  std::string ce_content, de_content;
+  ASSERT_TRUE(android::base::ReadFileToString(
+      fake_package_ce_path + "/file1", &ce_content, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::ReadFileToString(
+      fake_package_de_path + "/file1", &de_content, false /* follow_symlinks */));
+  ASSERT_EQ("CE_RESTORE_CONTENT", ce_content);
+  ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
+}
+
+TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  // Prepare data for snapshot.
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  int64_t ce_snapshot_inode;
+  // Request a snapshot of both the CE as well as the DE content.
+  ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+  // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
+  ASSERT_NE(0, ce_snapshot_inode);
+  // Check snapshot is there.
+  struct stat sb;
+  ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+  // Check snapshot is deleted.
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+}
+
+TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  // Create a snapshot
+  ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+  ASSERT_TRUE(android::base::WriteStringToFile(
+          "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+          0700, 10000, 20000, false /* follow_symlinks */));
+
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+
+  // Check snapshot is deleted.
+  struct stat sb;
+  ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+  ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+  // Check that deleting already deleted snapshot is no-op.
+  ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+          "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+}
+
+TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+  // Setup rollback data to make sure that test fails due to wrong volumeUuid
+  // being passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
+          "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+}
+
+TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+  // Setup rollback data to make sure that fails due to wrong volumeUuid being
+  // passed, not because of some other reason.
+  auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+  auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+  ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+  ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+  auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+  auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+  ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+  ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+  auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+          &fake_package_ce_path, &fake_package_de_path]() {
+      delete_dir_contents(rollback_ce_dir, true);
+      delete_dir_contents(rollback_de_dir, true);
+      delete_dir_contents(fake_package_ce_path, true);
+      delete_dir_contents(fake_package_de_path, true);
+      rmdir(rollback_ce_dir.c_str());
+      rmdir(rollback_de_dir.c_str());
+  };
+  auto scope_guard = android::base::make_scope_guard(deleter);
+
+  EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
+          "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ad7a5ae..1782aa2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -18,6 +18,7 @@
 #include <string.h>
 
 #include <android-base/logging.h>
+#include <android-base/scopeguard.h>
 #include <gtest/gtest.h>
 
 #include "InstalldNativeService.h"
@@ -544,5 +545,58 @@
     EXPECT_EQ(0, MatchExtension("docx"));
 }
 
+TEST_F(UtilsTest, TestRollbackPaths) {
+    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));
+
+    EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
+    EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
+            create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback",
+            create_data_misc_ce_rollback_path(nullptr, 0));
+    EXPECT_EQ("/data/misc_ce/10/rollback",
+            create_data_misc_ce_rollback_path(nullptr, 10));
+
+    EXPECT_EQ("/data/misc_de/0/rollback",
+            create_data_misc_de_rollback_path(nullptr, 0));
+    EXPECT_EQ("/data/misc_de/10/rollback",
+            create_data_misc_de_rollback_path(nullptr, 10));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
+    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+
+    auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
+    auto deleter = [&rollback_ce_package_path]() {
+        delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+    };
+    auto scope_guard = android::base::make_scope_guard(deleter);
+
+    ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+
+    ino_t ce_data_inode;
+    ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+
+    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+    // Check that path defined by inode is picked even if it's not the same as
+    // the fallback one.
+    EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+            create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+
+    // These last couple of cases are never exercised in production because we
+    // only snapshot apps in the primary data partition. Exercise them here for
+    // the sake of completeness.
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
+            create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+    EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
+            create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index a7ef674..70eefe2 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2017 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 <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 74ad184..5b487bb 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <fts.h>
 #include <stdlib.h>
+#include <sys/capability.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/xattr.h>
@@ -34,6 +35,7 @@
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
+#include "dexopt_return_codes.h"
 #include "globals.h"  // extern variables.
 
 #ifndef LOG_TAG
@@ -68,6 +70,35 @@
     CHECK(is_valid_package_name(package_name));
 }
 
+static std::string resolve_ce_path_by_inode_or_fallback(const std::string& root_path,
+        ino_t ce_data_inode, const std::string& fallback) {
+    if (ce_data_inode != 0) {
+        DIR* dir = opendir(root_path.c_str());
+        if (dir == nullptr) {
+            PLOG(ERROR) << "Failed to opendir " << root_path;
+            return fallback;
+        }
+
+        struct dirent* ent;
+        while ((ent = readdir(dir))) {
+            if (ent->d_ino == ce_data_inode) {
+                auto resolved = StringPrintf("%s/%s", root_path.c_str(), ent->d_name);
+                if (resolved != fallback) {
+                    LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
+                            << " instead of " << fallback;
+                }
+                closedir(dir);
+                return resolved;
+            }
+        }
+        LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
+        closedir(dir);
+        return fallback;
+    } else {
+        return fallback;
+    }
+}
+
 /**
  * Create the path name where package app contents should be stored for
  * the given volume UUID and package name.  An empty UUID is assumed to
@@ -111,34 +142,8 @@
     // For testing purposes, rely on the inode when defined; this could be
     // optimized to use access() in the future.
     auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
-    if (ce_data_inode != 0) {
-        auto user_path = create_data_user_ce_path(volume_uuid, user);
-        DIR* dir = opendir(user_path.c_str());
-        if (dir == nullptr) {
-            PLOG(ERROR) << "Failed to opendir " << user_path;
-            return fallback;
-        }
-
-        struct dirent* ent;
-        while ((ent = readdir(dir))) {
-            if (ent->d_ino == ce_data_inode) {
-                auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
-#if DEBUG_XATTRS
-                if (resolved != fallback) {
-                    LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
-                            << " instead of " << fallback;
-                }
-#endif
-                closedir(dir);
-                return resolved;
-            }
-        }
-        LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
-        closedir(dir);
-        return fallback;
-    } else {
-        return fallback;
-    }
+    auto user_path = create_data_user_ce_path(volume_uuid, user);
+    return resolve_ce_path_by_inode_or_fallback(user_path, ce_data_inode, fallback);
 }
 
 std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -192,6 +197,34 @@
     return StringPrintf("%s/user_de/%u", data.c_str(), userid);
 }
 
+
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) {
+    return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) {
+    return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name, ino_t ce_rollback_inode) {
+    auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+    auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+    return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
+}
+
+std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name) {
+    return StringPrintf("%s/%s",
+           create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+}
+
 /**
  * Create the path name for media for a certain userid.
  */
@@ -1063,5 +1096,26 @@
     }
 }
 
+void drop_capabilities(uid_t uid) {
+    if (setgid(uid) != 0) {
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
+    }
+    if (setuid(uid) != 0) {
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
+    }
+    // drop capabilities
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    if (capset(&capheader, &capdata[0]) < 0) {
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
+    }
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index d05724a..5d3a97d 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,6 +61,15 @@
 std::string create_data_user_ce_package_path_as_user_link(
         const char* volume_uuid, userid_t userid, const char* package_name);
 
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name);
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name, ino_t ce_rollback_inode);
+std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name);
+
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
 std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
@@ -140,6 +149,8 @@
 // It returns true if there were no errors at all, and false otherwise.
 bool collect_profiles(std::vector<std::string>* profiles_paths);
 
+void drop_capabilities(uid_t uid);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
new file mode 100644
index 0000000..f1ac717
--- /dev/null
+++ b/cmds/installd/view_compiler.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "view_compiler.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
+
+namespace android {
+namespace installd {
+
+using base::unique_fd;
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+                   int uid) {
+    CHECK(apk_path != nullptr);
+    CHECK(package_name != nullptr);
+    CHECK(out_dex_file != nullptr);
+
+    // viewcompiler won't have permission to open anything, so we have to open the files first
+    // and pass file descriptors.
+
+    // Open input file
+    unique_fd infd{open(apk_path, 0)};
+    if (infd.get() < 0) {
+        PLOG(ERROR) << "Could not open input file: " << apk_path;
+        return false;
+    }
+
+    // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
+    // we close stdout and open it towards the right output.
+    unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)};
+    if (outfd.get() < 0) {
+        PLOG(ERROR) << "Could not open output file: " << out_dex_file;
+        return false;
+    }
+    if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
+        PLOG(ERROR) << "Could not change output file permissions";
+        return false;
+    }
+    if (close(STDOUT_FILENO) != 0) {
+        PLOG(ERROR) << "Could not close stdout";
+        return false;
+    }
+    if (dup2(outfd, STDOUT_FILENO) < 0) {
+        PLOG(ERROR) << "Could not duplicate output file descriptor";
+        return false;
+    }
+
+    // Prepare command line arguments for viewcompiler
+    std::string args[] = {"/system/bin/viewcompiler",
+                          "--apk",
+                          "--infd",
+                          android::base::StringPrintf("%d", infd.get()),
+                          "--dex",
+                          "--package",
+                          package_name};
+    char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
+                          const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
+                          const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
+                          const_cast<char*>(args[6].c_str()), nullptr};
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        // Now that we've opened the files we need, drop privileges.
+        drop_capabilities(uid);
+        execv("/system/bin/viewcompiler", argv);
+        _exit(1);
+    }
+
+    return wait_child(pid) == 0;
+}
+
+} // namespace installd
+} // namespace android
\ No newline at end of file
diff --git a/cmds/installd/view_compiler.h b/cmds/installd/view_compiler.h
new file mode 100644
index 0000000..f7c6e57
--- /dev/null
+++ b/cmds/installd/view_compiler.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#ifndef VIEW_COMPILER_H_
+#define VIEW_COMPILER_H_
+
+namespace android {
+namespace installd {
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+                   int uid);
+
+} // namespace installd
+} // namespace android
+
+#endif // VIEW_COMPILER_H_
\ No newline at end of file
diff --git a/data/etc/android.hardware.telephony.ims.xml b/data/etc/android.hardware.telephony.ims.xml
new file mode 100644
index 0000000..eeb7b00
--- /dev/null
+++ b/data/etc/android.hardware.telephony.ims.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices that support IMS via ImsService APIs. -->
+<permissions>
+    <feature name="android.hardware.telephony.ims" />
+</permissions>
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 05d96ff..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -112,15 +112,25 @@
 
 #if __ANDROID_API__ >= 29
 
+/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
 enum ResNsendFlags : uint32_t {
-    // Send a single request to a single resolver and fail on timeout or network errors
+    /**
+     * Send a single request to a single resolver and fail on timeout or network errors
+     */
     ANDROID_RESOLV_NO_RETRY = 1 << 0,
 
-    // Do not cache the result of the lookup. The lookup may return a result that is already
-    // in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+    /**
+     * Do not cache the result of the lookup. The lookup may return a result that is already
+     * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+     */
     ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
 
-    // Don't lookup the request in cache, do not write back the response into the cache
+    /**
+     * Don't lookup the request in cache.
+     */
     ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
 };
 
@@ -136,8 +146,7 @@
  * POSIX error code (see errno.h) if an immediate error occurs.
  */
 int android_res_nquery(net_handle_t network,
-        const char *dname, int ns_class, int ns_type,
-        enum ResNsendFlags flags) __INTRODUCED_IN(29);
+        const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
 
 /**
  * Issue the query |msg| on the given |network|.
@@ -148,10 +157,11 @@
  * POSIX error code (see errno.h) if an immediate error occurs.
  */
 int android_res_nsend(net_handle_t network,
-        const uint8_t *msg, size_t msglen, enum ResNsendFlags flags) __INTRODUCED_IN(29);
+        const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
 
 /**
  * Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
  *
  * Returns:
  *     < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b2db945..0423264 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -181,7 +181,10 @@
                 if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
                     int size = ashmem_get_size_region(obj.handle);
                     if (size > 0) {
-                        *outAshmemSize -= size;
+                        // ashmem size might have changed since last time it was accounted for, e.g.
+                        // in acquire_object(). Value of *outAshmemSize is not critical since we are
+                        // releasing the object anyway. Check for integer overflow condition.
+                        *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
                     }
                 }
 
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index f6381f7..0d30560 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -54,6 +54,7 @@
     virtual const String16&     getInterfaceDescriptor() const;
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
@@ -66,6 +67,7 @@
     explicit                    BpInterface(const sp<IBinder>& remote);
 
 protected:
+    typedef INTERFACE           BaseInterface;
     virtual IBinder*            onAsBinder();
 };
 
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 05655c1..a96c9a0 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -16,7 +16,7 @@
 
 cc_library {
     name: "libbinder_ndk",
-    vendor_available: false,
+    vendor_available: true,
 
     export_include_dirs: [
         "include_ndk",
@@ -39,12 +39,24 @@
     ],
 
     shared_libs: [
-        "libandroid_runtime",
         "libbase",
         "libbinder",
         "libutils",
     ],
 
+    required: [
+        // libbinder_ndk may be used by Java and non-Java things. When lower-level things use it,
+        // they shouldn't have to take on the cost of loading libandroid_runtime.
+        "libandroid_runtime",
+    ],
+
+    header_libs: [
+        "jni_headers",
+    ],
+    export_header_lib_headers: [
+        "jni_headers",
+    ],
+
     version_script: "libbinder_ndk.map.txt",
     stubs: {
         symbol_file: "libbinder_ndk.map.txt",
@@ -60,12 +72,10 @@
         "include_ndk/android/*.h",
     ],
     license: "NOTICE",
-    draft: true,
 }
 
 ndk_library {
     name: "libbinder_ndk",
     symbol_file: "libbinder_ndk.map.txt",
     first_version: "29",
-    draft: true,
 }
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
index baea2e8..4a31080 100644
--- a/libs/binder/ndk/ibinder_jni.cpp
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -17,15 +17,68 @@
 #include <android/binder_ibinder_jni.h>
 #include "ibinder_internal.h"
 
-#include <android_util_Binder.h>
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+
+#include <mutex>
+
+#include <dlfcn.h>
 
 using ::android::IBinder;
-using ::android::ibinderForJavaObject;
-using ::android::javaObjectForIBinder;
 using ::android::sp;
 
+struct LazyAndroidRuntime {
+    typedef sp<IBinder> (*FromJava)(JNIEnv* env, jobject obj);
+    typedef jobject (*ToJava)(JNIEnv* env, const sp<IBinder>& val);
+
+    static FromJava ibinderForJavaObject;
+    static ToJava javaObjectForIBinder;
+
+    static void load() {
+        std::call_once(mLoadFlag, []() {
+            void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+            if (handle == nullptr) {
+                LOG(WARNING) << "Could not open libandroid_runtime.";
+                return;
+            }
+
+            ibinderForJavaObject = reinterpret_cast<FromJava>(
+                    dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+            if (ibinderForJavaObject == nullptr) {
+                LOG(WARNING) << "Could not find ibinderForJavaObject.";
+                // no return
+            }
+
+            javaObjectForIBinder = reinterpret_cast<ToJava>(dlsym(
+                    handle, "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
+            if (javaObjectForIBinder == nullptr) {
+                LOG(WARNING) << "Could not find javaObjectForIBinder.";
+                // no return
+            }
+        });
+    }
+
+   private:
+    static std::once_flag mLoadFlag;
+
+    LazyAndroidRuntime(){};
+};
+
+LazyAndroidRuntime::FromJava LazyAndroidRuntime::ibinderForJavaObject = nullptr;
+LazyAndroidRuntime::ToJava LazyAndroidRuntime::javaObjectForIBinder = nullptr;
+std::once_flag LazyAndroidRuntime::mLoadFlag;
+
 AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
-    sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    LazyAndroidRuntime::load();
+    if (LazyAndroidRuntime::ibinderForJavaObject == nullptr) {
+        return nullptr;
+    }
+
+    sp<IBinder> ibinder = (LazyAndroidRuntime::ibinderForJavaObject)(env, binder);
 
     sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
     AIBinder_incStrong(cbinder.get());
@@ -38,5 +91,10 @@
         return nullptr;
     }
 
-    return javaObjectForIBinder(env, binder->getBinder());
+    LazyAndroidRuntime::load();
+    if (LazyAndroidRuntime::javaObjectForIBinder == nullptr) {
+        return nullptr;
+    }
+
+    return (LazyAndroidRuntime::javaObjectForIBinder)(env, binder->getBinder());
 }
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index 80b6c07..055c79b 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -33,6 +33,15 @@
 binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
 
 /**
+ * Gets a binder object with this specific instance name. Will return nullptr immediately if the
+ * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
+ * function is responsible for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+
+/**
  * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
  * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
  * for calling AIBinder_decStrong).
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 80773f3..c6868b0 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -109,6 +109,8 @@
     AIBinder* mBinder = nullptr;
 };
 
+namespace impl {
+
 /**
  * This baseclass owns a single object, used to make various classes RAII.
  */
@@ -169,10 +171,12 @@
     T mT;
 };
 
+}  // namespace impl
+
 /**
  * Convenience wrapper. See AParcel.
  */
-class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+class ScopedAParcel : public impl::ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -185,7 +189,7 @@
 /**
  * Convenience wrapper. See AStatus.
  */
-class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -209,8 +213,8 @@
  * Convenience wrapper. See AIBinder_DeathRecipient.
  */
 class ScopedAIBinder_DeathRecipient
-    : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
-                             nullptr> {
+    : public impl::ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+                                   nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -225,7 +229,7 @@
  * Convenience wrapper. See AIBinder_Weak.
  */
 class ScopedAIBinder_Weak
-    : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+    : public impl::ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
    public:
     /**
      * Takes ownership of a.
@@ -243,7 +247,7 @@
 /**
  * Convenience wrapper for a file descriptor.
  */
-class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+class ScopedFileDescriptor : public impl::ScopedAResource<int, int, close, -1> {
    public:
     /**
      * Takes ownership of a.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f0d25f7..655f4d5 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -91,6 +91,7 @@
     ABinderProcess_setThreadPoolMaxThreadCount; # apex
     ABinderProcess_startThreadPool; # apex
     AServiceManager_addService; # apex
+    AServiceManager_checkService; # apex
     AServiceManager_getService; # apex
   local:
     *;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 9ddc555..d0b166d 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -37,6 +37,18 @@
     status_t status = sm->addService(String16(instance), binder->getBinder());
     return PruneStatusT(status);
 }
+AIBinder* AServiceManager_checkService(const char* instance) {
+    if (instance == nullptr) {
+        return nullptr;
+    }
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->checkService(String16(instance));
+
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+    AIBinder_incStrong(ret.get());
+    return ret.get();
+}
 AIBinder* AServiceManager_getService(const char* instance) {
     if (instance == nullptr) {
         return nullptr;
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index c159d71..bff601e 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -35,6 +35,19 @@
 //     EXPECT_EQ(nullptr, foo.get());
 // }
 
+TEST(NdkBinder, CheckServiceThatDoesntExist) {
+    AIBinder* binder = AServiceManager_checkService("asdfghkl;");
+    ASSERT_EQ(nullptr, binder);
+}
+
+TEST(NdkBinder, CheckServiceThatDoesExist) {
+    AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService);
+    EXPECT_NE(nullptr, binder);
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+
+    AIBinder_decStrong(binder);
+}
+
 TEST(NdkBinder, DoubleNumber) {
     sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
     ASSERT_NE(foo, nullptr);
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 17e8f6b..784e2c8 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -23,7 +23,7 @@
 
 namespace android {
 
-class NativeLoaderNamespace;
+struct NativeLoaderNamespace;
 
 class GraphicsEnv {
 public:
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index a7c7e79..73150dc 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,8 +1,7 @@
-brianderson@google.com
 jessehall@google.com
 jwcai@google.com
+lpy@google.com
+marissaw@google.com
 mathias@google.com
-olv@google.com
-pceballos@google.com
 racarr@google.com
 stoza@google.com
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..b377a41 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -40,13 +40,14 @@
 #define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 #define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
 
-#define ATRACE_BUFFER_INDEX(index)                                   \
-    if (ATRACE_ENABLED()) {                                          \
-        char ___traceBuf[1024];                                      \
-        snprintf(___traceBuf, 1024, "%s: %d",                        \
-                mCore->mConsumerName.string(), (index));             \
-        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);  \
-    }
+#define ATRACE_BUFFER_INDEX(index)                                                         \
+    do {                                                                                   \
+        if (ATRACE_ENABLED()) {                                                            \
+            char ___traceBuf[1024];                                                        \
+            snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+            android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);                    \
+        }                                                                                  \
+    } while (false)
 
 namespace android {
 
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
new file mode 100644
index 0000000..45eab00
--- /dev/null
+++ b/libs/incidentcompanion/Android.bp
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+filegroup {
+    name: "incidentcompanion_aidl",
+    srcs: [
+        "binder/android/os/IIncidentAuthListener.aidl",
+        "binder/android/os/IIncidentCompanion.aidl",
+    ],
+    path: "binder",
+}
+
+cc_library_static {
+    name: "libincidentcompanion",
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+    aidl: {
+        local_include_dirs: ["binder"],
+        export_aidl_headers: true,
+    },
+    srcs: [
+        ":incidentcompanion_aidl",
+    ],
+    export_include_dirs: ["binder"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wunused-parameter",
+    ],
+}
+
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
similarity index 66%
rename from cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
rename to libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
index c1a7f15..5484be8 100644
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
+++ b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
@@ -17,7 +17,18 @@
 package android.os;
 
 /**
-  * Specifies arguments for IDumpstate.
-  * {@hide}
-  */
-parcelable DumpstateOptions cpp_header "android/os/DumpstateOptions.h";
+ * Callback for IIncidentCompanion.
+ *
+ * @hide
+ */
+oneway interface IIncidentAuthListener {
+    /**
+     * The user approved the incident or bug report to be sent.
+     */
+    void onReportApproved();
+
+    /**
+     * The user did not approve the incident or bug report to be sent.
+     */
+    void onReportDenied();
+}
diff --git a/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
new file mode 100644
index 0000000..6bf98d2
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
@@ -0,0 +1,72 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+import android.os.IIncidentAuthListener;
+
+/**
+ * Helper service for incidentd and dumpstated to provide user feedback
+ * and authorization for bug and inicdent reports to be taken.
+ *
+ * @hide
+ */
+interface IIncidentCompanion {
+    /**
+     * Request an authorization for an incident or bug report.
+     * // TODO(b/111441001): Add the permission
+     * <p>
+     * This function requires the ___ permission.
+     *
+     * @param callingUid The original application that requested the report.  This function
+     *      returns via the callback whether the application should be trusted.  It is up
+     *      to the caller to actually implement the restriction to take or not take
+     *      the incident or bug report.
+     * @param flags FLAG_CONFIRMATION_DIALOG (0x1) - to show this as a dialog.  Otherwise
+     *      a dialog will be shown as a notification.
+     * @param callback Interface to receive results.  The results may not come back for
+     *      a long (user's choice) time, or ever (if they never respond to the notification).
+     *      Authorization requests are not persisted across reboot.  It is up to the calling
+     *      service to request another authorization after reboot if they still would like
+     *      to send their report.
+     */
+    oneway void authorizeReport(int callingUid, String callingPackage,
+            int flags, IIncidentAuthListener callback);
+
+    /**
+     * Cancel an authorization.
+     */
+    oneway void cancelAuthorization(IIncidentAuthListener callback);
+
+    /**
+     * Return the list of pending approvals.
+     */
+    List<String> getPendingReports();
+
+    /**
+     * The user has authorized the report to be shared.
+     *
+     * @param uri the report.
+     */
+    void approveReport(String uri);
+
+    /**
+     * The user has denied the report from being shared.
+     *
+     * @param uri the report.
+     */
+    void denyReport(String uri);
+}
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 6926f7f..324d443 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -57,15 +57,15 @@
             uint8_t b[16];
             int64_t i64[2];
         };
-        uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+        explicit uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
         uuid_t() : b{0} {}
     };
 
     Sensor(const Sensor&) = default;
     Sensor& operator=(const Sensor&) = default;
 
-    Sensor(const char * name = "");
-    Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+    explicit Sensor(const char * name = "");
+    explicit Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
     Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
     ~Sensor();
 
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index baed2ee..8176578 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -64,7 +64,7 @@
     // Default sensor sample period
     static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
 
-    SensorEventQueue(const sp<ISensorEventConnection>& connection);
+    explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
     virtual ~SensorEventQueue();
     virtual void onFirstRef();
 
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 23f7a91..f09c9c6 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -71,7 +71,7 @@
     void sensorManagerDied();
     static status_t waitForSensorService(sp<ISensorServer> *server);
 
-    SensorManager(const String16& opPackageName);
+    explicit SensorManager(const String16& opPackageName);
     status_t assertStateLocked();
 
 private:
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index 3938e4f..97ead21 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -1,5 +1,7 @@
-jiyong@google.com
+lpy@google.com
+marissaw@google.com
 mathias@google.com
-olv@google.com
 romainguy@google.com
 stoza@google.com
+jwcai@google.com
+tianyuj@google.com
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 233e0fc..26e8201 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -47,6 +47,7 @@
     "liblog",
     "libhardware",
     "libnativewindow",
+    "libprocessgroup",
     "libutils",
     "libEGL",
     "libGLESv1_CM",
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 26aed4f..a27d58d 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -12,9 +12,9 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
-#include <cutils/sched_policy.h>
 #include <log/log.h>
 #include <private/dvr/display_client.h>
+#include <processgroup/sched_policy.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
 
diff --git a/opengl/libagl/Android.bp b/opengl/libagl/Android.bp
new file mode 100644
index 0000000..6ec24b3
--- /dev/null
+++ b/opengl/libagl/Android.bp
@@ -0,0 +1,99 @@
+//
+// Build the software OpenGL ES library
+//
+
+cc_defaults {
+    name: "libGLES_android_defaults",
+
+    cflags: [
+        "-DLOG_TAG=\"libagl\"",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-fvisibility=hidden",
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libhardware",
+        "libutils",
+        "liblog",
+        "libpixelflinger",
+        "libETC1",
+        "libui",
+        "libnativewindow",
+    ],
+
+    // we need to access the private Bionic header <bionic_tls.h>
+    include_dirs: ["bionic/libc/private"],
+
+    arch: {
+        arm: {
+            cflags: ["-fstrict-aliasing"],
+        },
+
+        mips: {
+            cflags: [
+                "-fstrict-aliasing",
+                // The graphics code can generate division by zero
+                "-mno-check-zero-division",
+            ],
+        },
+    },
+}
+
+cc_library_shared {
+    name: "libGLES_android",
+    defaults: ["libGLES_android_defaults"],
+
+    whole_static_libs: ["libGLES_android_arm"],
+
+    srcs: [
+        "egl.cpp",
+        "state.cpp",
+        "texture.cpp",
+        "Tokenizer.cpp",
+        "TokenManager.cpp",
+        "TextureObjectManager.cpp",
+        "BufferObjectManager.cpp",
+    ],
+
+    arch: {
+        arm: {
+            srcs: [
+                "fixed_asm.S",
+                "iterators.S",
+            ],
+        },
+
+        mips: {
+            rev6: {
+                srcs: ["arch-mips/fixed_asm.S"],
+            },
+        },
+    },
+
+    relative_install_path: "egl",
+}
+
+cc_library_static {
+    name: "libGLES_android_arm",
+    defaults: ["libGLES_android_defaults"],
+
+    srcs: [
+        "array.cpp",
+        "fp.cpp",
+        "light.cpp",
+        "matrix.cpp",
+        "mipmap.cpp",
+        "primitives.cpp",
+        "vertex.cpp",
+    ],
+
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+}
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
deleted file mode 100644
index 15a12e4..0000000
--- a/opengl/libagl/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Build the software OpenGL ES library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	egl.cpp                     \
-	state.cpp		            \
-	texture.cpp		            \
-    Tokenizer.cpp               \
-    TokenManager.cpp            \
-    TextureObjectManager.cpp    \
-    BufferObjectManager.cpp     \
-	array.cpp.arm		        \
-	fp.cpp.arm		            \
-	light.cpp.arm		        \
-	matrix.cpp.arm		        \
-	mipmap.cpp.arm		        \
-	primitives.cpp.arm	        \
-	vertex.cpp.arm
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui libnativewindow
-
-LOCAL_SRC_FILES_arm += fixed_asm.S iterators.S
-LOCAL_CFLAGS_arm += -fstrict-aliasing
-
-ifndef ARCH_MIPS_REV6
-LOCAL_SRC_FILES_mips += arch-mips/fixed_asm.S
-endif
-LOCAL_CFLAGS_mips += -fstrict-aliasing
-# The graphics code can generate division by zero
-LOCAL_CFLAGS_mips += -mno-check-zero-division
-
-LOCAL_CFLAGS += -Wall -Werror
-
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_MODULE_RELATIVE_PATH := egl
-LOCAL_MODULE:= libGLES_android
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
deleted file mode 100644
index 2f42ab6..0000000
--- a/opengl/libs/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
deleted file mode 100644
index 134854a..0000000
--- a/opengl/tests/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-dirs := \
-	linetex \
-	swapinterval \
-	textures \
-	tritex \
-
-ifneq (,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
-	gl2_cameraeye \
-	gl2_java \
-	gl2_jni \
-	gldual \
-	gl_jni \
-	gl_perfapp \
-	lighting1709 \
-	testLatency \
-	testPauseResume \
-	testViewport \
-
-endif # JAVA_SUPPORT
-
-ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
-	testFramerate
-
-endif # JAVA_SUPPORT platform
-
-include $(call all-named-subdir-makefiles, $(dirs))
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
new file mode 100644
index 0000000..00e00df
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+    name: "GL2CameraEye",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_cameraeye/Android.mk b/opengl/tests/gl2_cameraeye/Android.mk
deleted file mode 100644
index 4a43a9e..0000000
--- a/opengl/tests/gl2_cameraeye/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GL2CameraEye
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
new file mode 100644
index 0000000..a8e5d7d
--- /dev/null
+++ b/opengl/tests/gl2_java/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// OpenGL ES 2.0 Java sample
+//########################################################################
+android_app {
+    name: "GL2Java",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_java/Android.mk b/opengl/tests/gl2_java/Android.mk
deleted file mode 100644
index 71aa5a0..0000000
--- a/opengl/tests/gl2_java/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES 2.0 Java sample
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2Java
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
new file mode 100644
index 0000000..65f89b1
--- /dev/null
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+
+android_app {
+    name: "GL2JNI",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    jni_libs: ["libgl2jni"],
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+    name: "libgl2jni",
+    cflags: [
+        "-Werror",
+        "-Wno-error=unused-parameter",
+    ],
+    srcs: ["jni/gl_code.cpp"],
+    shared_libs: [
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+    ],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
deleted file mode 100644
index b0081c2..0000000
--- a/opengl/tests/gl2_jni/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2JNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgl2jni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
-  gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libEGL \
-	libGLESv2
-
-LOCAL_MODULE := libgl2jni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
new file mode 100644
index 0000000..5bec336
--- /dev/null
+++ b/opengl/tests/gl_jni/Android.bp
@@ -0,0 +1,34 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+    name: "GLJNI",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    jni_libs: ["libgljni"],
+}
+
+// Build JNI Shared Library
+
+cc_library_shared {
+    name: "libgljni",
+    cflags: [
+        "-Werror",
+        "-Wno-error=unused-parameter",
+    ],
+    srcs: ["jni/gl_code.cpp"],
+    shared_libs: [
+        "liblog",
+        "libEGL",
+        "libGLESv1_CM",
+    ],
+    sdk_version: "current",
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+}
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
deleted file mode 100644
index d64dfcf..0000000
--- a/opengl/tests/gl_jni/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLJNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgljni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
-  gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libEGL \
-	libGLESv1_CM
-
-LOCAL_MODULE := libgljni
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_ARM_MODE := arm
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
new file mode 100644
index 0000000..cf899ac
--- /dev/null
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES Perf App
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+    name: "GLPerf",
+    srcs: ["**/*.java"],
+    jni_libs: ["libglperf"],
+    // Run on Eclair
+    sdk_version: "7",
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+    name: "libglperf",
+    cflags: [
+        "-Werror",
+        "-Wno-error=unused-parameter",
+    ],
+    srcs: ["jni/gl_code.cpp"],
+    shared_libs: [
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+    ],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
deleted file mode 100644
index 3f411ea..0000000
--- a/opengl/tests/gl_perfapp/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES Perf App
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLPerf
-
-LOCAL_JNI_SHARED_LIBRARIES := libglperf
-
-# Run on Eclair
-LOCAL_SDK_VERSION := 7
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
-  gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libEGL \
-	libGLESv2
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MODULE := libglperf
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
new file mode 100644
index 0000000..2432566
--- /dev/null
+++ b/opengl/tests/gldual/Android.bp
@@ -0,0 +1,30 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+    name: "GLDual",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    jni_libs: ["libgldualjni"],
+}
+
+//########################################################################
+// Build JNI Shared Library
+//########################################################################
+cc_library_shared {
+    name: "libgldualjni",
+    cflags: [
+        "-Werror",
+        "-Wno-error=unused-parameter",
+    ],
+    srcs: ["jni/gl_code.cpp"],
+    shared_libs: [
+        "liblog",
+        "libEGL",
+        "libGLESv2",
+    ],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
deleted file mode 100644
index 5bdc0a8..0000000
--- a/opengl/tests/gldual/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLDual
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgldualjni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
-  gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libEGL \
-	libGLESv2
-
-LOCAL_MODULE := libgldualjni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
new file mode 100644
index 0000000..e734dd1
--- /dev/null
+++ b/opengl/tests/lighting1709/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+    name: "LightingTest",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    certificate: "platform",
+}
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
deleted file mode 100644
index 0047231..0000000
--- a/opengl/tests/lighting1709/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := LightingTest
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
new file mode 100644
index 0000000..dbc2cdb
--- /dev/null
+++ b/opengl/tests/linetex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+    name: "test-opengl-linetex",
+    srcs: ["linetex.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
deleted file mode 100644
index 3df0a0f..0000000
--- a/opengl/tests/linetex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	linetex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-linetex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
new file mode 100644
index 0000000..eed4dff
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+    name: "test-opengl-swapinterval",
+    srcs: ["swapinterval.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+    ],
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
deleted file mode 100644
index 2a2c12f..0000000
--- a/opengl/tests/swapinterval/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	swapinterval.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-swapinterval
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
new file mode 100644
index 0000000..5aa83b0
--- /dev/null
+++ b/opengl/tests/testFramerate/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// Test framerate and look for hiccups
+//########################################################################
+
+android_app {
+    name: "TestFramerate",
+    srcs: ["**/*.java"],
+    sdk_version: "system_current",
+}
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
deleted file mode 100644
index ca6654a..0000000
--- a/opengl/tests/testFramerate/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test framerate and look for hiccups
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestFramerate
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
new file mode 100644
index 0000000..c516dc3
--- /dev/null
+++ b/opengl/tests/testLatency/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// Test end-to-end latency.
+//########################################################################
+android_app {
+    name: "TestLatency",
+    sdk_version: "8",
+    srcs: ["**/*.java"],
+}
diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk
deleted file mode 100644
index 96417c7..0000000
--- a/opengl/tests/testLatency/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test end-to-end latency.
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SDK_VERSION := 8
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestLatency
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
new file mode 100644
index 0000000..810e895
--- /dev/null
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -0,0 +1,6 @@
+// OpenGL ES JNI sample
+android_app {
+    name: "TestEGL",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+}
diff --git a/opengl/tests/testPauseResume/Android.mk b/opengl/tests/testPauseResume/Android.mk
deleted file mode 100644
index dda5424..0000000
--- a/opengl/tests/testPauseResume/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestEGL
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
new file mode 100644
index 0000000..629b573
--- /dev/null
+++ b/opengl/tests/testViewport/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+    name: "TestViewport",
+    srcs: ["**/*.java"],
+    sdk_version: "8",
+}
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
deleted file mode 100644
index 9980e7d..0000000
--- a/opengl/tests/testViewport/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestViewport
-
-# Set a specific SDK version so we can run on Froyo.
-
-LOCAL_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
new file mode 100644
index 0000000..84adda2
--- /dev/null
+++ b/opengl/tests/textures/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+    name: "test-opengl-textures",
+    srcs: ["textures.cpp"],
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+    static_libs: ["libglTest"],
+    cflags: [
+        "-DGL_GLEXT_PROTOTYPES",
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
deleted file mode 100644
index 629a2d2..0000000
--- a/opengl/tests/textures/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	textures.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-textures
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
new file mode 100644
index 0000000..390397b
--- /dev/null
+++ b/opengl/tests/tritex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+    name: "test-opengl-tritex",
+    srcs: ["tritex.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libui",
+        "libgui",
+        "libutils",
+    ],
+    static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
deleted file mode 100644
index 7055afa..0000000
--- a/opengl/tests/tritex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	tritex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-    libEGL \
-    libGLESv1_CM \
-    libui \
-    libgui \
-    libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-tritex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/services/inputflinger/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/services/nativeperms/Android.bp b/services/nativeperms/Android.bp
new file mode 100644
index 0000000..cbc7d66
--- /dev/null
+++ b/services/nativeperms/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "nativeperms",
+    srcs: [
+        "nativeperms.cpp",
+        "android/os/IPermissionController.aidl",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbrillo",
+        "libbrillo-binder",
+        "libchrome",
+        "libutils",
+    ],
+    init_rc: ["nativeperms.rc"],
+}
diff --git a/services/nativeperms/Android.mk b/services/nativeperms/Android.mk
deleted file mode 100644
index 34ccd0b..0000000
--- a/services/nativeperms/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2016 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := nativeperms
-LOCAL_SRC_FILES := \
-    nativeperms.cpp \
-    android/os/IPermissionController.aidl
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := \
-    libbinder \
-    libbrillo \
-    libbrillo-binder \
-    libchrome \
-    libutils
-LOCAL_INIT_RC := nativeperms.rc
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
index 5a35410..031744a 100644
--- a/services/sensorservice/SensorRecord.h
+++ b/services/sensorservice/SensorRecord.h
@@ -25,7 +25,7 @@
 
 class SensorService::SensorRecord {
 public:
-    SensorRecord(const sp<const SensorEventConnection>& connection);
+    explicit SensorRecord(const sp<const SensorEventConnection>& connection);
     bool addConnection(const sp<const SensorEventConnection>& connection);
     bool removeConnection(const wp<const SensorEventConnection>& connection);
     size_t getNumConnections() const { return mConnections.size(); }
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index ddcee28..8d7a05b 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -43,7 +43,7 @@
 
 struct SensorManager final : public ISensorManager {
 
-    SensorManager(JavaVM* vm);
+    explicit SensorManager(JavaVM* vm);
     ~SensorManager();
 
     // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 495c14e..934ae58 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
 
     mat() { }
     mat(const mat& rhs)  : base(rhs) { }
-    mat(const base& rhs) : base(rhs) { }  // NOLINT(implicit)
+    mat(const base& rhs) : base(rhs) { }  // NOLINT(google-explicit-constructor)
 
     // -----------------------------------------------------------------------
     // conversion constructors
 
     // sets the diagonal to the value, off-diagonal to zero
-    mat(pTYPE rhs) {  // NOLINT(implicit)
+    mat(pTYPE rhs) {  // NOLINT(google-explicit-constructor)
         helpers::doAssign(*this, rhs);
     }
 
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
new file mode 100644
index 0000000..d33c0ca
--- /dev/null
+++ b/services/sensorservice/tests/Android.bp
@@ -0,0 +1,13 @@
+cc_binary {
+    name: "test-sensorservice",
+    srcs: ["sensorservicetest.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libutils",
+        "libsensor",
+        "libandroid",
+    ],
+}
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
deleted file mode 100644
index 8a9c36b..0000000
--- a/services/sensorservice/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	sensorservicetest.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-	libutils libsensor libandroid
-
-LOCAL_MODULE:= test-sensorservice
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 9e5d280..c195434 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
 
     vec() { }
     vec(const vec& rhs)  : base(rhs) { }
-    vec(const base& rhs) : base(rhs) { }  // NOLINT(implicit)
+    vec(const base& rhs) : base(rhs) { }  // NOLINT(google-explicit-constructor)
 
     // -----------------------------------------------------------------------
     // conversion constructors
 
-    vec(pTYPE rhs) {  // NOLINT(implicit)
+    vec(pTYPE rhs) {  // NOLINT(google-explicit-constructor)
         for (size_t i=0 ; i<SIZE ; i++)
             base::operator[](i) = rhs;
     }
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ce4daa5..5d4ac23 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -44,6 +44,7 @@
         "liblayers_proto",
         "liblog",
         "libpdx_default_transport",
+        "libprocessgroup",
         "libprotobuf-cpp-lite",
         "libsync",
         "libtimestats_proto",
@@ -173,6 +174,7 @@
         "libhidltransport",
         "liblayers_proto",
         "liblog",
+        "libprocessgroup",
         "libsurfaceflinger",
         "libtimestats_proto",
         "libutils",
@@ -197,23 +199,6 @@
     },
 }
 
-cc_library_shared {
-    name: "libsurfaceflinger_ddmconnection",
-    defaults: ["surfaceflinger_defaults"],
-    srcs: ["DdmConnection.cpp"],
-    shared_libs: [
-        "libcutils",
-        "libdl",
-        "liblog",
-    ],
-    product_variables: {
-        // uses jni which may not be available in PDK
-        pdk: {
-            enabled: false,
-        },
-    },
-}
-
 subdirs = [
     "layerproto",
     "TimeStats/timestatsproto",
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
deleted file mode 100644
index 35d55f5..0000000
--- a/services/surfaceflinger/DdmConnection.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 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 <dlfcn.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "jni.h"
-#include "DdmConnection.h"
-
-namespace android {
-
-void DdmConnection_start(const char* name) {
-    ALOGI("DdmConnection_start");
-    DdmConnection::start(name);
-}
-
-void DdmConnection::start(const char* name) {
-    JavaVM* vm;
-    JNIEnv* env;
-
-    // start a VM
-    JavaVMInitArgs args;
-    JavaVMOption opt;
-
-    opt.optionString =
-        "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-
-    args.version = JNI_VERSION_1_4;
-    args.options = &opt;
-    args.nOptions = 1;
-    args.ignoreUnrecognized = JNI_FALSE;
-
-
-    // TODO: Should this just link against libnativehelper and use its
-    // JNI_CreateJavaVM wrapper that essential does this dlopen/dlsym
-    // work based on the current system default runtime?
-    void* libart_dso = dlopen("libart.so", RTLD_NOW);
-    ALOGE_IF(!libart_dso, "DdmConnection: %s", dlerror());
-
-    void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW);
-    ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror());
-
-    if (!libart_dso || !libandroid_runtime_dso) {
-        goto error;
-    }
-
-    jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
-    JNI_CreateJavaVM = reinterpret_cast<decltype(JNI_CreateJavaVM)>(
-            dlsym(libart_dso, "JNI_CreateJavaVM"));
-    ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror());
-
-    jint (*registerNatives)(JNIEnv* env, jclass clazz);
-    registerNatives = reinterpret_cast<decltype(registerNatives)>(
-            dlsym(libandroid_runtime_dso,
-                "Java_com_android_internal_util_WithFramework_registerNatives"));
-    ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
-
-    if (!JNI_CreateJavaVM || !registerNatives) {
-        goto error;
-    }
-
-    if (JNI_CreateJavaVM(&vm, &env, &args) == 0) {
-        jclass startClass;
-        jmethodID startMeth;
-
-        // register native code
-        if (registerNatives(env, 0) == 0) {
-            // set our name by calling DdmHandleAppName.setAppName()
-            startClass = env->FindClass("android/ddm/DdmHandleAppName");
-            if (startClass) {
-                startMeth = env->GetStaticMethodID(startClass,
-                        "setAppName", "(Ljava/lang/String;I)V");
-                if (startMeth) {
-                    jstring str = env->NewStringUTF(name);
-                    env->CallStaticVoidMethod(startClass, startMeth, str, getuid());
-                    env->DeleteLocalRef(str);
-                }
-            }
-
-            // initialize DDMS communication by calling
-            // DdmRegister.registerHandlers()
-            startClass = env->FindClass("android/ddm/DdmRegister");
-            if (startClass) {
-                startMeth = env->GetStaticMethodID(startClass,
-                        "registerHandlers", "()V");
-                if (startMeth) {
-                    env->CallStaticVoidMethod(startClass, startMeth);
-                }
-            }
-        }
-    }
-    return;
-
-error:
-    if (libandroid_runtime_dso) {
-        dlclose(libandroid_runtime_dso);
-    }
-    if (libart_dso) {
-        dlclose(libart_dso);
-    }
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h
deleted file mode 100644
index 938d14b..0000000
--- a/services/surfaceflinger/DdmConnection.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_DDM_CONNECTION
-#define ANDROID_SF_DDM_CONNECTION
-
-namespace android {
-
-// wrapper for dlsym
-extern "C" void DdmConnection_start(const char* name);
-
-class DdmConnection {
-public:
-    // Creates a JVM and registers all handlers to DDMS.
-    // This allows tools relying on DDMS to find surfaceflinger
-    // (e.g: Memory Leak finder, heap analyzer, ...)
-    static void start(const char* name);
-};
-
-}; // namespace android
-
-#endif /* ANDROID_SF_DDM_CONNECTION */
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index dc2b300..ce0611c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,3 +1,4 @@
+akrulec@google.com
 chaviw@google.com
 lpy@google.com
 marissaw@google.com
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 82bf19f..4ec1e7f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,7 +67,6 @@
 #include "ColorLayer.h"
 #include "Colorizer.h"
 #include "ContainerLayer.h"
-#include "DdmConnection.h"
 #include "DispSync.h"
 #include "DisplayDevice.h"
 #include "EventControlThread.h"
@@ -225,7 +224,6 @@
         mAnimCompositionPending(false),
         mBootStage(BootStage::BOOTLOADER),
         mDebugRegion(0),
-        mDebugDDMS(0),
         mDebugDisableHWC(0),
         mDebugDisableTransformHint(0),
         mDebugInSwapBuffers(0),
@@ -305,16 +303,12 @@
     property_get("debug.sf.showupdates", value, "0");
     mDebugRegion = atoi(value);
 
-    property_get("debug.sf.ddms", value, "0");
-    mDebugDDMS = atoi(value);
-    if (mDebugDDMS) {
-        if (!startDdmConnection()) {
-            // start failed, and DDMS debugging not enabled
-            mDebugDDMS = 0;
-        }
-    }
     ALOGI_IF(mDebugRegion, "showupdates enabled");
-    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
+
+    // DDMS debugging deprecated (b/120782499)
+    property_get("debug.sf.ddms", value, "0");
+    int debugDdms = atoi(value);
+    ALOGI_IF(debugDdms, "DDMS debugging not supported");
 
     property_get("debug.sf.disable_backpressure", value, "0");
     mPropagateBackpressure = !atoi(value);
@@ -4501,24 +4495,6 @@
     return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ();
 }
 
-bool SurfaceFlinger::startDdmConnection()
-{
-    void* libddmconnection_dso =
-            dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
-    if (!libddmconnection_dso) {
-        return false;
-    }
-    void (*DdmConnection_start)(const char* name);
-    DdmConnection_start =
-            (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
-    if (!DdmConnection_start) {
-        dlclose(libddmconnection_dso);
-        return false;
-    }
-    (*DdmConnection_start)(getServiceName());
-    return true;
-}
-
 void SurfaceFlinger::updateColorMatrixLocked() {
     mat4 colorMatrix;
     if (mGlobalSaturationFactor != 1.0f) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 463a551..d2b1233 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -731,7 +731,6 @@
     void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
     void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
     void dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const;
-    bool startDdmConnection();
     void appendSfConfigString(String8& result) const;
     void checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
                          TraverseLayersFunction traverseLayers);
@@ -837,7 +836,6 @@
 
     // don't use a lock for these, we don't care
     int mDebugRegion;
-    int mDebugDDMS;
     int mDebugDisableHWC;
     int mDebugDisableTransformHint;
     volatile nsecs_t mDebugInSwapBuffers;
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
new file mode 100644
index 0000000..ac02d12
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -0,0 +1 @@
+zzyiwei@google.com
\ No newline at end of file
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index d0900e9..aefe704 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -21,13 +21,13 @@
 #include <android/frameworks/displayservice/1.0/IDisplayService.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <cutils/sched_policy.h>
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <displayservice/DisplayService.h>
 #include <hidl/LegacySupport.h>
+#include <processgroup/sched_policy.h>
 #include <configstore/Utils.h>
 #include "SurfaceFlinger.h"
 
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
index 6132956..f3d2bc9 100644
--- a/services/utils/Android.bp
+++ b/services/utils/Android.bp
@@ -18,6 +18,8 @@
 cc_library_static {
     name: "libserviceutils",
 
+    vendor_available: true,
+
     cflags: [
         "-Wall",
         "-Werror",
@@ -27,8 +29,13 @@
         "PriorityDumper.cpp",
     ],
 
-    clang: true,
+    header_libs: [
+        "libutils_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libutils_headers",
+    ],
+
     export_include_dirs: ["include"],
 }
-
-subdirs = ["tests"]
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index fed8481..206c8eb 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -84,8 +84,8 @@
         "libutils",
         "libcutils",
         "libz",
-        "libnativebridge",
-        "libnativeloader",
+        "libnativebridge_lazy",
+        "libnativeloader_lazy",
         "libnativewindow",
         "android.hardware.graphics.common@1.0",
     ],
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 009b257..ba4cf00 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -139,12 +139,12 @@
         auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
         if (app_namespace &&
             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
-            std::string error_msg;
-            dlhandle_ = OpenNativeLibrary(
+            char* error_msg = nullptr;
+            dlhandle_ = OpenNativeLibraryInNamespace(
                 app_namespace, path_.c_str(), &native_bridge_, &error_msg);
             if (!dlhandle_) {
-                ALOGE("failed to load layer library '%s': %s", path_.c_str(),
-                      error_msg.c_str());
+                ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
+                android::NativeLoaderFreeErrorMessage(error_msg);
                 refcount_ = 0;
                 return false;
             }
@@ -165,9 +165,10 @@
     std::lock_guard<std::mutex> lock(mutex_);
     if (--refcount_ == 0) {
         ALOGV("closing layer library '%s'", path_.c_str());
-        std::string error_msg;
+        char* error_msg = nullptr;
         if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
-            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+            android::NativeLoaderFreeErrorMessage(error_msg);
             refcount_++;
         } else {
            dlhandle_ = nullptr;
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 1dae456..9e2ff5b 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -33,6 +33,7 @@
     LayerRef& operator=(const LayerRef&) = delete;
 
     // provides bool-like behavior
+    // NOLINTNEXTLINE(google-explicit-constructor)
     operator const Layer*() const { return layer_; }
 
     PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;