Merge "Use android::base::Basename instead of basename"
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d7d2091..2887402 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -2199,7 +2199,7 @@
             }
         }
     }
-    std::unique_ptr<Task> reboot_task = nullptr;
+    std::vector<std::unique_ptr<Task>> tasks;
     std::vector<std::string> args(argv, argv + argc);
     while (!args.empty()) {
         std::string command = next_arg(&args);
@@ -2253,17 +2253,17 @@
         } else if (command == FB_CMD_REBOOT) {
             if (args.size() == 1) {
                 std::string reboot_target = next_arg(&args);
-                reboot_task = std::make_unique<RebootTask>(fp.get(), reboot_target);
+                tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), reboot_target));
             } else if (!fp->skip_reboot) {
-                reboot_task = std::make_unique<RebootTask>(fp.get());
+                tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
             }
             if (!args.empty()) syntax_error("junk after reboot command");
         } else if (command == FB_CMD_REBOOT_BOOTLOADER) {
-            reboot_task = std::make_unique<RebootTask>(fp.get(), "bootloader");
+            tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "bootloader"));
         } else if (command == FB_CMD_REBOOT_RECOVERY) {
-            reboot_task = std::make_unique<RebootTask>(fp.get(), "recovery");
+            tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "recovery"));
         } else if (command == FB_CMD_REBOOT_FASTBOOT) {
-            reboot_task = std::make_unique<RebootTask>(fp.get(), "fastboot");
+            tasks.emplace_back(std::make_unique<RebootTask>(fp.get(), "fastboot"));
         } else if (command == FB_CMD_CONTINUE) {
             fb->Continue();
         } else if (command == FB_CMD_BOOT) {
@@ -2305,12 +2305,11 @@
                 fprintf(stderr,
                         "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
                 fp->skip_secondary = true;
-                do_flashall(fp.get());
-            } else {
-                do_flashall(fp.get());
             }
+            do_flashall(fp.get());
+
             if (!fp->skip_reboot) {
-                reboot_task = std::make_unique<RebootTask>(fp.get());
+                tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
             }
         } else if (command == "update") {
             bool slot_all = (fp->slot_override == "all");
@@ -2324,7 +2323,7 @@
             }
             do_update(filename.c_str(), fp.get());
             if (!fp->skip_reboot) {
-                reboot_task = std::make_unique<RebootTask>(fp.get());
+                tasks.emplace_back(std::make_unique<RebootTask>(fp.get()));
             }
         } else if (command == FB_CMD_SET_ACTIVE) {
             std::string slot = verify_slot(next_arg(&args), false);
@@ -2358,8 +2357,7 @@
             fb->CreatePartition(partition, size);
         } else if (command == FB_CMD_DELETE_PARTITION) {
             std::string partition = next_arg(&args);
-            auto delete_task = std::make_unique<DeleteTask>(fp.get(), partition);
-            fb->DeletePartition(partition);
+            tasks.emplace_back(std::make_unique<DeleteTask>(fp.get(), partition));
         } else if (command == FB_CMD_RESIZE_PARTITION) {
             std::string partition = next_arg(&args);
             std::string size = next_arg(&args);
@@ -2407,15 +2405,14 @@
         }
         std::vector<std::string> partitions = {"userdata", "cache", "metadata"};
         for (const auto& partition : partitions) {
-            std::unique_ptr<WipeTask> wipe_task = std::make_unique<WipeTask>(fp.get(), partition);
-            wipe_task->Run();
+            tasks.emplace_back(std::make_unique<WipeTask>(fp.get(), partition));
         }
     }
     if (fp->wants_set_active) {
         fb->SetActive(next_active);
     }
