Merge "Remove dumping raft logs"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index f8f0265..2d780f5 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,7 @@
 [Hook Scripts]
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
 installd_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/installd/"
+dumpstate_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/dumpstate/"
+dumpsys_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/dumpsys/"
+# bugreports matches both cmds/bugreport and cmds/bugreportz
+bugreports_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/bugreport"
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/bugreport/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/bugreportz/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index c852df1..5acc09d 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -133,6 +133,7 @@
     name: "dumpstate_test",
     defaults: ["dumpstate_defaults"],
     srcs: [
+        "dumpstate.cpp",
         "tests/dumpstate_test.cpp",
     ],
     static_libs: ["libgmock"],
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 85eb464..600a500 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -56,11 +56,11 @@
     timespec ts;
     ts.tv_sec = MSEC_TO_SEC(timeout_ms);
     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
-    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
     int saved_errno = errno;
 
     // Set the signals back the way they were.
-    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+    if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
         printf("*** sigprocmask failed: %s\n", strerror(errno));
         if (ret == 0) {
             return false;
@@ -310,7 +310,7 @@
         struct sigaction sigact;
         memset(&sigact, 0, sizeof(sigact));
         sigact.sa_handler = SIG_IGN;
-        sigaction(SIGPIPE, &sigact, NULL);
+        sigaction(SIGPIPE, &sigact, nullptr);
 
         execvp(path, (char**)args.data());
         // execvp's result will be handled after waitpid_with_timeout() below, but
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/dumpstate/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 618a91f..240fb74 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1710,24 +1710,118 @@
     // clang-format on
 }
 
-/** Main entry point for dumpstate. */
-int run_main(int argc, char* argv[]) {
-    int do_add_date = 0;
-    int do_zip_file = 0;
-    int do_vibrate = 1;
-    char* use_outfile = nullptr;
-    int use_socket = 0;
-    int use_control_socket = 0;
-    int do_fb = 0;
-    int do_broadcast = 0;
-    int is_remote_mode = 0;
-    bool show_header_only = false;
-    bool do_start_service = false;
-    bool telephony_only = false;
-    bool wifi_only = false;
-    int dup_stdout_fd;
-    int dup_stderr_fd;
+int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) {
+    int ret = -1;  // success
+    int c;
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
+        switch (c) {
+            // clang-format off
+            case 'd': options_.do_add_date = true;            break;
+            case 'z': options_.do_zip_file = true;            break;
+            case 'o': options_.use_outfile = optarg;          break;
+            case 's': options_.use_socket = true;             break;
+            case 'S': options_.use_control_socket = true;     break;
+            case 'v': options_.show_header_only = true;       break;
+            case 'q': options_.do_vibrate = false;            break;
+            case 'p': options_.do_fb = true;                  break;
+            case 'P': update_progress_ = true;                break;
+            case 'R': options_.is_remote_mode = true;         break;
+            case 'B': options_.do_broadcast = true;           break;
+            case 'V':                                         break;  // compatibility no-op
+            case 'h':
+                ret = 0;
+                break;
+            default:
+                fprintf(stderr, "Invalid option: %c\n", c);
+                ret = 1;
+                break;
+                // clang-format on
+        }
+    }
 
