summaryrefslogtreecommitdiffstats
path: root/chrome/app/chrome_watcher_client_win.cc
blob: 23e595eac869207c71e70fb4eae0aa28af5b53d3 (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2015 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 "chrome/app/chrome_watcher_client_win.h"

#include "base/bind.h"
#include "base/logging.h"
#include "components/browser_watcher/watcher_client_win.h"

namespace {

// Because we can only bind parameters from the left, |parent_process| must be
// the last parameter of the method that we bind into a
// BrowserWatcherClient::CommandLineGenerator. The ChromeWatcherClient API is
// more intuitive if the ChromeWatcherClient::CommandLineGenerator takes
// |parent_process| as its second parameter, so we use this intermediate
// function to swap the order.
base::CommandLine InvokeCommandLineGenerator(
    const ChromeWatcherClient::CommandLineGenerator& command_line_generator,
    HANDLE on_initialized_event,
    HANDLE parent_process) {
  return command_line_generator.Run(parent_process, ::GetCurrentThreadId(),
                                    on_initialized_event);
}

}  // namespace

ChromeWatcherClient::ChromeWatcherClient(
    const CommandLineGenerator& command_line_generator)
    : command_line_generator_(command_line_generator) {
}

ChromeWatcherClient::~ChromeWatcherClient() {
}

bool ChromeWatcherClient::LaunchWatcher() {
  // Create an inheritable event that the child process will signal when it has
  // completed initialization.
  SECURITY_ATTRIBUTES on_initialized_event_attributes = {
      sizeof(SECURITY_ATTRIBUTES),  // nLength
      nullptr,                      // lpSecurityDescriptor
      TRUE                          // bInheritHandle
  };
  on_initialized_event_.Set(::CreateEvent(&on_initialized_event_attributes,
                                          TRUE,  // manual reset
                                          FALSE, nullptr));
  if (!on_initialized_event_.IsValid()) {
    DPLOG(ERROR) << "Failed to create an event.";
    return false;
  }

  // Configure the basic WatcherClient, binding in the initialization event
  // HANDLE.
  browser_watcher::WatcherClient watcher_client(
      base::Bind(&InvokeCommandLineGenerator, command_line_generator_,
                 on_initialized_event_.Get()));
  // Indicate that the event HANDLE should be inherited.
  watcher_client.AddInheritedHandle(on_initialized_event_.Get());
  // Launch the watcher.
  watcher_client.LaunchWatcher();
  // Grab a handle to the watcher so that we may later wait on its
  // initialization.
  process_ = watcher_client.process().Duplicate();
  if (!process_.IsValid())
    on_initialized_event_.Close();
  return process_.IsValid();
}

bool ChromeWatcherClient::EnsureInitialized() {
  if (!process_.IsValid())
    return false;

  DCHECK(on_initialized_event_.IsValid());

  HANDLE handles[] = {on_initialized_event_.Get(), process_.Handle()};
  DWORD result = ::WaitForMultipleObjects(arraysize(handles), handles,
                                          FALSE, INFINITE);

  switch (result) {
    case WAIT_OBJECT_0:
      return true;
    case WAIT_OBJECT_0 + 1:
      LOG(ERROR) << "Chrome watcher process failed to launch.";
      return false;
    case WAIT_FAILED:
      DPLOG(ERROR) << "Failure while waiting on Chrome watcher process launch.";
      return false;
    default:
      NOTREACHED() << "Unexpected result while waiting on Chrome watcher "
                      "process launch: " << result;
      return false;
  }
}

bool ChromeWatcherClient::WaitForExit(int* exit_code) {
  return process_.IsValid() && process_.WaitForExit(exit_code);
}

bool ChromeWatcherClient::WaitForExitWithTimeout(base::TimeDelta timeout,
                                                 int* exit_code) {
  return process_.IsValid() &&
         process_.WaitForExitWithTimeout(timeout, exit_code);
}