1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_
6#define CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_
7
8#include <queue>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/basictypes.h"
14#include "base/callback.h"
15#include "base/cancelable_callback.h"
16#include "base/id_map.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/memory/singleton.h"
19#include "base/process/process.h"
20#include "content/public/browser/notification_observer.h"
21#include "content/public/browser/notification_registrar.h"
22#include "ipc/ipc_channel_proxy.h"
23#include "ipc/ipc_listener.h"
24#include "ipc/ipc_sender.h"
25
26namespace base {
27class CommandLine;
28}
29
30namespace cloud_print {
31struct CloudPrintProxyInfo;
32}  // namespace cloud_print
33
34// A ServiceProcessControl works as a portal between the service process and
35// the browser process.
36//
37// It is used to start and terminate the service process. It is also used
38// to send and receive IPC messages from the service process.
39//
40// THREADING
41//
42// This class is accessed on the UI thread through some UI actions. It then
43// talks to the IPC channel on the IO thread.
44class ServiceProcessControl : public IPC::Sender,
45                              public IPC::Listener,
46                              public content::NotificationObserver {
47 public:
48  enum ServiceProcessEvent {
49    SERVICE_EVENT_INITIALIZE,
50    SERVICE_EVENT_ENABLED_ON_LAUNCH,
51    SERVICE_EVENT_ENABLE,
52    SERVICE_EVENT_DISABLE,
53    SERVICE_EVENT_DISABLE_BY_POLICY,
54    SERVICE_EVENT_LAUNCH,
55    SERVICE_EVENT_LAUNCHED,
56    SERVICE_EVENT_LAUNCH_FAILED,
57    SERVICE_EVENT_CHANNEL_CONNECTED,
58    SERVICE_EVENT_CHANNEL_ERROR,
59    SERVICE_EVENT_INFO_REQUEST,
60    SERVICE_EVENT_INFO_REPLY,
61    SERVICE_EVENT_HISTOGRAMS_REQUEST,
62    SERVICE_EVENT_HISTOGRAMS_REPLY,
63    SERVICE_PRINTERS_REQUEST,
64    SERVICE_PRINTERS_REPLY,
65    SERVICE_EVENT_MAX,
66  };
67
68  typedef IDMap<ServiceProcessControl>::iterator iterator;
69  typedef std::queue<IPC::Message> MessageQueue;
70  typedef base::Callback<void(const cloud_print::CloudPrintProxyInfo&)>
71      CloudPrintProxyInfoCallback;
72  typedef base::Callback<void(const std::vector<std::string>&)>
73      PrintersCallback;
74
75  // Returns the singleton instance of this class.
76  static ServiceProcessControl* GetInstance();
77
78  // Return true if this object is connected to the service.
79  // Virtual for testing.
80  virtual bool IsConnected() const;
81
82  // If no service process is currently running, creates a new service process
83  // and connects to it. If a service process is already running this method
84  // will try to connect to it.
85  // |success_task| is called when we have successfully launched the process
86  // and connected to it.
87  // |failure_task| is called when we failed to connect to the service process.
88  // It is OK to pass the same value for |success_task| and |failure_task|. In
89  // this case, the task is invoked on success or failure.
90  // Note that if we are already connected to service process then
91  // |success_task| can be invoked in the context of the Launch call.
92  // Virtual for testing.
93  virtual void Launch(const base::Closure& success_task,
94                      const base::Closure& failure_task);
95
96  // Disconnect the IPC channel from the service process.
97  // Virtual for testing.
98  virtual void Disconnect();
99
100  // IPC::Listener implementation.
101  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
102  virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
103  virtual void OnChannelError() OVERRIDE;
104
105  // IPC::Sender implementation
106  virtual bool Send(IPC::Message* message) OVERRIDE;
107
108  // content::NotificationObserver implementation.
109  virtual void Observe(int type,
110                       const content::NotificationSource& source,
111                       const content::NotificationDetails& details) OVERRIDE;
112
113  // Send a shutdown message to the service process. IPC channel will be
114  // destroyed after calling this method.
115  // Return true if the message was sent.
116  // Virtual for testing.
117  virtual bool Shutdown();
118
119  // Send request for cloud print proxy info (enabled state, email, proxy id).
120  // The callback gets the information when received.
121  // Returns true if request was sent. Callback will be called only in case of
122  // reply from service. The method resets any previous callback.
123  // This call starts service if needed.
124  bool GetCloudPrintProxyInfo(
125      const CloudPrintProxyInfoCallback& cloud_print_status_callback);
126
127  // Send request for histograms collected in service process.
128  // Returns true if request was sent, and callback will be called in case of
129  // success or timeout. The method resets any previous callback.
130  // Returns false if service is not running or other failure, callback will not
131  // be called in this case.
132  bool GetHistograms(const base::Closure& cloud_print_status_callback,
133                     const base::TimeDelta& timeout);
134
135  // Send request for printers available for cloud print proxy.
136  // The callback gets the information when received.
137  // Returns true if request was sent. Callback will be called only in case of
138  // reply from service. The method resets any previous callback.
139  // This call starts service if needed.
140  bool GetPrinters(const PrintersCallback& enumerate_printers_callback);
141
142 private:
143  // This class is responsible for launching the service process on the
144  // PROCESS_LAUNCHER thread.
145  class Launcher
146      : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
147   public:
148    Launcher(ServiceProcessControl* process,
149             scoped_ptr<base::CommandLine> cmd_line);
150    // Execute the command line to start the process asynchronously. After the
151    // command is executed |task| is called with the process handle on the UI
152    // thread.
153    void Run(const base::Closure& task);
154
155    bool launched() const { return launched_; }
156
157   private:
158    friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>;
159    virtual ~Launcher();
160
161#if !defined(OS_MACOSX)
162    void DoDetectLaunched();
163#endif  // !OS_MACOSX
164
165    void DoRun();
166    void Notify();
167    void CloseProcessHandle();
168    ServiceProcessControl* process_;
169    scoped_ptr<base::CommandLine> cmd_line_;
170    base::Closure notify_task_;
171    bool launched_;
172    uint32 retry_count_;
173    base::ProcessHandle process_handle_;
174  };
175
176  friend class MockServiceProcessControl;
177  friend class CloudPrintProxyPolicyStartupTest;
178
179  ServiceProcessControl();
180  virtual ~ServiceProcessControl();
181
182  friend struct DefaultSingletonTraits<ServiceProcessControl>;
183
184  typedef std::vector<base::Closure> TaskList;
185
186  // Message handlers
187  void OnCloudPrintProxyInfo(
188      const cloud_print::CloudPrintProxyInfo& proxy_info);
189  void OnHistograms(const std::vector<std::string>& pickled_histograms);
190  void OnPrinters(const std::vector<std::string>& printers);
191
192  // Runs callback provided in |GetHistograms()|.
193  void RunHistogramsCallback();
194
195  // Helper method to invoke all the callbacks based on success or failure.
196  void RunConnectDoneTasks();
197
198  // Method called by Launcher when the service process is launched.
199  void OnProcessLaunched();
200
201  // Used internally to connect to the service process.
202  void ConnectInternal();
203
204  // Takes ownership of the pointer. Split out for testing.
205  void SetChannel(scoped_ptr<IPC::ChannelProxy> channel);
206
207  static void RunAllTasksHelper(TaskList* task_list);
208
209  // IPC channel to the service process.
210  scoped_ptr<IPC::ChannelProxy> channel_;
211
212  // Service process launcher.
213  scoped_refptr<Launcher> launcher_;
214
215  // Callbacks that get invoked when the channel is successfully connected.
216  TaskList connect_success_tasks_;
217  // Callbacks that get invoked when there was a connection failure.
218  TaskList connect_failure_tasks_;
219
220  // Callback that gets invoked when a printers is received from
221  // the cloud print proxy.
222  PrintersCallback printers_callback_;
223
224  // Callback that gets invoked when a status message is received from
225  // the cloud print proxy.
226  CloudPrintProxyInfoCallback cloud_print_info_callback_;
227
228  // Callback that gets invoked when a message with histograms is received from
229  // the service process.
230  base::Closure histograms_callback_;
231
232  content::NotificationRegistrar registrar_;
233
234  // Callback that gets invoked if service didn't reply in time.
235  base::CancelableClosure histograms_timeout_callback_;
236};
237
238#endif  // CHROME_BROWSER_SERVICE_PROCESS_SERVICE_PROCESS_CONTROL_H_
239