Merge "init: always kill oneshot services' process groups." am: 8fa4d6c382 am: f45bc91373
Change-Id: Ic26dc11fdf9bc4fae50700250fd06ae01d46d856
diff --git a/init/service.cpp b/init/service.cpp
index 574ff52..ad42df7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -42,9 +42,11 @@
#if defined(__ANDROID__)
#include <ApexProperties.sysprop.h>
+#include <android/api-level.h>
#include "mount_namespace.h"
#include "property_service.h"
+#include "selinux.h"
#else
#include "host_init_stubs.h"
#endif
@@ -182,7 +184,7 @@
}
}
-void Service::KillProcessGroup(int signal) {
+void Service::KillProcessGroup(int signal, bool report_oneshot) {
// If we've already seen a successful result from killProcessGroup*(), then we have removed
// the cgroup already and calling these functions a second time will simply result in an error.
// This is true regardless of which signal was sent.
@@ -190,11 +192,20 @@
if (!process_cgroup_empty_) {
LOG(INFO) << "Sending signal " << signal << " to service '" << name_ << "' (pid " << pid_
<< ") process group...";
+ int max_processes = 0;
int r;
if (signal == SIGTERM) {
- r = killProcessGroupOnce(proc_attr_.uid, pid_, signal);
+ r = killProcessGroupOnce(proc_attr_.uid, pid_, signal, &max_processes);
} else {
- r = killProcessGroup(proc_attr_.uid, pid_, signal);
+ r = killProcessGroup(proc_attr_.uid, pid_, signal, &max_processes);
+ }
+
+ if (report_oneshot && max_processes > 0) {
+ LOG(WARNING)
+ << "Killed " << max_processes
+ << " additional processes from a oneshot process group for service '" << name_
+ << "'. This is new behavior, previously child processes would not be killed in "
+ "this case.";
}
if (r == 0) process_cgroup_empty_ = true;
@@ -244,7 +255,16 @@
void Service::Reap(const siginfo_t& siginfo) {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
- KillProcessGroup(SIGKILL);
+ KillProcessGroup(SIGKILL, false);
+ } else {
+ // Legacy behavior from ~2007 until Android R: this else branch did not exist and we did not
+ // kill the process group in this case.
+ if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
+ // The new behavior in Android R is to kill these process groups in all cases. The
+ // 'true' parameter instructions KillProcessGroup() to report a warning message where it
+ // detects a difference in behavior has occurred.
+ KillProcessGroup(SIGKILL, true);
+ }
}
// Remove any socket resources we may have created.
diff --git a/init/service.h b/init/service.h
index 272c9f9..f842b3c 100644
--- a/init/service.h
+++ b/init/service.h
@@ -132,7 +132,7 @@
private:
void NotifyStateChange(const std::string& new_state) const;
void StopOrReset(int how);
- void KillProcessGroup(int signal);
+ void KillProcessGroup(int signal, bool report_oneshot = false);
void SetProcessAttributesAndCaps();
static unsigned long next_start_order_;
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index f73ec2d..0b38b6b 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -47,11 +47,14 @@
// Return 0 and removes the cgroup if there are no longer any processes in it.
// Returns -1 in the case of an error occurring or if there are processes still running
// even after retrying for up to 200ms.
-int killProcessGroup(uid_t uid, int initialPid, int signal);
+// If max_processes is not nullptr, it returns the maximum number of processes seen in the cgroup
+// during the killing process. Note that this can be 0 if all processes from the process group have
+// already been terminated.
+int killProcessGroup(uid_t uid, int initialPid, int signal, int* max_processes = nullptr);
// Returns the same as killProcessGroup(), however it does not retry, which means
// 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 killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_processes = nullptr);
int createProcessGroup(uid_t uid, int initialPid, bool memControl = false);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 7b6dde2..6272664 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -301,7 +301,8 @@
return feof(fd.get()) ? processes : -1;
}
-static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
+static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries,
+ int* max_processes) {
std::string cpuacct_path;
std::string memory_path;
@@ -316,9 +317,16 @@
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+ if (max_processes != nullptr) {
+ *max_processes = 0;
+ }
+
int retry = retries;
int processes;
while ((processes = DoKillProcessGroupOnce(cgroup, uid, initialPid, signal)) > 0) {
+ if (max_processes != nullptr && processes > *max_processes) {
+ *max_processes = processes;
+ }
LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
if (retry > 0) {
std::this_thread::sleep_for(5ms);
@@ -359,12 +367,12 @@
}
}
-int killProcessGroup(uid_t uid, int initialPid, int signal) {
- return KillProcessGroup(uid, initialPid, signal, 40 /*retries*/);
+int killProcessGroup(uid_t uid, int initialPid, int signal, int* max_processes) {
+ return KillProcessGroup(uid, initialPid, signal, 40 /*retries*/, max_processes);
}
-int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
- return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/);
+int killProcessGroupOnce(uid_t uid, int initialPid, int signal, int* max_processes) {
+ return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/, max_processes);
}
int createProcessGroup(uid_t uid, int initialPid, bool memControl) {