// 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 int a // BrowserWatcherClient::CommandLineGenerator. The ChromeWatcherClient API is // more intuitive if the ChromeWatcherClient::CommandLineGenerator takes // |parent_process| as its second (of three) parameters, 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, 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); }