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);
}
|