-    if (reboot_task) {
-        reboot_task->Run();
+    for (auto& task : tasks) {
+        task->Run();
     }
     fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
 
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 3bfa4d5..4202c17 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -252,13 +252,6 @@
     header_libs: [
         "libstorage_literals_headers",
     ],
-    test_suites: [
-        "vts",
-        "device-tests"
-    ],
-    test_options: {
-        min_shipping_api_level: 29,
-    },
     auto_gen_config: true,
     require_root: true,
     compile_multilib: "first",
@@ -267,6 +260,13 @@
 cc_test {
     name: "vts_libsnapshot_test",
     defaults: ["libsnapshot_test_defaults", "libsnapshot_hal_deps"],
+    test_suites: [
+        "vts",
+        "device-tests"
+    ],
+    test_options: {
+        min_shipping_api_level: 30,
+    },
 }
 
 cc_test {
@@ -275,6 +275,13 @@
     cppflags: [
         "-DLIBSNAPSHOT_TEST_VAB_LEGACY",
     ],
+    test_suites: [
+        "device-tests"
+    ],
+    test_options: {
+        // Legacy VAB launched in Android R.
+        min_shipping_api_level: 30,
+    },
 }
 
 cc_test {
@@ -283,6 +290,13 @@
     cppflags: [
         "-DLIBSNAPSHOT_TEST_VABC_LEGACY",
     ],
+    test_suites: [
+        "device-tests"
+    ],
+    test_options: {
+        // Legacy VABC launched in Android S.
+        min_shipping_api_level: 31,
+    },
 }
 
 cc_test {
diff --git a/healthd/healthd.rc b/healthd/healthd.rc
deleted file mode 100644
index 8e2ebb6..0000000
--- a/healthd/healthd.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service healthd /system/bin/healthd
-    class hal
-    critical
-    group root system wakelock
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 9b2d775..48bc0b7 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -36,6 +36,7 @@
 
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
 bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+bool SetUserProfiles(uid_t uid, const std::vector<std::string>& profiles);
 
 __END_DECLS
 
@@ -75,6 +76,11 @@
 // that it only returns 0 in the case that the cgroup exists and it contains no processes.
 int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_processes = nullptr);
 
+// Sends the provided signal to all members of a process group, but does not wait for processes to
+// exit, or for the cgroup to be removed. Callers should also ensure that killProcessGroup is called
+// later to ensure the cgroup is fully removed, otherwise system resources may leak.
+int sendSignalToProcessGroup(uid_t uid, int initialPid, int signal);
+
 int createProcessGroup(uid_t uid, int initialPid, bool memControl = false);
 
 // Set various properties of a process group. For these functions to work, the process group must
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 38eb92f..a021594 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -200,6 +200,11 @@
     return SetProcessProfiles(uid, pid, std::span<const std::string_view>(profiles_));
 }
 
+bool SetUserProfiles(uid_t uid, const std::vector<std::string>& profiles) {
+    return TaskProfiles::GetInstance().SetUserProfiles(uid, std::span<const std::string>(profiles),
+                                                       false);
+}
+
 static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
     return StringPrintf("%s/uid_%d", cgroup, uid);
 }
@@ -537,6 +542,15 @@
     return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
 }
 
+int sendSignalToProcessGroup(uid_t uid, int initialPid, int signal) {
+    std::string hierarchy_root_path;
+    if (CgroupsAvailable()) {
+        CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &hierarchy_root_path);
+    }
+    const char* cgroup = hierarchy_root_path.c_str();
+    return DoKillProcessGroupOnce(cgroup, uid, initialPid, signal);
+}
+
 static int createProcessGroupInternal(uid_t uid, int initialPid, std::string cgroup,
                                       bool activate_controllers) {
     auto uid_path = ConvertUidToPath(cgroup.c_str(), uid);
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4db7372..1731828 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -139,6 +139,17 @@
     return true;
 }
 
+bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const {
+    if (path == nullptr) {
+        return true;
+    }
+
+    const std::string& file_name =
+            controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
+    *path = StringPrintf("%s/uid_%d/%s", controller()->path(), uid, file_name.c_str());
+    return true;
+}
+
 bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const {
     // TODO: add support when kernel supports util_clamp
     LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported";
@@ -225,6 +236,29 @@
     return true;
 }
 
