blob: 0e2318472f455a2c9f40b4b2b12622aa9eca7e68 [file] [log] [blame]
siggic0d0a0e2014-11-17 23:29:191// 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.
4
siggi420541c2014-11-18 23:16:325#include "components/browser_watcher/exit_code_watcher_win.h"
siggic0d0a0e2014-11-17 23:29:196
siggic0d0a0e2014-11-17 23:29:197#include "base/logging.h"
8#include "base/process/kill.h"
siggic0d0a0e2014-11-17 23:29:199#include "base/strings/stringprintf.h"
10#include "base/win/registry.h"
11
12namespace browser_watcher {
13
14namespace {
15
16base::string16 GetValueName(const base::Time creation_time,
17 base::ProcessId pid) {
18 // Convert the PID and creation time to a string value unique to this
19 // process instance.
20 return base::StringPrintf(L"%d-%lld", pid, creation_time.ToInternalValue());
21}
22
23} // namespace
24
siggic0d0a0e2014-11-17 23:29:1925ExitCodeWatcher::ExitCodeWatcher(const base::char16* registry_path) :
siggid497a1a2014-12-19 15:20:5126 registry_path_(registry_path), exit_code_(STILL_ACTIVE) {
siggic0d0a0e2014-11-17 23:29:1927}
28
29ExitCodeWatcher::~ExitCodeWatcher() {
30}
31
erikwright7c4a4262015-01-09 18:32:3332bool ExitCodeWatcher::Initialize(base::Process process) {
rvargas960db882015-01-24 00:27:2533 if (!process.IsValid()) {
34 LOG(ERROR) << "Invalid parent handle, can't get parent process ID.";
35 return false;
36 }
37
38 DWORD process_pid = process.Pid();
siggic0d0a0e2014-11-17 23:29:1939 if (process_pid == 0) {
erikwright7c4a4262015-01-09 18:32:3340 LOG(ERROR) << "Invalid parent handle, can't get parent process ID.";
siggic0d0a0e2014-11-17 23:29:1941 return false;
42 }
43
44 FILETIME creation_time = {};
45 FILETIME dummy = {};
erikwright7c4a4262015-01-09 18:32:3346 if (!::GetProcessTimes(process.Handle(), &creation_time, &dummy, &dummy,
47 &dummy)) {
48 PLOG(ERROR) << "Invalid parent handle, can't get parent process times.";
siggic0d0a0e2014-11-17 23:29:1949 return false;
50 }
51
rvargas960db882015-01-24 00:27:2552 // Success, take ownership of the process.
erikwright7c4a4262015-01-09 18:32:3353 process_ = process.Pass();
siggic0d0a0e2014-11-17 23:29:1954 process_creation_time_ = base::Time::FromFileTime(creation_time);
55
56 // Start by writing the value STILL_ACTIVE to registry, to allow detection
57 // of the case where the watcher itself is somehow terminated before it can
58 // write the process' actual exit code.
59 return WriteProcessExitCode(STILL_ACTIVE);
60}
61
62void ExitCodeWatcher::WaitForExit() {
siggid497a1a2014-12-19 15:20:5163 if (!process_.WaitForExit(&exit_code_)) {
siggic0d0a0e2014-11-17 23:29:1964 LOG(ERROR) << "Failed to wait for process.";
65 return;
66 }
siggic0d0a0e2014-11-17 23:29:1967
siggid497a1a2014-12-19 15:20:5168 WriteProcessExitCode(exit_code_);
siggic0d0a0e2014-11-17 23:29:1969}
70
71bool ExitCodeWatcher::WriteProcessExitCode(int exit_code) {
72 base::win::RegKey key(HKEY_CURRENT_USER,
73 registry_path_.c_str(),
74 KEY_WRITE);
siggi581938f2014-12-18 21:17:1575 base::string16 value_name(
rvargas960db882015-01-24 00:27:2576 GetValueName(process_creation_time_, process_.Pid()));
siggic0d0a0e2014-11-17 23:29:1977
78 ULONG result = key.WriteValue(value_name.c_str(), exit_code);
79 if (result != ERROR_SUCCESS) {
80 LOG(ERROR) << "Unable to write to registry, error " << result;
81 return false;
82 }
83
84 return true;
85}
86
87} // namespace browser_watcher