1 // Copyright (c) 2014 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.
5 #include "components/browser_watcher/exit_code_watcher_win.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/process/kill.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/win/registry.h"
14 namespace browser_watcher
{
18 base::string16
GetValueName(const base::Time creation_time
,
19 base::ProcessId pid
) {
20 // Convert the PID and creation time to a string value unique to this
22 return base::StringPrintf(L
"%d-%lld", pid
, creation_time
.ToInternalValue());
27 const char ExitCodeWatcher::kParenthHandleSwitch
[] = "parent-handle";
29 ExitCodeWatcher::ExitCodeWatcher(const base::char16
* registry_path
) :
30 registry_path_(registry_path
),
34 ExitCodeWatcher::~ExitCodeWatcher() {
37 bool ExitCodeWatcher::ParseArguments(const base::CommandLine
& cmd_line
) {
38 std::string process_handle_str
=
39 cmd_line
.GetSwitchValueASCII(kParenthHandleSwitch
);
40 unsigned process_handle_uint
= 0;
41 if (process_handle_str
.empty() ||
42 !base::StringToUint(process_handle_str
, &process_handle_uint
)) {
43 LOG(ERROR
) << "Missing or invalid parent-handle argument.";
47 HANDLE process_handle
= reinterpret_cast<HANDLE
>(process_handle_uint
);
48 // Initial test of the handle, a zero PID indicates invalid handle, or not
49 // a process handle. In this case, bail immediately and avoid closing the
51 DWORD process_pid
= ::GetProcessId(process_handle
);
52 if (process_pid
== 0) {
53 LOG(ERROR
) << "Invalid parent-handle, can't get parent PID.";
57 FILETIME creation_time
= {};
59 if (!::GetProcessTimes(process_handle
, &creation_time
,
60 &dummy
, &dummy
, &dummy
)) {
61 LOG(ERROR
) << "Invalid parent handle, can't get parent process times.";
65 // Success, take ownership of the process handle.
66 process_
.Set(process_handle
);
67 process_pid_
= process_pid
;
68 process_creation_time_
= base::Time::FromFileTime(creation_time
);
70 // Start by writing the value STILL_ACTIVE to registry, to allow detection
71 // of the case where the watcher itself is somehow terminated before it can
72 // write the process' actual exit code.
73 return WriteProcessExitCode(STILL_ACTIVE
);
76 void ExitCodeWatcher::WaitForExit() {
78 if (!base::WaitForExitCode(process_
.Get(), &exit_code
)) {
79 LOG(ERROR
) << "Failed to wait for process.";
82 // WaitForExitCode closes the handle on success.
85 WriteProcessExitCode(exit_code
);
88 bool ExitCodeWatcher::WriteProcessExitCode(int exit_code
) {
89 base::win::RegKey
key(HKEY_CURRENT_USER
,
90 registry_path_
.c_str(),
92 base::string16
value_name(GetValueName(process_creation_time_
, process_pid_
));
94 ULONG result
= key
.WriteValue(value_name
.c_str(), exit_code
);
95 if (result
!= ERROR_SUCCESS
) {
96 LOG(ERROR
) << "Unable to write to registry, error " << result
;
103 } // namespace browser_watcher