+    // TODO: use helper function to convert argv into a string
+    for (int i = 0; i < argc; i++) {
+        args_ += argv[i];
+        if (i < argc - 1) {
+            args_ += " ";
+        }
+    }
+
+    // Reset next index used by getopt so this can be called multiple times, for eg, in tests.
+    optind = 1;
+    return ret;
+}
+
+// TODO: Move away from system properties when we have binder.
+void Dumpstate::SetOptionsFromProperties() {
+    extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    if (!extra_options_.empty()) {
+        // Framework uses a system property to override some command-line args.
+        // Currently, it contains the type of the requested bugreport.
+        if (extra_options_ == "bugreportplus") {
+            // Currently, the dumpstate binder is only used by Shell to update progress.
+            options_.do_start_service = true;
+            update_progress_ = true;
+            options_.do_fb = false;
+        } else if (extra_options_ == "bugreportremote") {
+            options_.do_vibrate = false;
+            options_.is_remote_mode = true;
+            options_.do_fb = false;
+        } else if (extra_options_ == "bugreportwear") {
+            options_.do_start_service = true;
+            update_progress_ = true;
+            options_.do_zip_file = true;
+        } else if (extra_options_ == "bugreporttelephony") {
+            options_.telephony_only = true;
+        } else if (extra_options_ == "bugreportwifi") {
+            options_.wifi_only = true;
+            options_.do_zip_file = true;
+        } else {
+            MYLOGE("Unknown extra option: %s\n", extra_options_.c_str());
+        }
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    }
+
+    notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
+    if (!notification_title.empty()) {
+        // Reset the property
+        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
+
+        notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        if (!notification_description.empty()) {
+            // Reset the property
+            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+        }
+        MYLOGD("notification (title:  %s, description: %s)\n", notification_title.c_str(),
+               notification_description.c_str());
+    }
+}
+
+bool Dumpstate::ValidateOptions() {
+    if ((options_.do_zip_file || options_.do_add_date || ds.update_progress_ ||
+         options_.do_broadcast) &&
+        options_.use_outfile.empty()) {
+        return false;
+    }
+
+    if (options_.use_control_socket && !options_.do_zip_file) {
+        return false;
+    }
+
+    if (ds.update_progress_ && !options_.do_broadcast) {
+        return false;
+    }
+
+    if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast ||
+                                    !options_.do_zip_file || !options_.do_add_date)) {
+        return false;
+    }
+    return true;
+}
+
+/* Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
 
@@ -1744,97 +1838,12 @@
         }
     }
 
-    /* parse arguments */
-    int c;
-    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
-        switch (c) {
-            // clang-format off
-            case 'd': do_add_date = 1;            break;
-            case 'z': do_zip_file = 1;            break;
-            case 'o': use_outfile = optarg;       break;
-            case 's': use_socket = 1;             break;
-            case 'S': use_control_socket = 1;     break;
-            case 'v': show_header_only = true;    break;
-            case 'q': do_vibrate = 0;             break;
-            case 'p': do_fb = 1;                  break;
-            case 'P': ds.update_progress_ = true; break;
-            case 'R': is_remote_mode = 1;         break;
-            case 'B': do_broadcast = 1;           break;
-            case 'V':                             break; // compatibility no-op
-            case 'h':
-                ShowUsageAndExit(0);
-                break;
-            default:
-                fprintf(stderr, "Invalid option: %c\n", c);
-                ShowUsageAndExit();
-                // clang-format on
-        }
+    int status = ds.ParseCommandlineOptions(argc, argv);
+    if (status != -1) {
+        ShowUsageAndExit(status);
     }
