summaryrefslogtreecommitdiffstats
path: root/components/browser_watcher/exit_code_watcher_win.cc
blob: 0e2318472f455a2c9f40b4b2b12622aa9eca7e68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 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