Merge changes from topic "CowXorOp"

* changes:
  libsnapshot: Don't PrepMergeOps on resume
  snapuserd: Add support for Xor ops in snapuserd
  snapuserd: Rename Read Ahead Iterator
  snapuserd: Add XorSink
  libsnapshot: Clone worker readers from snapuserd
  libsnapshot: Add support for Xor ops in Cow Format
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 360ea95..e20e8d9 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -93,8 +93,18 @@
     errx(1, "process %d is a zombie", pid);
   }
 
-  if (kill(pid, 0) != 0) {
-    err(1, "cannot send signal to process %d", pid);
+  // Send a signal to the main thread pid, not a side thread. The signal
+  // handler always sets the crashing tid to the main thread pid when sent this
+  // signal. This is to avoid a problem where the signal is sent to a process,
+  // but happens on a side thread and the intercept mismatches since it
+  // is looking for the main thread pid, not the tid of this random thread.
+  // See b/194346289 for extra details.
+  if (kill(proc_info.pid, 0) != 0) {
+    if (pid == proc_info.pid) {
+      err(1, "cannot send signal to process %d", pid);
+    } else {
+      err(1, "cannot send signal to main thread %d (requested thread %d)", proc_info.pid, pid);
+    }
   }
 
   unique_fd piperead, pipewrite;
@@ -103,9 +113,13 @@
   }
 
   std::thread redirect_thread = spawn_redirect_thread(std::move(piperead));
-  if (!debuggerd_trigger_dump(pid, dump_type, 0, std::move(pipewrite))) {
+  if (!debuggerd_trigger_dump(proc_info.pid, dump_type, 0, std::move(pipewrite))) {
     redirect_thread.join();
-    errx(1, "failed to dump process %d", pid);
+    if (pid == proc_info.pid) {
+      errx(1, "failed to dump process %d", pid);
+    } else {
+      errx(1, "failed to dump main thread %d (requested thread %d)", proc_info.pid, pid);
+    }
   }
 
   redirect_thread.join();
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index abda071..f24c4fc 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1825,3 +1825,29 @@
   ASSERT_TRUE(android::base::ReadFdToString(output_fd, &output));
   ASSERT_EQ("foo", output);
 }
+
+// Verify that when an intercept is present for the main thread, and the signal
+// is received on a different thread, the intercept still works.
+TEST_F(CrasherTest, intercept_for_main_thread_signal_on_side_thread) {
+  StartProcess([]() {
+    std::thread thread([]() {
+      // Raise the signal on the side thread.
+      raise_debugger_signal(kDebuggerdNativeBacktrace);
+    });
+    thread.join();
+    _exit(0);
+  });
+
+  unique_fd output_fd;
+  StartIntercept(&output_fd, kDebuggerdNativeBacktrace);
+  FinishCrasher();
+  AssertDeath(0);
+
+  int intercept_result;
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 375dbed..35be2bf 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -155,18 +155,14 @@
  * could allocate memory or hold a lock.
  */
 static void log_signal_summary(const siginfo_t* info) {
-  char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
-  if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
-    strcpy(thread_name, "<name unknown>");
-  } else {
-    // short names are null terminated by prctl, but the man page
-    // implies that 16 byte names are not.
-    thread_name[MAX_TASK_NAME_LEN] = 0;
+  char main_thread_name[MAX_TASK_NAME_LEN + 1];
+  if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
+    strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
   }
 
   if (info->si_signo == BIONIC_SIGNAL_DEBUGGER) {
-    async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
-                          thread_name);
+    async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for pid %d (%s)", __getpid(),
+                          main_thread_name);
     return;
   }
 
@@ -181,9 +177,13 @@
     get_signal_sender(sender_desc, sizeof(sender_desc), info);
   }
 