-
-    // TODO: use helper function to convert argv into a string
-    for (int i = 0; i < argc; i++) {
-        ds.args_ += argv[i];
-        if (i < argc - 1) {
-            ds.args_ += " ";
-        }
-    }
-
-    ds.extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    if (!ds.extra_options_.empty()) {
-        // Framework uses a system property to override some command-line args.
-        // Currently, it contains the type of the requested bugreport.
-        if (ds.extra_options_ == "bugreportplus") {
-            // Currently, the dumpstate binder is only used by Shell to update progress.
-            do_start_service = true;
-            ds.update_progress_ = true;
-            do_fb = 0;
-        } else if (ds.extra_options_ == "bugreportremote") {
-            do_vibrate = 0;
-            is_remote_mode = 1;
-            do_fb = 0;
-        } else if (ds.extra_options_ == "bugreportwear") {
-            do_start_service = true;
-            ds.update_progress_ = true;
-            do_zip_file = 1;
-        } else if (ds.extra_options_ == "bugreporttelephony") {
-            telephony_only = true;
-        } else if (ds.extra_options_ == "bugreportwifi") {
-            wifi_only = true;
-            do_zip_file = 1;
-        } else {
-            MYLOGE("Unknown extra option: %s\n", ds.extra_options_.c_str());
-        }
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    }
-
-    ds.notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
-    if (!ds.notification_title.empty()) {
-        // Reset the property
-        android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
-        ds.notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        if (!ds.notification_description.empty()) {
-            // Reset the property
-            android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
-        }
-        MYLOGD("notification (title:  %s, description: %s)\n",
-               ds.notification_title.c_str(), ds.notification_description.c_str());
-    }
-
-    if ((do_zip_file || do_add_date || ds.update_progress_ || do_broadcast) && !use_outfile) {
-        ExitOnInvalidArgs();
-    }
-
-    if (use_control_socket && !do_zip_file) {
-        ExitOnInvalidArgs();
-    }
-
-    if (ds.update_progress_ && !do_broadcast) {
-        ExitOnInvalidArgs();
-    }
-
-    if (is_remote_mode && (ds.update_progress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
+    ds.SetOptionsFromProperties();
+    if (!ds.ValidateOptions()) {
         ExitOnInvalidArgs();
     }
 
@@ -1849,18 +1858,21 @@
         exit(1);
     }
 
-    if (show_header_only) {
+    // TODO: make const reference, but first avoid setting do_zip_file below.
+    Dumpstate::DumpOptions& options = ds.options_;
+    if (options.show_header_only) {
         ds.PrintHeader();
         exit(0);
     }
 
-    /* redirect output if needed */
-    bool is_redirecting = !use_socket && use_outfile;
+    // Redirect output if needed
+    bool is_redirecting = !options.use_socket && !options.use_outfile.empty();
 
     // TODO: temporarily set progress until it's part of the Dumpstate constructor
-    std::string stats_path =
-        is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", dirname(use_outfile))
-                       : "";
+    std::string stats_path = is_redirecting
+                                 ? android::base::StringPrintf("%s/dumpstate-stats.txt",
+                                                               dirname(options.use_outfile.c_str()))
+                                 : "";
     ds.progress_.reset(new Progress(stats_path));
 
     /* gets the sequential id */
@@ -1872,7 +1884,7 @@
 
     register_sig_handler();
 
-    if (do_start_service) {
+    if (options.do_start_service) {
         MYLOGI("Starting 'dumpstate' service\n");
         android::status_t ret;
         if ((ret = android::os::DumpstateService::Start()) != android::OK) {
@@ -1893,23 +1905,24 @@
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
-    if (use_socket) {
+    if (options.use_socket) {
         redirect_to_socket(stdout, "dumpstate");
     }
 
-    if (use_control_socket) {
+    if (options.use_control_socket) {
         MYLOGD("Opening control socket\n");
         ds.control_socket_fd_ = open_socket("dumpstate");
         ds.update_progress_ = 1;
     }
 
     if (is_redirecting) {
-        ds.bugreport_dir_ = dirname(use_outfile);
+        ds.bugreport_dir_ = dirname(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_ = android::base::StringPrintf("%s-%s-%s", basename(use_outfile),
-                                                    device_name.c_str(), build_id.c_str());
-        if (do_add_date) {
+        ds.base_name_ =
+            android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()),
+                                        device_name.c_str(), build_id.c_str());
+        if (options.do_add_date) {
             char date[80];
             strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
             ds.name_ = date;
@@ -1917,13 +1930,13 @@
             ds.name_ = "undated";
         }
 
-        if (telephony_only) {
+        if (options.telephony_only) {
             ds.base_name_ += "-telephony";
-        } else if (wifi_only) {
+        } else if (options.wifi_only) {
             ds.base_name_ += "-wifi";
         }
 
-        if (do_fb) {
+        if (options.do_fb) {
             ds.screenshot_path_ = ds.GetPath(".png");
         }
         ds.tmp_path_ = ds.GetPath(".tmp");
@@ -1939,14 +1952,14 @@
             ds.bugreport_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());
 
-        if (do_zip_file) {
+        if (options.do_zip_file) {
             ds.path_ = ds.GetPath(".zip");
             MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
             create_parent_dirs(ds.path_.c_str());
             ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
             if (ds.zip_file == nullptr) {
                 MYLOGE("fopen(%s, 'wb'): %s\n", ds.path_.c_str(), strerror(errno));
-                do_zip_file = 0;
+                options.do_zip_file = false;
             } else {
                 ds.zip_writer_.reset(new ZipWriter(ds.zip_file.get()));
             }
@@ -1954,7 +1967,7 @@
         }
 
         if (ds.update_progress_) {
-            if (do_broadcast) {
+            if (options.do_broadcast) {
                 // clang-format off
 
                 std::vector<std::string> am_args = {
@@ -1967,7 +1980,7 @@
                 // clang-format on
                 SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
             }
-            if (use_control_socket) {
+            if (options.use_control_socket) {
                 dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
             }
         }
@@ -1980,11 +1993,11 @@
         fclose(cmdline);
     }
 
-    if (do_vibrate) {
+    if (options.do_vibrate) {
         Vibrate(150);
     }
 
-    if (do_fb && ds.do_early_screenshot_) {
+    if (options.do_fb && ds.do_early_screenshot_) {
         if (ds.screenshot_path_.empty()) {
             // should not have happened
             MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
@@ -1994,13 +2007,15 @@
         }
     }
 
-    if (do_zip_file) {
+    if (options.do_zip_file) {
         if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) {
             MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(),
                    strerror(errno));
         }
     }
 
+    int dup_stdout_fd;
+    int dup_stderr_fd;
     if (is_redirecting) {
         TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
         redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
@@ -2027,10 +2042,10 @@
     // duration is logged into MYLOG instead.
     ds.PrintHeader();
 
-    if (telephony_only) {
+    if (options.telephony_only) {
         DumpstateTelephonyOnly();
         ds.DumpstateBoard();
-    } else if (wifi_only) {
+    } else if (options.wifi_only) {
         DumpstateWifiOnly();
     } else {
         // Dumps systrace right away, otherwise it will be filled with unnecessary events.
@@ -2086,12 +2101,11 @@
     }
 
     /* rename or zip the (now complete) .tmp file to its final location */
-    if (use_outfile) {
-
+    if (!options.use_outfile.empty()) {
         /* check if user changed the suffix using system properties */
         std::string name = android::base::GetProperty(
             android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
-        bool change_suffix= false;
+        bool change_suffix = false;
         if (!name.empty()) {
             /* must whitelist which characters are allowed, otherwise it could cross directories */
             std::regex valid_regex("^[-_a-zA-Z0-9]+$");
@@ -2116,7 +2130,7 @@
         }
 
         bool do_text_file = true;
-        if (do_zip_file) {
+        if (options.do_zip_file) {
             if (!ds.FinishZipFile()) {
                 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
                 do_text_file = true;
@@ -2145,7 +2159,7 @@
                 ds.path_.clear();
             }
         }
-        if (use_control_socket) {
+        if (options.use_control_socket) {
             if (do_text_file) {
                 dprintf(ds.control_socket_fd_,
                         "FAIL:could not create zip file, check %s "
@@ -2158,7 +2172,7 @@
     }
 
     /* vibrate a few but shortly times to let user know it's finished */
-    if (do_vibrate) {
+    if (options.do_vibrate) {
         for (int i = 0; i < 3; i++) {
             Vibrate(75);
             usleep((75 + 50) * 1000);
@@ -2166,7 +2180,7 @@
     }
 
     /* tell activity manager we're done */
-    if (do_broadcast) {
+    if (options.do_broadcast) {
         if (!ds.path_.empty()) {
             MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
             // clang-format off
@@ -2180,7 +2194,7 @@
                  "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
             };
             // clang-format on
-            if (do_fb) {
+            if (options.do_fb) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.SCREENSHOT");
                 am_args.push_back(ds.screenshot_path_);
@@ -2195,7 +2209,7 @@
                     am_args.push_back(ds.notification_description);
                 }
             }
-            if (is_remote_mode) {
+            if (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.path_));
@@ -2218,7 +2232,7 @@
         TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
     }
 
-    if (use_control_socket && ds.control_socket_fd_ != -1) {
+    if (options.use_control_socket && ds.control_socket_fd_ != -1) {
         MYLOGD("Closing control socket\n");
         close(ds.control_socket_fd_);
     }
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index b220013..389cc2e 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -290,14 +290,51 @@
     /* Returns true if the current version supports priority dump feature. */
     bool CurrentVersionSupportsPriorityDumps() const;
 
-    // TODO: initialize fields on constructor
+    // TODO: revisit the return values later.
+    /*
+     * Parses commandline arguments and sets runtime options accordingly.
+     *
+     * Returns 0 or positive number if the caller should exit with returned value as
+     * exit code, or returns -1 if caller should proceed with execution.
+     */
+    int ParseCommandlineOptions(int argc, char* argv[]);
 
+    /* Sets runtime options from the system properties. */
+    void SetOptionsFromProperties();
+
+    /* Returns true if the options set so far are consistent. */
+    bool ValidateOptions();
+
+    // TODO: add update_progress_ & other options from DumpState.
+    /*
+     * Structure to hold options that determine the behavior of dumpstate.
+     */
+    struct DumpOptions {
+        bool do_add_date = false;
+        bool do_zip_file = false;
+        bool do_vibrate = true;
+        bool use_socket = false;
+        bool use_control_socket = false;
+        bool do_fb = false;
+        bool do_broadcast = false;
+        bool is_remote_mode = false;
+        bool show_header_only = false;
+        bool do_start_service = false;
+        bool telephony_only = false;
+        bool wifi_only = false;
+        std::string use_outfile;
+    };
+
+    // TODO: initialize fields on constructor
     // dumpstate id - unique after each device reboot.
     uint32_t id_;
 
     // dumpstate pid
     pid_t pid_;
 
+    // Runtime options.
+    DumpOptions options_;
+
     // Whether progress updates should be published.
     bool update_progress_ = false;
 
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 838b385..c57535a 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -54,6 +54,8 @@
 using ::testing::internal::GetCapturedStderr;
 using ::testing::internal::GetCapturedStdout;
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 class DumpstateListenerMock : public IDumpstateListener {
   public:
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
@@ -144,6 +146,7 @@
         ds.progress_.reset(new Progress());
         ds.update_progress_ = false;
         ds.update_progress_threshold_ = 0;
+        ds.options_ = Dumpstate::DumpOptions();
     }
 
     // Runs a command and capture `stdout` and `stderr`.
@@ -201,6 +204,157 @@
     Dumpstate& ds = Dumpstate::GetInstance();
 };
 
+TEST_F(DumpstateTest, ParseCommandlineOptionsNone) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate")
+    };
+    // clang-format on
+
+    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
+    EXPECT_EQ(-1, ret);
+    EXPECT_FALSE(ds.options_.do_add_date);
+    EXPECT_FALSE(ds.options_.do_zip_file);
+    EXPECT_EQ("", ds.options_.use_outfile);
+    EXPECT_FALSE(ds.options_.use_socket);
+    EXPECT_FALSE(ds.options_.use_control_socket);
+    EXPECT_FALSE(ds.options_.show_header_only);
+    EXPECT_TRUE(ds.options_.do_vibrate);
+    EXPECT_FALSE(ds.options_.do_fb);
+    EXPECT_FALSE(ds.update_progress_);
+    EXPECT_FALSE(ds.options_.is_remote_mode);
+    EXPECT_FALSE(ds.options_.do_broadcast);
+}
+
+TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) {
+    // clang-format off
+    char* argv[] = {
+        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"),
+
+    };
+    // clang-format on
+    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
+    EXPECT_EQ(-1, ret);
+    EXPECT_TRUE(ds.options_.do_add_date);
+    EXPECT_TRUE(ds.options_.do_zip_file);
+    // TODO: Maybe we should trim the filename
+    EXPECT_EQ(" abc", std::string(ds.options_.use_outfile));
+    EXPECT_TRUE(ds.options_.use_socket);
+    EXPECT_TRUE(ds.options_.use_control_socket);
+
+    // Other options retain default values
+    EXPECT_FALSE(ds.options_.show_header_only);
+    EXPECT_TRUE(ds.options_.do_vibrate);
+    EXPECT_FALSE(ds.options_.do_fb);
+    EXPECT_FALSE(ds.update_progress_);
+    EXPECT_FALSE(ds.options_.is_remote_mode);
+    EXPECT_FALSE(ds.options_.do_broadcast);
+}
+
+TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-v"),
+        const_cast<char*>("-q"),
+        const_cast<char*>("-p"),
+        const_cast<char*>("-P"),
+        const_cast<char*>("-R"),
+        const_cast<char*>("-B"),
+    };
+    // clang-format on
+    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
+    EXPECT_EQ(-1, ret);
+    EXPECT_TRUE(ds.options_.show_header_only);
+    EXPECT_FALSE(ds.options_.do_vibrate);
+    EXPECT_TRUE(ds.options_.do_fb);
+    EXPECT_TRUE(ds.update_progress_);
+    EXPECT_TRUE(ds.options_.is_remote_mode);
+    EXPECT_TRUE(ds.options_.do_broadcast);
+
+    // Other options retain default values
+    EXPECT_FALSE(ds.options_.do_add_date);
+    EXPECT_FALSE(ds.options_.do_zip_file);
+    EXPECT_EQ("", ds.options_.use_outfile);
+    EXPECT_FALSE(ds.options_.use_socket);
+    EXPECT_FALSE(ds.options_.use_control_socket);
+}
+
+TEST_F(DumpstateTest, ParseCommandlineOptionsHelp) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-h")
+    };
+    // clang-format on
+    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
+
+    // -h is for help. Caller exit with code = 0 after printing usage, so expect return = 0.
+    EXPECT_EQ(0, ret);
+}
+
+TEST_F(DumpstateTest, ParseCommandlineOptionsUnknown) {
+    // clang-format off
+    char* argv[] = {
+        const_cast<char*>("dumpstate"),
+        const_cast<char*>("-u")  // unknown flag
+    };
+    // clang-format on
+    int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv);
+
+    // -u is unknown. Caller exit with code = 1 to show execution failure, after printing usage,
+    // so expect return = 1.
+    EXPECT_EQ(1, ret);
+}
+
+TEST_F(DumpstateTest, ValidateOptionsNeedOutfile1) {
+    ds.options_.do_zip_file = true;
+    EXPECT_FALSE(ds.ValidateOptions());
+    ds.options_.use_outfile = "a/b/c";
+    EXPECT_TRUE(ds.ValidateOptions());
+}
+
+TEST_F(DumpstateTest, ValidateOptionsNeedOutfile2) {
+    ds.options_.do_broadcast = true;
+    EXPECT_FALSE(ds.ValidateOptions());
+    ds.options_.use_outfile = "a/b/c";
+    EXPECT_TRUE(ds.ValidateOptions());
+}
+
+TEST_F(DumpstateTest, ValidateOptionsNeedZipfile) {
+    ds.options_.use_control_socket = true;
+    EXPECT_FALSE(ds.ValidateOptions());
+
+    ds.options_.do_zip_file = true;
+    ds.options_.use_outfile = "a/b/c";  // do_zip_file needs outfile
+    EXPECT_TRUE(ds.ValidateOptions());
+}
+
+TEST_F(DumpstateTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
+    ds.update_progress_ = true;
+    ds.options_.use_outfile = "a/b/c";  // update_progress_ needs outfile
+    EXPECT_FALSE(ds.ValidateOptions());
+
+    ds.options_.do_broadcast = true;
+    EXPECT_TRUE(ds.ValidateOptions());
+}
+
+TEST_F(DumpstateTest, ValidateOptionsRemoteMode) {
+    ds.options_.is_remote_mode = true;
+    EXPECT_FALSE(ds.ValidateOptions());
+
+    ds.options_.do_broadcast = true;
+    ds.options_.do_zip_file = true;
+    ds.options_.do_add_date = true;
+    ds.options_.use_outfile = "a/b/c";  // do_broadcast needs outfile
+    EXPECT_TRUE(ds.ValidateOptions());
+}
+
 TEST_F(DumpstateTest, RunCommandNoArgs) {
     EXPECT_EQ(-1, RunCommand("", {}));
 }
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
new file mode 100644
index 0000000..1ba7cff
--- /dev/null
+++ b/cmds/dumpsys/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+felipeal@google.com
+nandana@google.com
+jsharkey@android.com
+enh@google.com
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index a9d5055..e318a7f 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -136,7 +136,7 @@
     // Something really bad has happened, and we're not going to even
     // try returning rich error data.
     if (mException == EX_TRANSACTION_FAILED) {
-        return mErrorCode;
+        return mErrorCode == OK ? FAILED_TRANSACTION : mErrorCode;
     }
 
     status_t status = parcel->writeInt32(mException);
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 3f3c4fa..5461b4f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -25,6 +25,7 @@
 
     srcs: [
         "ibinder.cpp",
+        "ibinder_jni.cpp",
         "parcel.cpp",
         "process.cpp",
         "status.cpp",
@@ -32,6 +33,7 @@
     ],
 
     shared_libs: [
+        "libandroid_runtime",
         "libbase",
         "libbinder",
         "libutils",
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
new file mode 100644
index 0000000..baea2e8
--- /dev/null
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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/binder_ibinder_jni.h>
+#include "ibinder_internal.h"
+
+#include <android_util_Binder.h>
+
+using ::android::IBinder;
+using ::android::ibinderForJavaObject;
+using ::android::javaObjectForIBinder;
+using ::android::sp;
+
+AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
+    sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
+
+    sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
+    AIBinder_incStrong(cbinder.get());
+
+    return cbinder.get();
+}
+
+jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) {
+    if (binder == nullptr) {
+        return nullptr;
+    }
+
+    return javaObjectForIBinder(env, binder->getBinder());
+}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 871335d..f237e69 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -33,6 +33,7 @@
 #include <android/binder_status.h>
 
 __BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
 
 // Also see TF_* in kernel's binder.h
 typedef uint32_t binder_flags_t;
@@ -154,7 +155,8 @@
  */
 __attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
         const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
-        AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);
+        AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact)
+        __INTRODUCED_IN(29);
 
 /**
  * Creates a new binder object of the appropriate class.
@@ -173,12 +175,13 @@
  * these two objects are actually equal using the AIBinder pointer alone (which they should be able
  * to do). Also see the suggested memory ownership model suggested above.
  */
-__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args);
+__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
+        __INTRODUCED_IN(29);
 
 /**
  * If this is hosted in a process other than the current one.
  */
-bool AIBinder_isRemote(const AIBinder* binder);
+bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * If this binder is known to be alive. This will not send a transaction to a remote process and
@@ -187,14 +190,14 @@
  * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
  * based on the results of bookkeeping or other transactions made internally.
  */
-bool AIBinder_isAlive(const AIBinder* binder);
+bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Built-in transaction for all binder objects. This sends a transaction which will immediately
  * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
  * sanity check.
  */
-binder_status_t AIBinder_ping(AIBinder* binder);
+binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Registers for notifications that the associated binder is dead. The same death recipient may be
@@ -206,7 +209,7 @@
  * identification and holding user data.
  */
 binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
-                                     void* cookie);
+                                     void* cookie) __INTRODUCED_IN(29);
 
 /**
  * Stops registration for the associated binder dying. Does not delete the recipient. This function
@@ -214,22 +217,22 @@
  * returns STATUS_NAME_NOT_FOUND.
  */
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
-                                       void* cookie);
+                                       void* cookie) __INTRODUCED_IN(29);
 
 /**
  * This can only be called if a strong reference to this object already exists in process.
  */
-void AIBinder_incStrong(AIBinder* binder);
+void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * This will delete the object and call onDestroy once the refcount reaches zero.
  */
-void AIBinder_decStrong(AIBinder* binder);
+void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * For debugging only!
  */
-int32_t AIBinder_debugGetRefCount(AIBinder* binder);
+int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * This sets the class of an AIBinder object. This checks to make sure the remote object is of
@@ -240,18 +243,18 @@
  * This returns true if the class association succeeds. If it fails, no change is made to the
  * binder object.
  */
-bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz);
+bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
 
 /**
  * Returns the class that this binder was constructed with or associated with.
  */
-const AIBinder_Class* AIBinder_getClass(AIBinder* binder);
+const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
  * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
  */
-void* AIBinder_getUserData(AIBinder* binder);
+void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * A transaction is a series of calls to these functions which looks this
@@ -274,7 +277,7 @@
  * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
  * deleted with AParcel_delete.
  */
-binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in);
+binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
 
 /**
  * Transact using a parcel created from AIBinder_prepareTransaction. This actually communicates with
@@ -289,42 +292,45 @@
  * and must be released with AParcel_delete when finished reading.
  */
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
-                                  AParcel** out, binder_flags_t flags);
+                                  AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
 
 /**
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
  */
-__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder);
+__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
+        __INTRODUCED_IN(29);
 
 /**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
  */
-void AIBinder_Weak_delete(AIBinder_Weak* weakBinder);
+void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
 
 /**
  * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
  * nullptr.
  */
-__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder);
+__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
+        __INTRODUCED_IN(29);
 
 /**
  * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
  */
-typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie);
+typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
 
 /**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
  */
 __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
-        AIBinder_DeathRecipient_onBinderDied onBinderDied);
+        AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
 
 /**
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
  */
-void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient);
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
new file mode 100644
index 0000000..81fb3c5
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_ibinder_jni.h
+ * @brief Conversions between AIBinder and android.os.IBinder
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+
+#include <jni.h>
+
+__BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+
+/**
+ * Converts an android.os.IBinder object into an AIBinder* object.
+ *
+ * If either env or the binder is null, null is returned. If this binder object was originally an
+ * AIBinder object, the original object is returned. The returned object has one refcount
+ * associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ */
+__attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
+        __INTRODUCED_IN(29);
+
+/**
+ * Converts an AIBinder* object into an android.os.IBinder object.
+ *
+ * If either env or the binder is null, null is returned. If this binder object was originally an
+ * IBinder object, the original java object will be returned.
+ */
+__attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
+        __INTRODUCED_IN(29);
+
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+__END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 271810a..a3800da 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -34,6 +34,7 @@
 typedef struct AIBinder AIBinder;
 
 __BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
 
 /**
  * This object represents a package of data that can be sent between processes. When transacting, an
@@ -47,129 +48,140 @@
 /**
  * Cleans up a parcel.
  */
