blob: c622ed3ae7ce347ee93ac73264610031374cffd2 [file] [log] [blame]
// Copyright (c) 2012 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.
#ifndef CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_
#define CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_
#include <stdint.h>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <vector>
#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/containers/id_map.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "build/build_config.h"
#include "chrome/browser/upgrade_detector/upgrade_observer.h"
#include "chrome/common/service_process.mojom.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#if defined(OS_CHROMEOS)
#error "Not supported on ChromeOS"
#endif
namespace base {
class CommandLine;
}
namespace mojo {
class IsolatedConnection;
}
// A ServiceProcessControl works as a portal between the service process and
// the browser process.
//
// It is used to start and terminate the service process. It is also used
// to send and receive IPC messages from the service process.
//
// THREADING
//
// This class is accessed on the UI thread through some UI actions.
class ServiceProcessControl : public UpgradeObserver {
public:
enum ServiceProcessEvent {
SERVICE_EVENT_INITIALIZE,
SERVICE_EVENT_ENABLED_ON_LAUNCH,
SERVICE_EVENT_ENABLE,
SERVICE_EVENT_DISABLE,
SERVICE_EVENT_DISABLE_BY_POLICY,
SERVICE_EVENT_LAUNCH,
SERVICE_EVENT_LAUNCHED,
SERVICE_EVENT_LAUNCH_FAILED,
SERVICE_EVENT_CHANNEL_CONNECTED,
SERVICE_EVENT_CHANNEL_ERROR,
SERVICE_EVENT_INFO_REQUEST,
SERVICE_EVENT_INFO_REPLY,
SERVICE_EVENT_HISTOGRAMS_REQUEST,
SERVICE_EVENT_HISTOGRAMS_REPLY,
SERVICE_PRINTERS_REQUEST,
SERVICE_PRINTERS_REPLY,
SERVICE_EVENT_MAX,
};
// Returns the singleton instance of this class.
static ServiceProcessControl* GetInstance();
// Return true if this object is connected to the service.
// Virtual for testing.
virtual bool IsConnected() const;
// If no service process is currently running, creates a new service process
// and connects to it. If a service process is already running this method
// will try to connect to it.
// |success_task| is called when we have successfully launched the process
// and connected to it.
// |failure_task| is called when we failed to connect to the service process.
// It is OK to pass the same value for |success_task| and |failure_task|. In
// this case, the task is invoked on success or failure.
// Note that if we are already connected to service process then
// |success_task| can be invoked in the context of the Launch call.
// Virtual for testing.
virtual void Launch(base::OnceClosure success_task,
base::OnceClosure failure_task);
// Disconnect the IPC channel from the service process.
// Virtual for testing.
virtual void Disconnect();
// UpgradeObserver implementation.
void OnUpgradeRecommended() override;
// Send a shutdown message to the service process. IPC channel will be
// destroyed after calling this method.
// Return true if the message was sent.
// Virtual for testing.
virtual bool Shutdown();
// Send request for histograms collected in service process.
// Returns true if request was sent, and callback will be called in case of
// success or timeout. The method resets any previous callback.
// Returns false if service is not running or other failure, callback will not
// be called in this case.
bool GetHistograms(const base::Closure& cloud_print_status_callback,
const base::TimeDelta& timeout);
service_manager::InterfaceProvider& remote_interfaces() {
return remote_interfaces_;
}
base::ProcessId GetLaunchedPidForTesting() const { return saved_pid_; }
private:
// This class is responsible for launching the service process on the
// PROCESS_LAUNCHER thread.
class Launcher
: public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
public:
explicit Launcher(std::unique_ptr<base::CommandLine> cmd_line);
// Execute the command line to start the process asynchronously. After the
// command is executed |task| is called with the process handle on the UI
// thread.
void Run(const base::Closure& task);
bool launched() const { return launched_; }
base::ProcessId saved_pid() const { return saved_pid_; }
private:
friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>;
virtual ~Launcher();
#if !defined(OS_MACOSX)
void DoDetectLaunched();
#endif // !OS_MACOSX
void DoRun();
void Notify();
std::unique_ptr<base::CommandLine> cmd_line_;
base::Closure notify_task_;
bool launched_;
uint32_t retry_count_;
base::Process process_;
// Used to save the process id for |process_| upon successful launch.
// Only used for testing.
base::ProcessId saved_pid_;
};
friend class MockServiceProcessControl;
friend class CloudPrintProxyPolicyStartupTest;
friend class TestCloudPrintProxyService;
ServiceProcessControl();
~ServiceProcessControl() override;
friend struct base::DefaultSingletonTraits<ServiceProcessControl>;
using TaskList = std::vector<base::OnceClosure>;
void OnChannelConnected();
void OnChannelError();
void OnHistograms(const std::vector<std::string>& pickled_histograms);
// Runs callback provided in |GetHistograms()|.
void RunHistogramsCallback();
// Helper method to invoke all the callbacks based on success or failure.
void RunConnectDoneTasks();
// Method called by Launcher when the service process is launched.
void OnProcessLaunched();
// Used internally to connect to the service process.
void ConnectInternal();
// Called when ConnectInternal's async work is done.
void OnPeerConnectionComplete(
std::unique_ptr<mojo::IsolatedConnection> connection);
// Split out for testing.
void SetMojoHandle(service_manager::mojom::InterfaceProviderPtr handle);
static void RunAllTasksHelper(TaskList* task_list);
std::unique_ptr<mojo::IsolatedConnection> mojo_connection_;
service_manager::InterfaceProvider remote_interfaces_;
chrome::mojom::ServiceProcessPtr service_process_;
// Service process launcher.
scoped_refptr<Launcher> launcher_;
// Callbacks that get invoked when the channel is successfully connected.
TaskList connect_success_tasks_;
// Callbacks that get invoked when there was a connection failure.
TaskList connect_failure_tasks_;
// Callback that gets invoked when a message with histograms is received from
// the service process.
base::Closure histograms_callback_;
// Callback that gets invoked if service didn't reply in time.
base::CancelableClosure histograms_timeout_callback_;
// If true changes to UpgradeObserver are applied, if false they are ignored.
bool apply_changes_from_upgrade_observer_;
// Same as |Launcher::saved_pid_|.
base::ProcessId saved_pid_;
base::WeakPtrFactory<ServiceProcessControl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceProcessControl);
};
#endif // CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_