xref: /aosp_15_r20/external/cronet/base/process/kill_win.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/process/kill.h"
6 
7 #include <windows.h>
8 
9 #include <io.h>
10 #include <stdint.h>
11 
12 #include <algorithm>
13 
14 #include "base/logging.h"
15 #include "base/notreached.h"
16 #include "base/process/memory.h"
17 #include "base/process/process_iterator.h"
18 
19 namespace base {
20 
GetTerminationStatus(ProcessHandle handle,int * exit_code)21 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
22   DCHECK(exit_code);
23 
24   DWORD tmp_exit_code = 0;
25 
26   if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
27     DPLOG(FATAL) << "GetExitCodeProcess() failed";
28 
29     // This really is a random number.  We haven't received any
30     // information about the exit code, presumably because this
31     // process doesn't have permission to get the exit code, or
32     // because of some other cause for GetExitCodeProcess to fail
33     // (MSDN docs don't give the possible failure error codes for
34     // this function, so it could be anything).  But we don't want
35     // to leave exit_code uninitialized, since that could cause
36     // random interpretations of the exit code.  So we assume it
37     // terminated "normally" in this case.
38     *exit_code = win::kNormalTerminationExitCode;
39 
40     // Assume the child has exited normally if we can't get the exit
41     // code.
42     return TERMINATION_STATUS_NORMAL_TERMINATION;
43   }
44   if (tmp_exit_code == STILL_ACTIVE) {
45     DWORD wait_result = WaitForSingleObject(handle, 0);
46     if (wait_result == WAIT_TIMEOUT) {
47       *exit_code = static_cast<int>(wait_result);
48       return TERMINATION_STATUS_STILL_RUNNING;
49     }
50 
51     if (wait_result == WAIT_FAILED) {
52       DPLOG(ERROR) << "WaitForSingleObject() failed";
53       *exit_code = static_cast<int>(wait_result);
54     } else {
55       DCHECK_EQ(WAIT_OBJECT_0, wait_result);
56       DLOG(ERROR) << "The process used 0x103 (STILL_ACTIVE) as exit code.";
57       *exit_code = static_cast<int>(tmp_exit_code);
58     }
59 
60     return TERMINATION_STATUS_ABNORMAL_TERMINATION;
61   }
62 
63   *exit_code = static_cast<int>(tmp_exit_code);
64 
65   // clang-format off
66   switch (tmp_exit_code) {
67     case win::kNormalTerminationExitCode:
68       return TERMINATION_STATUS_NORMAL_TERMINATION;
69     case win::kDebuggerInactiveExitCode:    // STATUS_DEBUGGER_INACTIVE.
70     case win::kKeyboardInterruptExitCode:   // Control-C/end session.
71     case win::kDebuggerTerminatedExitCode:  // Debugger terminated process.
72     case win::kProcessKilledExitCode:       // Task manager kill.
73       return TERMINATION_STATUS_PROCESS_WAS_KILLED;
74     case win::kSandboxFatalMemoryExceeded:  // Terminated process due to
75                                             // exceeding the sandbox job
76                                             // object memory limits.
77     case win::kOomExceptionCode:            // Ran out of memory.
78       return TERMINATION_STATUS_OOM;
79     // This exit code means the process failed an OS integrity check.
80     // This is tested in ProcessMitigationsTest.* in sandbox.
81     case win::kStatusInvalidImageHashExitCode:
82       return TERMINATION_STATUS_INTEGRITY_FAILURE;
83     default:
84       // All other exit codes indicate crashes.
85       return TERMINATION_STATUS_PROCESS_CRASHED;
86   }
87   // clang-format on
88 }
89 
WaitForProcessesToExit(const FilePath::StringType & executable_name,TimeDelta wait,const ProcessFilter * filter)90 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
91                             TimeDelta wait,
92                             const ProcessFilter* filter) {
93   bool result = true;
94   DWORD start_time = GetTickCount();
95 
96   NamedProcessIterator iter(executable_name, filter);
97   for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
98        entry = iter.NextProcessEntry()) {
99     DWORD remaining_wait = static_cast<DWORD>(
100         std::max(static_cast<int64_t>(0),
101                  wait.InMilliseconds() - (GetTickCount() - start_time)));
102     HANDLE process = OpenProcess(SYNCHRONIZE,
103                                  FALSE,
104                                  entry->th32ProcessID);
105     DWORD wait_result = WaitForSingleObject(process, remaining_wait);
106     CloseHandle(process);
107     result &= (wait_result == WAIT_OBJECT_0);
108   }
109 
110   return result;
111 }
112 
CleanupProcesses(const FilePath::StringType & executable_name,TimeDelta wait,int exit_code,const ProcessFilter * filter)113 bool CleanupProcesses(const FilePath::StringType& executable_name,
114                       TimeDelta wait,
115                       int exit_code,
116                       const ProcessFilter* filter) {
117   if (WaitForProcessesToExit(executable_name, wait, filter))
118     return true;
119   KillProcesses(executable_name, exit_code, filter);
120   return false;
121 }
122 
123 }  // namespace base
124