-void AParcel_delete(AParcel* parcel);
+void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
 
 /**
  * Writes an AIBinder to the next location in a non-null parcel. Can be null.
  */
-binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder);
+binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
 
 /**
  * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
  * non-null. One strong ref-count of ownership is passed to the caller of this function.
  */
-binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder);
+binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
+        __INTRODUCED_IN(29);
 
 /**
  * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
  * ref-count of ownership is passed to the caller of this function.
  */
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder);
+binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
+        __INTRODUCED_IN(29);
 
 /**
  * Writes an AStatus object to the next location in a non-null parcel.
+ *
+ * If the status is considered to be a low-level status and has no additional information other
+ * than a binder_status_t (for instance, if it is created with AStatus_fromStatus), then that
+ * status will be returned from this method and nothing will be written to the parcel. If either
+ * this happens or if writing the status object itself fails, the return value from this function
+ * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
  */
-binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status);
+binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
+        __INTRODUCED_IN(29);
 
 /**
  * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
  * of this function.
  */
-binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status);
+binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
+        __INTRODUCED_IN(29);
 
 // @START
 /**
  * Writes int32_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value);
+binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint32_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value);
+binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int64_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value);
+binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes uint64_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value);
+binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes float value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeFloat(AParcel* parcel, float value);
+binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
 
 /**
  * Writes double value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeDouble(AParcel* parcel, double value);
+binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
 
 /**
  * Writes bool value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeBool(AParcel* parcel, bool value);
+binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
 
 /**
  * Writes char16_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value);
+binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
 
 /**
  * Writes int8_t value to the next location in a non-null parcel.
  */
-binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value);
+binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int32_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value);
+binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint32_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value);
+binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int64_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value);
+binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into uint64_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value);
+binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into float value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readFloat(const AParcel* parcel, float* value);
+binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into double value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readDouble(const AParcel* parcel, double* value);
+binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into bool value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readBool(const AParcel* parcel, bool* value);
+binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into char16_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value);
+binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
 
 /**
  * Reads into int8_t value from the next location in a non-null parcel.
  */
-binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value);
+binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
 
 // @END
 
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 1a6a6f0..2d8b7fa 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -30,6 +30,7 @@
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
+#if __ANDROID_API__ >= __ANDROID_API_Q__
 
 enum {
     STATUS_OK = 0,
@@ -102,19 +103,19 @@
 /**
  * New status which is considered a success.
  */
-__attribute__((warn_unused_result)) AStatus* AStatus_newOk();
+__attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
 
 /**
  * New status with exception code.
  */
-__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(
-        binder_exception_t exception);
+__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
+        __INTRODUCED_IN(29);
 
 /**
  * New status with exception code and message.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
-        binder_exception_t exception, const char* message);
+        binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
 
 /**
  * New status with a service speciic error.
@@ -122,7 +123,7 @@
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
-        int32_t serviceSpecific);
+        int32_t serviceSpecific) __INTRODUCED_IN(29);
 
 /**
  * New status with a service specific error and message.
@@ -130,25 +131,26 @@
  * This is considered to be EX_TRANSACTION_FAILED with extra information.
  */
 __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
-        int32_t serviceSpecific, const char* message);
+        int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
 
 /**
  * New status with binder_status_t. This is typically for low level failures when a binder_status_t
  * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
  * an AStatus instance.
  */