-  char main_thread_name[MAX_TASK_NAME_LEN + 1];
-  if (!get_main_thread_name(main_thread_name, sizeof(main_thread_name))) {
-    strncpy(main_thread_name, "<unknown>", sizeof(main_thread_name));
+  char thread_name[MAX_TASK_NAME_LEN + 1];  // one more for termination
+  if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+    strcpy(thread_name, "<name unknown>");
+  } else {
+    // short names are null terminated by prctl, but the man page
+    // implies that 16 byte names are not.
+    thread_name[MAX_TASK_NAME_LEN] = 0;
   }
 
   async_safe_format_log(ANDROID_LOG_FATAL, "libc",
@@ -532,8 +532,13 @@
 
   log_signal_summary(info);
 
+  // If we got here due to the signal BIONIC_SIGNAL_DEBUGGER, it's possible
+  // this is not the main thread, which can cause the intercept logic to fail
+  // since the intercept is only looking for the main thread. In this case,
+  // setting crashing_tid to pid instead of the current thread's tid avoids
+  // the problem.
   debugger_thread_info thread_info = {
-      .crashing_tid = __gettid(),
+      .crashing_tid = (signal_number == BIONIC_SIGNAL_DEBUGGER) ? __getpid() : __gettid(),
       .pseudothread_tid = -1,
       .siginfo = info,
       .ucontext = context,
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index d0c89b9..f5ab557 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -413,17 +413,24 @@
     return fstab_result;
 }
 
-// Identify path to fstab file. Lookup is based on pattern
-// fstab.<fstab_suffix>, fstab.<hardware>, fstab.<hardware.platform> in
-// folders /odm/etc, vendor/etc, or /.
+// Return the path to the fstab file.  There may be multiple fstab files; the
+// one that is returned will be the first that exists of fstab.<fstab_suffix>,
+// fstab.<hardware>, and fstab.<hardware.platform>.  The fstab is searched for
+// in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
+// the first stage ramdisk during early boot.  Previously, the first stage
+// ramdisk's copy of the fstab had to be located in the root directory, but now
+// the system/etc directory is supported too and is the preferred location.
 std::string GetFstabPath() {
     for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
         std::string suffix;
 
         if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
 
-        for (const char* prefix :
-             {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab.", "/first_stage_ramdisk/fstab."}) {
+        for (const char* prefix : {// late-boot/post-boot locations
+                                   "/odm/etc/fstab.", "/vendor/etc/fstab.",
+                                   // early boot locations
+                                   "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.",
+                                   "/fstab.", "/first_stage_ramdisk/fstab."}) {
             std::string fstab_path = prefix + suffix;
             if (access(fstab_path.c_str(), F_OK) == 0) {
                 return fstab_path;
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd.rc b/fs_mgr/libsnapshot/snapuserd/snapuserd.rc
index 02fda8d..2750096 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd.rc
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd.rc
@@ -14,3 +14,6 @@
     user root
     group root system
     seclabel u:r:snapuserd:s0
+
+on property:init.svc.snapuserd=stopped
+    setprop snapuserd.ready false
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
index 81e9228..1ea05a3 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
@@ -42,13 +42,15 @@
 using android::base::unique_fd;
 
 bool EnsureSnapuserdStarted() {
-    if (android::base::GetProperty("init.svc.snapuserd", "") == "running") {
-        return true;
+    if (android::base::GetProperty("init.svc.snapuserd", "") != "running") {
+        android::base::SetProperty("ctl.start", "snapuserd");
+        if (!android::base::WaitForProperty("init.svc.snapuserd", "running", 10s)) {
+            LOG(ERROR) << "Timed out waiting for snapuserd to start.";
+            return false;
+        }
     }
-
-    android::base::SetProperty("ctl.start", "snapuserd");
-    if (!android::base::WaitForProperty("init.svc.snapuserd", "running", 10s)) {
-        LOG(ERROR) << "Timed out waiting for snapuserd to start.";
+    if (!android::base::WaitForProperty("snapuserd.ready", "true", 10s)) {
+        LOG(ERROR) << "Timed out waiting for snapuserd to be ready.";
         return false;
     }
     return true;
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
index a29b19b..672c13c 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_server.cpp
@@ -291,6 +291,14 @@
 
     AddWatchedFd(sockfd_, POLLIN);
 
+    // If started in first-stage init, the property service won't be online.
+    if (access("/dev/socket/property_service", F_OK) == 0) {
+        if (!android::base::SetProperty("snapuserd.ready", "true")) {
+            LOG(ERROR) << "Failed to set snapuserd.ready property";
+            return false;
+        }
+    }
+
     LOG(DEBUG) << "Snapuserd server now accepting connections";
     return true;
 }
diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp
index 9c2a7bb..05e00ed 100644
--- a/init/block_dev_initializer.cpp
+++ b/init/block_dev_initializer.cpp
@@ -87,7 +87,13 @@
 
     auto iter = devices->find(name);
     if (iter == devices->end()) {
-        return ListenerAction::kContinue;
+        auto partition_name = DeviceHandler::GetPartitionNameForDevice(uevent.device_name);
+        if (!partition_name.empty()) {
+            iter = devices->find(partition_name);
+        }
+        if (iter == devices->end()) {
+            return ListenerAction::kContinue;
+        }
     }
 
     LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name;
diff --git a/init/devices.cpp b/init/devices.cpp
index 56c6623..d4a3cb9 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -46,6 +46,7 @@
 using android::base::ReadFileToString;
 using android::base::Readlink;
 using android::base::Realpath;
+using android::base::Split;
 using android::base::StartsWith;
 using android::base::StringPrintf;
 using android::base::Trim;
@@ -187,6 +188,36 @@
     }
 }
 
+std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) {
+    static const auto partition_map = [] {
+        std::vector<std::pair<std::string, std::string>> partition_map;
+        auto parser = [&partition_map](const std::string& key, const std::string& value) {
+            if (key != "androidboot.partition_map") {
+                return;
+            }
+            for (const auto& map : Split(value, ";")) {
+                auto map_pieces = Split(map, ",");
+                if (map_pieces.size() != 2) {
+                    LOG(ERROR) << "Expected a comma separated device,partition mapping, but found '"
+                               << map << "'";
+                    continue;
+                }
+                partition_map.emplace_back(map_pieces[0], map_pieces[1]);
+            }
+        };
+        ImportKernelCmdline(parser);
+        ImportBootconfig(parser);
+        return partition_map;
+    }();
+
+    for (const auto& [device, partition] : partition_map) {
+        if (query_device == device) {
+            return partition;
+        }
+    }
+    return {};
+}
+
 // Given a path that may start with a platform device, find the parent platform device by finding a
 // parent directory with a 'subsystem' symlink that points to the platform bus.
 // If it doesn't start with a platform device, return false
@@ -389,6 +420,10 @@
         // If we don't have a partition name but we are a partition on a boot device, create a
         // symlink of /dev/block/by-name/<device_name> for symmetry.
         links.emplace_back("/dev/block/by-name/" + uevent.device_name);
+        auto partition_name = GetPartitionNameForDevice(uevent.device_name);
+        if (!partition_name.empty()) {
+            links.emplace_back("/dev/block/by-name/" + partition_name);
+        }
     }
 
     auto last_slash = uevent.path.rfind('/');
diff --git a/init/devices.h b/init/devices.h
index d70d746..f9f4d79 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -122,6 +122,12 @@
 
     std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
 
+    // `androidboot.partition_map` allows associating a partition name for a raw block device
+    // through a comma separated and semicolon deliminated list. For example,
+    // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to
+    // `userdata`.
+    static std::string GetPartitionNameForDevice(const std::string& device);
+
   private:
     bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
     std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 5ca0967..0734f25 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -43,6 +43,7 @@
 using android::base::GetBoolProperty;
 using android::base::StringPrintf;
 using android::base::unique_fd;
+using android::base::WriteStringToFile;
 
 static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs";
 static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
@@ -202,3 +203,21 @@
 
     return CgroupController(nullptr);
 }
+
+int CgroupMap::ActivateControllers(const std::string& path) const {
+    if (__builtin_available(android 30, *)) {
+        auto controller_count = ACgroupFile_getControllerCount();
+        for (uint32_t i = 0; i < controller_count; ++i) {
+            const ACgroupController* controller = ACgroupFile_getController(i);
+            if (ACgroupController_getFlags(controller) &
+                CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
+                std::string str = std::string("+") + ACgroupController_getName(controller);
+                if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) {
+                    return -errno;
+                }
+            }
+        }
+        return 0;
+    }
+    return -ENOSYS;
+}
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index 427d71b..22d717b 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -62,6 +62,7 @@
 
     static CgroupMap& GetInstance();
     CgroupController FindController(const std::string& name) const;
+    int ActivateControllers(const std::string& path) const;
 
   private:
     bool loaded_ = false;
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index c824376..faf945c 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -416,13 +416,15 @@
     return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
 }
 
-static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup) {
+static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup,
+                                      bool activate_controllers) {
     auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
 
     struct stat cgroup_stat;
     mode_t cgroup_mode = 0750;
     gid_t cgroup_uid = AID_SYSTEM;
     uid_t cgroup_gid = AID_SYSTEM;
+    int ret = 0;
 
     if (stat(cgroup.c_str(), &cgroup_stat) == 1) {
         PLOG(ERROR) << "Failed to get stats for " << cgroup;
@@ -436,6 +438,13 @@
         PLOG(ERROR) << "Failed to make and chown " << uid_path;
         return -errno;
     }
+    if (activate_controllers) {
+        ret = CgroupMap::GetInstance().ActivateControllers(uid_path);
+        if (ret) {
+            LOG(ERROR) << "Failed to activate controllers in " << uid_path;
+            return ret;
+        }
+    }
 
     auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid);
 
@@ -446,7 +455,6 @@
 
     auto uid_pid_procs_file = uid_pid_path + PROCESSGROUP_CGROUP_PROCS_FILE;
 
-    int ret = 0;
     if (!WriteStringToFile(std::to_string(initialPid), uid_pid_procs_file)) {
         ret = -errno;
         PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << uid_pid_procs_file;
@@ -466,14 +474,14 @@
     if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
         CgroupGetControllerPath("memory", &cgroup);
         cgroup += "/apps";
-        int ret = createProcessGroupInternal(uid, initialPid, cgroup);
+        int ret = createProcessGroupInternal(uid, initialPid, cgroup, false);
         if (ret != 0) {
             return ret;
         }
     }
 
     CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cgroup);
-    return createProcessGroupInternal(uid, initialPid, cgroup);
+    return createProcessGroupInternal(uid, initialPid, cgroup, true);
 }
 
 static bool SetProcessGroupValue(int tid, const std::string& attr_name, int64_t value) {