| // 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 <utility> | 
 |  | 
 | #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(base::StringPiece16 registry_path) | 
 |     : registry_path_(registry_path.as_string()), 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_ = std::move(process); | 
 |   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 |