Merge "Attempt native rollback for frequent crashes before boot completed" into qt-dev
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 552df41..e2a17c5 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -904,12 +904,12 @@
         }
         buf[8] = '\0';
 
-        if (strcmp(kSideloadServiceExitSuccess, buf) == 0 ||
-            strcmp(kSideloadServiceExitFailure, buf) == 0) {
+        if (strcmp(kMinadbdServicesExitSuccess, buf) == 0 ||
+            strcmp(kMinadbdServicesExitFailure, buf) == 0) {
             printf("\rTotal xfer: %.2fx%*s\n",
                    static_cast<double>(xfer) / (sb.st_size ? sb.st_size : 1),
                    static_cast<int>(strlen(filename) + 10), "");
-            if (strcmp(kSideloadServiceExitFailure, buf) == 0) {
+            if (strcmp(kMinadbdServicesExitFailure, buf) == 0) {
                 return 1;
             }
             return 0;
@@ -961,6 +961,33 @@
     }
 }
 
+static int adb_wipe_devices() {
+    auto wipe_devices_message_size = strlen(kMinadbdServicesExitSuccess);
+    std::string error;
+    unique_fd fd(adb_connect(
+            android::base::StringPrintf("rescue-wipe:userdata:%zu", wipe_devices_message_size),
+            &error));
+    if (fd < 0) {
+        fprintf(stderr, "adb: wipe device connection failed: %s\n", error.c_str());
+        return 1;
+    }
+
+    std::string message(wipe_devices_message_size, '\0');
+    if (!ReadFdExactly(fd, message.data(), wipe_devices_message_size)) {
+        fprintf(stderr, "adb: failed to read wipe result: %s\n", strerror(errno));
+        return 1;
+    }
+
+    if (message == kMinadbdServicesExitSuccess) {
+        return 0;
+    }
+
+    if (message != kMinadbdServicesExitFailure) {
+        fprintf(stderr, "adb: got unexpected message from rescue wipe %s\n", message.c_str());
+    }
+    return 1;
+}
+
 /**
  * Run ppp in "notty" mode against a resource listed as the first parameter
  * eg:
@@ -1643,6 +1670,7 @@
     } else if (!strcmp(argv[0], "rescue")) {
         // adb rescue getprop <prop>
         // adb rescue install <filename>
+        // adb rescue wipe userdata
         if (argc != 3) error_exit("rescue requires two arguments");
         if (!strcmp(argv[1], "getprop")) {
             return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2]));
@@ -1650,6 +1678,8 @@
             if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) {
                 return 1;
             }
+        } else if (!strcmp(argv[1], "wipe") && !strcmp(argv[2], "userdata")) {
+            return adb_wipe_devices();
         } else {
             error_exit("invalid rescue argument");
         }
diff --git a/adb/services.h b/adb/services.h
index 8f3919b..6fc89d7 100644
--- a/adb/services.h
+++ b/adb/services.h
@@ -23,9 +23,10 @@
 constexpr char kShellServiceArgPty[] = "pty";
 constexpr char kShellServiceArgShellProtocol[] = "v2";
 
-// Special flags sent by minadbd that indicate the end of sideload transfer and install result.
-constexpr char kSideloadServiceExitSuccess[] = "DONEDONE";
-constexpr char kSideloadServiceExitFailure[] = "FAILFAIL";
+// Special flags sent by minadbd. They indicate the end of sideload transfer and the result of
+// installation or wipe.
+constexpr char kMinadbdServicesExitSuccess[] = "DONEDONE";
+constexpr char kMinadbdServicesExitFailure[] = "FAILFAIL";
 
 unique_fd create_service_thread(const char* service_name, std::function<void(unique_fd)> func);
 #endif  // SERVICES_H_
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 70583af..eb4b1b8 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -23,6 +23,9 @@
 
 struct ThreadInfo {
   std::unique_ptr<unwindstack::Regs> registers;
+
+  pid_t uid;
+
   pid_t tid;
   std::string thread_name;
 
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 3196ce8..88c206f 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -343,6 +343,16 @@
   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
 }
 
+TEST_F(TombstoneTest, dump_thread_info_uid) {
+  dump_thread_info(&log_, ThreadInfo{.uid = 1,
+                                     .pid = 2,
+                                     .tid = 3,
+                                     .thread_name = "some_thread",
+                                     .process_name = "some_process"});
+  std::string expected = "pid: 2, tid: 3, name: some_thread  >>> some_process <<<\nuid: 1\n";
+  ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
+}
+
 TEST_F(TombstoneTest, dump_timestamp) {
   setenv("TZ", "UTC", 1);
   tzset();
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index d1726cd..d246722 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -151,6 +151,7 @@
 
   _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", thread_info.pid,
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
+  _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
 }
 
 static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
@@ -615,6 +616,7 @@
 
 void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext) {
+  pid_t uid = getuid();
   pid_t pid = getpid();
   pid_t tid = gettid();
 
@@ -636,6 +638,7 @@
   std::map<pid_t, ThreadInfo> threads;
   threads[gettid()] = ThreadInfo{
       .registers = std::move(regs),
+      .uid = uid,
       .tid = tid,
       .thread_name = thread_name,
       .pid = pid,