xref: /aosp_15_r20/external/libchrome/base/process/kill_posix.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/process/kill.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <errno.h>
8*635a8641SAndroid Build Coastguard Worker #include <signal.h>
9*635a8641SAndroid Build Coastguard Worker #include <sys/types.h>
10*635a8641SAndroid Build Coastguard Worker #include <sys/wait.h>
11*635a8641SAndroid Build Coastguard Worker #include <unistd.h>
12*635a8641SAndroid Build Coastguard Worker 
13*635a8641SAndroid Build Coastguard Worker #include "base/debug/activity_tracker.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/process/process_iterator.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/task_scheduler/post_task.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
21*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
22*635a8641SAndroid Build Coastguard Worker 
23*635a8641SAndroid Build Coastguard Worker namespace base {
24*635a8641SAndroid Build Coastguard Worker 
25*635a8641SAndroid Build Coastguard Worker namespace {
26*635a8641SAndroid Build Coastguard Worker 
GetTerminationStatusImpl(ProcessHandle handle,bool can_block,int * exit_code)27*635a8641SAndroid Build Coastguard Worker TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
28*635a8641SAndroid Build Coastguard Worker                                            bool can_block,
29*635a8641SAndroid Build Coastguard Worker                                            int* exit_code) {
30*635a8641SAndroid Build Coastguard Worker   DCHECK(exit_code);
31*635a8641SAndroid Build Coastguard Worker 
32*635a8641SAndroid Build Coastguard Worker   int status = 0;
33*635a8641SAndroid Build Coastguard Worker   const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
34*635a8641SAndroid Build Coastguard Worker                                             can_block ? 0 : WNOHANG));
35*635a8641SAndroid Build Coastguard Worker   if (result == -1) {
36*635a8641SAndroid Build Coastguard Worker     DPLOG(ERROR) << "waitpid(" << handle << ")";
37*635a8641SAndroid Build Coastguard Worker     *exit_code = 0;
38*635a8641SAndroid Build Coastguard Worker     return TERMINATION_STATUS_NORMAL_TERMINATION;
39*635a8641SAndroid Build Coastguard Worker   } else if (result == 0) {
40*635a8641SAndroid Build Coastguard Worker     // the child hasn't exited yet.
41*635a8641SAndroid Build Coastguard Worker     *exit_code = 0;
42*635a8641SAndroid Build Coastguard Worker     return TERMINATION_STATUS_STILL_RUNNING;
43*635a8641SAndroid Build Coastguard Worker   }
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker   *exit_code = status;
46*635a8641SAndroid Build Coastguard Worker 
47*635a8641SAndroid Build Coastguard Worker   if (WIFSIGNALED(status)) {
48*635a8641SAndroid Build Coastguard Worker     switch (WTERMSIG(status)) {
49*635a8641SAndroid Build Coastguard Worker       case SIGABRT:
50*635a8641SAndroid Build Coastguard Worker       case SIGBUS:
51*635a8641SAndroid Build Coastguard Worker       case SIGFPE:
52*635a8641SAndroid Build Coastguard Worker       case SIGILL:
53*635a8641SAndroid Build Coastguard Worker       case SIGSEGV:
54*635a8641SAndroid Build Coastguard Worker       case SIGTRAP:
55*635a8641SAndroid Build Coastguard Worker       case SIGSYS:
56*635a8641SAndroid Build Coastguard Worker         return TERMINATION_STATUS_PROCESS_CRASHED;
57*635a8641SAndroid Build Coastguard Worker       case SIGKILL:
58*635a8641SAndroid Build Coastguard Worker #if defined(OS_CHROMEOS)
59*635a8641SAndroid Build Coastguard Worker         // On ChromeOS, only way a process gets kill by SIGKILL
60*635a8641SAndroid Build Coastguard Worker         // is by oom-killer.
61*635a8641SAndroid Build Coastguard Worker         return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
62*635a8641SAndroid Build Coastguard Worker #endif
63*635a8641SAndroid Build Coastguard Worker       case SIGINT:
64*635a8641SAndroid Build Coastguard Worker       case SIGTERM:
65*635a8641SAndroid Build Coastguard Worker         return TERMINATION_STATUS_PROCESS_WAS_KILLED;
66*635a8641SAndroid Build Coastguard Worker       default:
67*635a8641SAndroid Build Coastguard Worker         break;
68*635a8641SAndroid Build Coastguard Worker     }
69*635a8641SAndroid Build Coastguard Worker   }
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker   if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
72*635a8641SAndroid Build Coastguard Worker     return TERMINATION_STATUS_ABNORMAL_TERMINATION;
73*635a8641SAndroid Build Coastguard Worker 
74*635a8641SAndroid Build Coastguard Worker   return TERMINATION_STATUS_NORMAL_TERMINATION;
75*635a8641SAndroid Build Coastguard Worker }
76*635a8641SAndroid Build Coastguard Worker 
77*635a8641SAndroid Build Coastguard Worker }  // namespace
78*635a8641SAndroid Build Coastguard Worker 
79*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL_NONSFI)
KillProcessGroup(ProcessHandle process_group_id)80*635a8641SAndroid Build Coastguard Worker bool KillProcessGroup(ProcessHandle process_group_id) {
81*635a8641SAndroid Build Coastguard Worker   bool result = kill(-1 * process_group_id, SIGKILL) == 0;
82*635a8641SAndroid Build Coastguard Worker   if (!result)
83*635a8641SAndroid Build Coastguard Worker     DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
84*635a8641SAndroid Build Coastguard Worker   return result;
85*635a8641SAndroid Build Coastguard Worker }
86*635a8641SAndroid Build Coastguard Worker #endif  // !defined(OS_NACL_NONSFI)
87*635a8641SAndroid Build Coastguard Worker 
GetTerminationStatus(ProcessHandle handle,int * exit_code)88*635a8641SAndroid Build Coastguard Worker TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
89*635a8641SAndroid Build Coastguard Worker   return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
90*635a8641SAndroid Build Coastguard Worker }
91*635a8641SAndroid Build Coastguard Worker 
GetKnownDeadTerminationStatus(ProcessHandle handle,int * exit_code)92*635a8641SAndroid Build Coastguard Worker TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
93*635a8641SAndroid Build Coastguard Worker                                                 int* exit_code) {
94*635a8641SAndroid Build Coastguard Worker   bool result = kill(handle, SIGKILL) == 0;
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker   if (!result)
97*635a8641SAndroid Build Coastguard Worker     DPLOG(ERROR) << "Unable to terminate process " << handle;
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker   return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
100*635a8641SAndroid Build Coastguard Worker }
101*635a8641SAndroid Build Coastguard Worker 
102*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL_NONSFI)
WaitForProcessesToExit(const FilePath::StringType & executable_name,TimeDelta wait,const ProcessFilter * filter)103*635a8641SAndroid Build Coastguard Worker bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
104*635a8641SAndroid Build Coastguard Worker                             TimeDelta wait,
105*635a8641SAndroid Build Coastguard Worker                             const ProcessFilter* filter) {
106*635a8641SAndroid Build Coastguard Worker   bool result = false;
107*635a8641SAndroid Build Coastguard Worker 
108*635a8641SAndroid Build Coastguard Worker   // TODO(port): This is inefficient, but works if there are multiple procs.
109*635a8641SAndroid Build Coastguard Worker   // TODO(port): use waitpid to avoid leaving zombies around
110*635a8641SAndroid Build Coastguard Worker 
111*635a8641SAndroid Build Coastguard Worker   TimeTicks end_time = TimeTicks::Now() + wait;
112*635a8641SAndroid Build Coastguard Worker   do {
113*635a8641SAndroid Build Coastguard Worker     NamedProcessIterator iter(executable_name, filter);
114*635a8641SAndroid Build Coastguard Worker     if (!iter.NextProcessEntry()) {
115*635a8641SAndroid Build Coastguard Worker       result = true;
116*635a8641SAndroid Build Coastguard Worker       break;
117*635a8641SAndroid Build Coastguard Worker     }
118*635a8641SAndroid Build Coastguard Worker     PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
119*635a8641SAndroid Build Coastguard Worker   } while ((end_time - TimeTicks::Now()) > TimeDelta());
120*635a8641SAndroid Build Coastguard Worker 
121*635a8641SAndroid Build Coastguard Worker   return result;
122*635a8641SAndroid Build Coastguard Worker }
123*635a8641SAndroid Build Coastguard Worker 
CleanupProcesses(const FilePath::StringType & executable_name,TimeDelta wait,int exit_code,const ProcessFilter * filter)124*635a8641SAndroid Build Coastguard Worker bool CleanupProcesses(const FilePath::StringType& executable_name,
125*635a8641SAndroid Build Coastguard Worker                       TimeDelta wait,
126*635a8641SAndroid Build Coastguard Worker                       int exit_code,
127*635a8641SAndroid Build Coastguard Worker                       const ProcessFilter* filter) {
128*635a8641SAndroid Build Coastguard Worker   bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
129*635a8641SAndroid Build Coastguard Worker   if (!exited_cleanly)
130*635a8641SAndroid Build Coastguard Worker     KillProcesses(executable_name, exit_code, filter);
131*635a8641SAndroid Build Coastguard Worker   return exited_cleanly;
132*635a8641SAndroid Build Coastguard Worker }
133*635a8641SAndroid Build Coastguard Worker 
134*635a8641SAndroid Build Coastguard Worker #if !defined(OS_MACOSX)
135*635a8641SAndroid Build Coastguard Worker 
136*635a8641SAndroid Build Coastguard Worker namespace {
137*635a8641SAndroid Build Coastguard Worker 
138*635a8641SAndroid Build Coastguard Worker class BackgroundReaper : public PlatformThread::Delegate {
139*635a8641SAndroid Build Coastguard Worker  public:
BackgroundReaper(base::Process child_process,const TimeDelta & wait_time)140*635a8641SAndroid Build Coastguard Worker   BackgroundReaper(base::Process child_process, const TimeDelta& wait_time)
141*635a8641SAndroid Build Coastguard Worker       : child_process_(std::move(child_process)), wait_time_(wait_time) {}
142*635a8641SAndroid Build Coastguard Worker 
ThreadMain()143*635a8641SAndroid Build Coastguard Worker   void ThreadMain() override {
144*635a8641SAndroid Build Coastguard Worker     if (!wait_time_.is_zero()) {
145*635a8641SAndroid Build Coastguard Worker       child_process_.WaitForExitWithTimeout(wait_time_, nullptr);
146*635a8641SAndroid Build Coastguard Worker       kill(child_process_.Handle(), SIGKILL);
147*635a8641SAndroid Build Coastguard Worker     }
148*635a8641SAndroid Build Coastguard Worker     child_process_.WaitForExit(nullptr);
149*635a8641SAndroid Build Coastguard Worker     delete this;
150*635a8641SAndroid Build Coastguard Worker   }
151*635a8641SAndroid Build Coastguard Worker 
152*635a8641SAndroid Build Coastguard Worker  private:
153*635a8641SAndroid Build Coastguard Worker   Process child_process_;
154*635a8641SAndroid Build Coastguard Worker   const TimeDelta wait_time_;
155*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
156*635a8641SAndroid Build Coastguard Worker };
157*635a8641SAndroid Build Coastguard Worker 
158*635a8641SAndroid Build Coastguard Worker }  // namespace
159*635a8641SAndroid Build Coastguard Worker 
EnsureProcessTerminated(Process process)160*635a8641SAndroid Build Coastguard Worker void EnsureProcessTerminated(Process process) {
161*635a8641SAndroid Build Coastguard Worker   DCHECK(!process.is_current());
162*635a8641SAndroid Build Coastguard Worker 
163*635a8641SAndroid Build Coastguard Worker   if (process.WaitForExitWithTimeout(TimeDelta(), nullptr))
164*635a8641SAndroid Build Coastguard Worker     return;
165*635a8641SAndroid Build Coastguard Worker 
166*635a8641SAndroid Build Coastguard Worker   PlatformThread::CreateNonJoinable(
167*635a8641SAndroid Build Coastguard Worker       0, new BackgroundReaper(std::move(process), TimeDelta::FromSeconds(2)));
168*635a8641SAndroid Build Coastguard Worker }
169*635a8641SAndroid Build Coastguard Worker 
170*635a8641SAndroid Build Coastguard Worker #if defined(OS_LINUX)
EnsureProcessGetsReaped(Process process)171*635a8641SAndroid Build Coastguard Worker void EnsureProcessGetsReaped(Process process) {
172*635a8641SAndroid Build Coastguard Worker   DCHECK(!process.is_current());
173*635a8641SAndroid Build Coastguard Worker 
174*635a8641SAndroid Build Coastguard Worker   // If the child is already dead, then there's nothing to do.
175*635a8641SAndroid Build Coastguard Worker   if (process.WaitForExitWithTimeout(TimeDelta(), nullptr))
176*635a8641SAndroid Build Coastguard Worker     return;
177*635a8641SAndroid Build Coastguard Worker 
178*635a8641SAndroid Build Coastguard Worker   PlatformThread::CreateNonJoinable(
179*635a8641SAndroid Build Coastguard Worker       0, new BackgroundReaper(std::move(process), TimeDelta()));
180*635a8641SAndroid Build Coastguard Worker }
181*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_LINUX)
182*635a8641SAndroid Build Coastguard Worker 
183*635a8641SAndroid Build Coastguard Worker #endif  // !defined(OS_MACOSX)
184*635a8641SAndroid Build Coastguard Worker #endif  // !defined(OS_NACL_NONSFI)
185*635a8641SAndroid Build Coastguard Worker 
186*635a8641SAndroid Build Coastguard Worker }  // namespace base
187