-__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status);
+__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
+        __INTRODUCED_IN(29);
 
 /**
  * Whether this object represents a successful transaction. If this function returns true, then
  * AStatus_getExceptionCode will return EX_NONE.
  */
-bool AStatus_isOk(const AStatus* status);
+bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * The exception that this status object represents.
  */
-binder_exception_t AStatus_getExceptionCode(const AStatus* status);
+binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * The service specific error if this object represents one. This function will only ever return a
@@ -156,7 +158,7 @@
  * 0, the status object may still represent a different exception or status. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  */
-int32_t AStatus_getServiceSpecificError(const AStatus* status);
+int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * The status if this object represents one. This function will only ever return a non-zero result
@@ -164,7 +166,7 @@
  * object may represent a different exception or a service specific error. To find out if this
  * transaction as a whole is okay, use AStatus_isOk instead.
  */
-binder_status_t AStatus_getStatus(const AStatus* status);
+binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * If there is a message associated with this status, this will return that message. If there is no
@@ -172,13 +174,14 @@
  *
  * The returned string has the lifetime of the status object passed into this function.
  */
-const char* AStatus_getMessage(const AStatus* status);
+const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
 
 /**
  * Deletes memory associated with the status instance.
  */
-void AStatus_delete(AStatus* status);
+void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 14683b9..4f486c9 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -6,6 +6,7 @@
     AIBinder_DeathRecipient_new;
     AIBinder_debugGetRefCount;
     AIBinder_decStrong;