+bool SetAttributeAction::ExecuteForUID(uid_t uid) const {
+    std::string path;
+
+    if (!attribute_->GetPathForUID(uid, &path)) {
+        LOG(ERROR) << "Failed to find cgroup for uid " << uid;
+        return false;
+    }
+
+    if (!WriteStringToFile(value_, path)) {
+        if (access(path.c_str(), F_OK) < 0) {
+            if (optional_) {
+                return true;
+            } else {
+                LOG(ERROR) << "No such cgroup attribute: " << path;
+                return false;
+            }
+        }
+        PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
+        return false;
+    }
+    return true;
+}
+
 SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
     : controller_(c), path_(p) {
     FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
@@ -552,6 +586,16 @@
     return true;
 }
 
+bool TaskProfile::ExecuteForUID(uid_t uid) const {
+    for (const auto& element : elements_) {
+        if (!element->ExecuteForUID(uid)) {
+            LOG(VERBOSE) << "Applying profile action " << element->Name() << " failed";
+            return false;
+        }
+    }
+    return true;
+}
+
 void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
     if (res_cached_) {
         return;
@@ -805,6 +849,24 @@
 }
 
 template <typename T>
+bool TaskProfiles::SetUserProfiles(uid_t uid, std::span<const T> profiles, bool use_fd_cache) {
+    for (const auto& name : profiles) {
+        TaskProfile* profile = GetProfile(name);
+        if (profile != nullptr) {
+            if (use_fd_cache) {
+                profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
+            }
+            if (!profile->ExecuteForUID(uid)) {
+                PLOG(WARNING) << "Failed to apply " << name << " process profile";
+            }
+        } else {
+            PLOG(WARNING) << "Failed to find " << name << "process profile";
+        }
+    }
+    return true;
+}
+
+template <typename T>
 bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles,
                                       bool use_fd_cache) {
     bool success = true;
@@ -857,3 +919,5 @@
                                             bool use_fd_cache);
 template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
                                             bool use_fd_cache);
+template bool TaskProfiles::SetUserProfiles(uid_t uid, std::span<const std::string> profiles,
+                                            bool use_fd_cache);
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 85b3f91..a8ecb87 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -36,6 +36,7 @@
     virtual const CgroupController* controller() const = 0;
     virtual const std::string& file_name() const = 0;
     virtual bool GetPathForTask(int tid, std::string* path) const = 0;
+    virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0;
 };
 
 class ProfileAttribute : public IProfileAttribute {
@@ -53,6 +54,7 @@
     void Reset(const CgroupController& controller, const std::string& file_name) override;
 
     bool GetPathForTask(int tid, std::string* path) const override;
+    bool GetPathForUID(uid_t uid, std::string* path) const override;
 
   private:
     CgroupController controller_;
@@ -72,6 +74,7 @@
     // Default implementations will fail
     virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
     virtual bool ExecuteForTask(int) const { return false; };
+    virtual bool ExecuteForUID(uid_t) const { return false; };
 
     virtual void EnableResourceCaching(ResourceCacheType) {}
     virtual void DropResourceCaching(ResourceCacheType) {}
@@ -116,6 +119,7 @@
     const char* Name() const override { return "SetAttribute"; }
     bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
     bool ExecuteForTask(int tid) const override;
+    bool ExecuteForUID(uid_t uid) const override;
 
   private:
     const IProfileAttribute* attribute_;
@@ -179,6 +183,7 @@
 
     bool ExecuteForProcess(uid_t uid, pid_t pid) const;
     bool ExecuteForTask(int tid) const;
+    bool ExecuteForUID(uid_t uid) const;
     void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
 
@@ -216,6 +221,8 @@
     bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles, bool use_fd_cache);
     template <typename T>
     bool SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache);
+    template <typename T>
+    bool SetUserProfiles(uid_t uid, std::span<const T> profiles, bool use_fd_cache);
 
   private:
     TaskProfiles();
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index c449e95..842189d 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -121,6 +121,10 @@
         return true;
     };
 
+    bool GetPathForUID(uid_t, std::string*) const override {
+        return false;
+    }
+
   private:
     const std::string file_name_;
 };