|  | // 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 <queue> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/callback.h" | 
|  | #include "base/cancelable_callback.h" | 
|  | #include "base/id_map.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/memory/singleton.h" | 
|  | #include "base/process/process.h" | 
|  | #include "build/build_config.h" | 
|  | #include "content/public/browser/notification_observer.h" | 
|  | #include "content/public/browser/notification_registrar.h" | 
|  | #include "ipc/ipc_channel_proxy.h" | 
|  | #include "ipc/ipc_listener.h" | 
|  | #include "ipc/ipc_sender.h" | 
|  |  | 
|  | namespace base { | 
|  | class CommandLine; | 
|  | } | 
|  |  | 
|  | namespace cloud_print { | 
|  | struct CloudPrintProxyInfo; | 
|  | }  // namespace cloud_print | 
|  |  | 
|  | // 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. It then | 
|  | // talks to the IPC channel on the IO thread. | 
|  | class ServiceProcessControl : public IPC::Sender, | 
|  | public IPC::Listener, | 
|  | public content::NotificationObserver { | 
|  | 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, | 
|  | }; | 
|  |  | 
|  | typedef IDMap<ServiceProcessControl>::iterator iterator; | 
|  | typedef std::queue<IPC::Message> MessageQueue; | 
|  | typedef base::Callback<void(const cloud_print::CloudPrintProxyInfo&)> | 
|  | CloudPrintProxyInfoCallback; | 
|  | typedef base::Callback<void(const std::vector<std::string>&)> | 
|  | PrintersCallback; | 
|  |  | 
|  | // 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(const base::Closure& success_task, | 
|  | const base::Closure& failure_task); | 
|  |  | 
|  | // Disconnect the IPC channel from the service process. | 
|  | // Virtual for testing. | 
|  | virtual void Disconnect(); | 
|  |  | 
|  | // IPC::Listener implementation. | 
|  | bool OnMessageReceived(const IPC::Message& message) override; | 
|  | void OnChannelConnected(int32_t peer_pid) override; | 
|  | void OnChannelError() override; | 
|  |  | 
|  | // IPC::Sender implementation | 
|  | bool Send(IPC::Message* message) override; | 
|  |  | 
|  | // content::NotificationObserver implementation. | 
|  | void Observe(int type, | 
|  | const content::NotificationSource& source, | 
|  | const content::NotificationDetails& details) 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 cloud print proxy info (enabled state, email, proxy id). | 
|  | // The callback gets the information when received. | 
|  | // Returns true if request was sent. Callback will be called only in case of | 
|  | // reply from service. The method resets any previous callback. | 
|  | // This call starts service if needed. | 
|  | bool GetCloudPrintProxyInfo( | 
|  | const CloudPrintProxyInfoCallback& cloud_print_status_callback); | 
|  |  | 
|  | // 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); | 
|  |  | 
|  | // Send request for printers available for cloud print proxy. | 
|  | // The callback gets the information when received. | 
|  | // Returns true if request was sent. Callback will be called only in case of | 
|  | // reply from service. The method resets any previous callback. | 
|  | // This call starts service if needed. | 
|  | bool GetPrinters(const PrintersCallback& enumerate_printers_callback); | 
|  |  | 
|  | 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(scoped_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_; } | 
|  |  | 
|  | private: | 
|  | friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>; | 
|  | virtual ~Launcher(); | 
|  |  | 
|  | #if !defined(OS_MACOSX) | 
|  | void DoDetectLaunched(); | 
|  | #endif  // !OS_MACOSX | 
|  |  | 
|  | void DoRun(); | 
|  | void Notify(); | 
|  | scoped_ptr<base::CommandLine> cmd_line_; | 
|  | base::Closure notify_task_; | 
|  | bool launched_; | 
|  | uint32_t retry_count_; | 
|  | base::Process process_; | 
|  | }; | 
|  |  | 
|  | friend class MockServiceProcessControl; | 
|  | friend class CloudPrintProxyPolicyStartupTest; | 
|  |  | 
|  | ServiceProcessControl(); | 
|  | ~ServiceProcessControl() override; | 
|  |  | 
|  | friend struct base::DefaultSingletonTraits<ServiceProcessControl>; | 
|  |  | 
|  | typedef std::vector<base::Closure> TaskList; | 
|  |  | 
|  | // Message handlers | 
|  | void OnCloudPrintProxyInfo( | 
|  | const cloud_print::CloudPrintProxyInfo& proxy_info); | 
|  | void OnHistograms(const std::vector<std::string>& pickled_histograms); | 
|  | void OnPrinters(const std::vector<std::string>& printers); | 
|  |  | 
|  | // 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(); | 
|  |  | 
|  | // Takes ownership of the pointer. Split out for testing. | 
|  | void SetChannel(scoped_ptr<IPC::ChannelProxy> channel); | 
|  |  | 
|  | static void RunAllTasksHelper(TaskList* task_list); | 
|  |  | 
|  | // IPC channel to the service process. | 
|  | scoped_ptr<IPC::ChannelProxy> channel_; | 
|  |  | 
|  | // 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 printers is received from | 
|  | // the cloud print proxy. | 
|  | PrintersCallback printers_callback_; | 
|  |  | 
|  | // Callback that gets invoked when a status message is received from | 
|  | // the cloud print proxy. | 
|  | CloudPrintProxyInfoCallback cloud_print_info_callback_; | 
|  |  | 
|  | // Callback that gets invoked when a message with histograms is received from | 
|  | // the service process. | 
|  | base::Closure histograms_callback_; | 
|  |  | 
|  | content::NotificationRegistrar registrar_; | 
|  |  | 
|  | // Callback that gets invoked if service didn't reply in time. | 
|  | base::CancelableClosure histograms_timeout_callback_; | 
|  | }; | 
|  |  | 
|  | #endif  // CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_ |