// Copyright (c) 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/browser_watcher/exit_code_watcher_win.h" #include "base/logging.h" #include "base/process/kill.h" #include "base/strings/stringprintf.h" #include "base/win/registry.h" namespace browser_watcher { namespace { base::string16 GetValueName(const base::Time creation_time, base::ProcessId pid) { // Convert the PID and creation time to a string value unique to this // process instance. return base::StringPrintf(L"%d-%lld", pid, creation_time.ToInternalValue()); } } // namespace ExitCodeWatcher::ExitCodeWatcher(const base::char16* registry_path) : registry_path_(registry_path), exit_code_(STILL_ACTIVE) { } ExitCodeWatcher::~ExitCodeWatcher() { } bool ExitCodeWatcher::Initialize(base::Process process) { if (!process.IsValid()) { LOG(ERROR) << "Invalid parent handle, can't get parent process ID."; return false; } DWORD process_pid = process.Pid(); if (process_pid == 0) { LOG(ERROR) << "Invalid parent handle, can't get parent process ID."; return false; } FILETIME creation_time = {}; FILETIME dummy = {}; if (!::GetProcessTimes(process.Handle(), &creation_time, &dummy, &dummy, &dummy)) { PLOG(ERROR) << "Invalid parent handle, can't get parent process times."; return false; } // Success, take ownership of the process. process_ = process.Pass(); process_creation_time_ = base::Time::FromFileTime(creation_time); // Start by writing the value STILL_ACTIVE to registry, to allow detection // of the case where the watcher itself is somehow terminated before it can // write the process' actual exit code. return WriteProcessExitCode(STILL_ACTIVE); } void ExitCodeWatcher::WaitForExit() { if (!process_.WaitForExit(&exit_code_)) { LOG(ERROR) << "Failed to wait for process."; return; } WriteProcessExitCode(exit_code_); } bool ExitCodeWatcher::WriteProcessExitCode(int exit_code) { base::win::RegKey key(HKEY_CURRENT_USER, registry_path_.c_str(), KEY_WRITE); base::string16 value_name( GetValueName(process_creation_time_, process_.Pid())); ULONG result = key.WriteValue(value_name.c_str(), exit_code); if (result != ERROR_SUCCESS) { LOG(ERROR) << "Unable to write to registry, error " << result; return false; } return true; } } // namespace browser_watcher