Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / base / process / kill_win.cc
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
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 <io.h>
8 #include <windows.h>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/process/process_iterator.h"
15 #include "base/profiler/scoped_tracker.h"
16 #include "base/win/object_watcher.h"
17
18 namespace base {
19
20 namespace {
21
22 // Exit codes with special meanings on Windows.
23 const DWORD kNormalTerminationExitCode = 0;
24 const DWORD kDebuggerInactiveExitCode = 0xC0000354;
25 const DWORD kKeyboardInterruptExitCode = 0xC000013A;
26 const DWORD kDebuggerTerminatedExitCode = 0x40010004;
27
28 // This exit code is used by the Windows task manager when it kills a
29 // process.  It's value is obviously not that unique, and it's
30 // surprising to me that the task manager uses this value, but it
31 // seems to be common practice on Windows to test for it as an
32 // indication that the task manager has killed something if the
33 // process goes away.
34 const DWORD kProcessKilledExitCode = 1;
35
36 // Maximum amount of time (in milliseconds) to wait for the process to exit.
37 static const int kWaitInterval = 2000;
38
39 class TimerExpiredTask : public win::ObjectWatcher::Delegate {
40  public:
41   explicit TimerExpiredTask(ProcessHandle process);
42   ~TimerExpiredTask();
43
44   void TimedOut();
45
46   // MessageLoop::Watcher -----------------------------------------------------
47   virtual void OnObjectSignaled(HANDLE object);
48
49  private:
50   void KillProcess();
51
52   // The process that we are watching.
53   ProcessHandle process_;
54
55   win::ObjectWatcher watcher_;
56
57   DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
58 };
59
60 TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
61   watcher_.StartWatching(process_, this);
62 }
63
64 TimerExpiredTask::~TimerExpiredTask() {
65   TimedOut();
66   DCHECK(!process_) << "Make sure to close the handle.";
67 }
68
69 void TimerExpiredTask::TimedOut() {
70   if (process_)
71     KillProcess();
72 }
73
74 void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
75   // TODO(vadimt): Remove ScopedTracker below once crbug.com/418183 is fixed.
76   tracked_objects::ScopedTracker tracking_profile(
77       FROM_HERE_WITH_EXPLICIT_FUNCTION("TimerExpiredTask_OnObjectSignaled"));
78
79   CloseHandle(process_);
80   process_ = NULL;
81 }
82
83 void TimerExpiredTask::KillProcess() {
84   // Stop watching the process handle since we're killing it.
85   watcher_.StopWatching();
86
87   // OK, time to get frisky.  We don't actually care when the process
88   // terminates.  We just care that it eventually terminates, and that's what
89   // TerminateProcess should do for us. Don't check for the result code since
90   // it fails quite often. This should be investigated eventually.
91   base::KillProcess(process_, kProcessKilledExitCode, false);
92
93   // Now, just cleanup as if the process exited normally.
94   OnObjectSignaled(process_);
95 }
96
97 }  // namespace
98
99 bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
100   bool result = (TerminateProcess(process, exit_code) != FALSE);
101   if (result && wait) {
102     // The process may not end immediately due to pending I/O
103     if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
104       DPLOG(ERROR) << "Error waiting for process exit";
105   } else if (!result) {
106     DPLOG(ERROR) << "Unable to terminate process";
107   }
108   return result;
109 }
110
111 // Attempts to kill the process identified by the given process
112 // entry structure, giving it the specified exit code.
113 // Returns true if this is successful, false otherwise.
114 bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
115   HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
116                                FALSE,  // Don't inherit handle
117                                process_id);
118   if (!process) {
119     DPLOG(ERROR) << "Unable to open process " << process_id;
120     return false;
121   }
122   bool ret = KillProcess(process, exit_code, wait);
123   CloseHandle(process);
124   return ret;
125 }
126
127 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
128   DWORD tmp_exit_code = 0;
129
130   if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
131     DPLOG(FATAL) << "GetExitCodeProcess() failed";
132     if (exit_code) {
133       // This really is a random number.  We haven't received any
134       // information about the exit code, presumably because this
135       // process doesn't have permission to get the exit code, or
136       // because of some other cause for GetExitCodeProcess to fail
137       // (MSDN docs don't give the possible failure error codes for
138       // this function, so it could be anything).  But we don't want
139       // to leave exit_code uninitialized, since that could cause
140       // random interpretations of the exit code.  So we assume it
141       // terminated "normally" in this case.
142       *exit_code = kNormalTerminationExitCode;
143     }
144     // Assume the child has exited normally if we can't get the exit
145     // code.
146     return TERMINATION_STATUS_NORMAL_TERMINATION;
147   }
148   if (tmp_exit_code == STILL_ACTIVE) {
149     DWORD wait_result = WaitForSingleObject(handle, 0);
150     if (wait_result == WAIT_TIMEOUT) {
151       if (exit_code)
152         *exit_code = wait_result;
153       return TERMINATION_STATUS_STILL_RUNNING;
154     }
155
156     if (wait_result == WAIT_FAILED) {
157       DPLOG(ERROR) << "WaitForSingleObject() failed";
158     } else {
159       DCHECK_EQ(WAIT_OBJECT_0, wait_result);
160
161       // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
162       NOTREACHED();
163     }
164
165     return TERMINATION_STATUS_ABNORMAL_TERMINATION;
166   }
167
168   if (exit_code)
169     *exit_code = tmp_exit_code;
170
171   switch (tmp_exit_code) {
172     case kNormalTerminationExitCode:
173       return TERMINATION_STATUS_NORMAL_TERMINATION;
174     case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
175     case kKeyboardInterruptExitCode:  // Control-C/end session.
176     case kDebuggerTerminatedExitCode:  // Debugger terminated process.
177     case kProcessKilledExitCode:  // Task manager kill.
178       return TERMINATION_STATUS_PROCESS_WAS_KILLED;
179     default:
180       // All other exit codes indicate crashes.
181       return TERMINATION_STATUS_PROCESS_CRASHED;
182   }
183 }
184
185 bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
186   bool success = WaitForExitCodeWithTimeout(
187       handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE));
188   CloseProcessHandle(handle);
189   return success;
190 }
191
192 bool WaitForExitCodeWithTimeout(ProcessHandle handle,
193                                 int* exit_code,
194                                 base::TimeDelta timeout) {
195   if (::WaitForSingleObject(
196       handle, static_cast<DWORD>(timeout.InMilliseconds())) != WAIT_OBJECT_0)
197     return false;
198   DWORD temp_code;  // Don't clobber out-parameters in case of failure.
199   if (!::GetExitCodeProcess(handle, &temp_code))
200     return false;
201
202   *exit_code = temp_code;
203   return true;
204 }
205
206 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
207                             base::TimeDelta wait,
208                             const ProcessFilter* filter) {
209   bool result = true;
210   DWORD start_time = GetTickCount();
211
212   NamedProcessIterator iter(executable_name, filter);
213   for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
214        entry = iter.NextProcessEntry()) {
215     DWORD remaining_wait = static_cast<DWORD>(std::max(
216         static_cast<int64>(0),
217         wait.InMilliseconds() - (GetTickCount() - start_time)));
218     HANDLE process = OpenProcess(SYNCHRONIZE,
219                                  FALSE,
220                                  entry->th32ProcessID);
221     DWORD wait_result = WaitForSingleObject(process, remaining_wait);
222     CloseHandle(process);
223     result &= (wait_result == WAIT_OBJECT_0);
224   }
225
226   return result;
227 }
228
229 bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
230   int exit_code;
231   return WaitForExitCodeWithTimeout(handle, &exit_code, wait) && exit_code == 0;
232 }
233
234 bool CleanupProcesses(const FilePath::StringType& executable_name,
235                       base::TimeDelta wait,
236                       int exit_code,
237                       const ProcessFilter* filter) {
238   if (WaitForProcessesToExit(executable_name, wait, filter))
239     return true;
240   KillProcesses(executable_name, exit_code, filter);
241   return false;
242 }
243
244 void EnsureProcessTerminated(ProcessHandle process) {
245   DCHECK(process != GetCurrentProcess());
246
247   // If already signaled, then we are done!
248   if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
249     CloseHandle(process);
250     return;
251   }
252
253   MessageLoop::current()->PostDelayedTask(
254       FROM_HERE,
255       base::Bind(&TimerExpiredTask::TimedOut,
256                  base::Owned(new TimerExpiredTask(process))),
257       base::TimeDelta::FromMilliseconds(kWaitInterval));
258 }
259
260 }  // namespace base