+    AIBinder_fromJavaBinder;
     AIBinder_getClass;
     AIBinder_getUserData;
     AIBinder_incStrong;
@@ -15,6 +16,7 @@
     AIBinder_new;
     AIBinder_ping;
     AIBinder_prepareTransaction;
+    AIBinder_toJavaBinder;
     AIBinder_transact;
     AIBinder_unlinkToDeath;
     AIBinder_Weak_delete;
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 85ee755..bbd3e5d 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -66,7 +66,7 @@
         header += "/**\n"
         header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
         header += " */\n"
-        header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value);\n\n"
+        header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
         source += "    status_t status = parcel->get()->write" + pretty + "(value);\n"
         source += "    return PruneStatusT(status);\n"
@@ -76,7 +76,7 @@
         header += "/**\n"
         header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
         header += " */\n"
-        header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value);\n\n"
+        header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
         source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
         source += "    status_t status = parcel->get()->read" + pretty + "(value);\n"
         source += "    return PruneStatusT(status);\n"
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 132144b..1f74e43 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -6,6 +6,7 @@
 echo "  global:"
 {
     grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h;
+    grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h;
     grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
     grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
 } | sort | uniq | awk '{ print "    " $0 ";"; }'
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index 549e4b3..e0ae469 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -71,8 +71,6 @@
 }
 
 binder_status_t PruneStatusT(status_t status) {
-    if (status > 0) return status;
-
     switch (status) {
         case ::android::OK:
             return STATUS_OK;
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index d242138..8e40a01 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -44,6 +44,7 @@
     name: "test_libbinder_ndk_test_defaults",
     defaults: ["test_libbinder_ndk_defaults"],
     shared_libs: [
+        "libandroid_runtime",
         "libbase",
         "libbinder",
         "libutils",
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index c07462e..3fc096a 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/logging.h>
+#include <android/binder_ibinder_jni.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <gtest/gtest.h>
@@ -102,6 +103,11 @@
     AIBinder_decStrong(binderB);
 }
 
+TEST(NdkBinder, ToFromJavaNullptr) {
+    EXPECT_EQ(nullptr, AIBinder_toJavaBinder(nullptr, nullptr));
+    EXPECT_EQ(nullptr, AIBinder_fromJavaBinder(nullptr, nullptr));
+}
+
 TEST(NdkBinder, ABpBinderRefCount) {
     AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
     AIBinder_Weak* wBinder = AIBinder_Weak_new(binder);
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 56bc35e..fdbd969 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -1165,27 +1165,28 @@
         result = EnumeratePhysicalDevices(instance, &device_count, nullptr);
         if (result < 0)
             return result;
+
         if (!pPhysicalDeviceGroupProperties) {
             *pPhysicalDeviceGroupCount = device_count;
             return result;
         }
 
-        device_count = std::min(device_count, *pPhysicalDeviceGroupCount);
         if (!device_count) {
             *pPhysicalDeviceGroupCount = 0;
             return result;
         }
+        device_count = std::min(device_count, *pPhysicalDeviceGroupCount);
+        if (!device_count)
+            return VK_INCOMPLETE;
 
         android::Vector<VkPhysicalDevice> devices;
         devices.resize(device_count);
-
+        *pPhysicalDeviceGroupCount = device_count;
         result = EnumeratePhysicalDevices(instance, &device_count,
                                           devices.editArray());
         if (result < 0)
             return result;
 
-        devices.resize(device_count);
-        *pPhysicalDeviceGroupCount = device_count;
         for (uint32_t i = 0; i < device_count; ++i) {
             pPhysicalDeviceGroupProperties[i].physicalDeviceCount = 1;
             pPhysicalDeviceGroupProperties[i].physicalDevices[0] = devices[i];