1// Copyright (c) 2011 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_SERVICE_PROCESS_CONTROL_H_
6#define CHROME_BROWSER_SERVICE_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/id_map.h"
16#include "base/memory/scoped_ptr.h"
17#include "base/process.h"
18#include "base/task.h"
19#include "content/common/notification_observer.h"
20#include "content/common/notification_registrar.h"
21#include "ipc/ipc_sync_channel.h"
22
23class Profile;
24class CommandLine;
25
26namespace remoting {
27struct ChromotingHostInfo;
28}  // namespace remoting
29
30// A ServiceProcessControl works as a portal between the service process and
31// the browser process.
32//
33// It is used to start and terminate the service process. It is also used
34// to send and receive IPC messages from the service process.
35//
36// THREADING
37//
38// This class is accessed on the UI thread through some UI actions. It then
39// talks to the IPC channel on the IO thread.
40class ServiceProcessControl : public IPC::Channel::Sender,
41                              public IPC::Channel::Listener,
42                              public NotificationObserver {
43 public:
44  typedef IDMap<ServiceProcessControl>::iterator iterator;
45  typedef std::queue<IPC::Message> MessageQueue;
46  typedef Callback1<const remoting::ChromotingHostInfo&>::Type
47      RemotingHostStatusHandler;
48
49  // An interface for handling messages received from the service process.
50  class MessageHandler {
51   public:
52    virtual ~MessageHandler() {}
53
54    // Called when we receive reply to remoting host status request.
55    virtual void OnRemotingHostInfo(
56        const remoting::ChromotingHostInfo& host_info) = 0;
57  };
58
59  // Construct a ServiceProcessControl with |profile|..
60  explicit ServiceProcessControl(Profile* profile);
61  virtual ~ServiceProcessControl();
62
63  // Return the user profile associated with this service process.
64  Profile* profile() const { return profile_; }
65
66  // Return true if this object is connected to the service.
67  bool is_connected() const { return channel_.get() != NULL; }
68
69  // If no service process is currently running, creates a new service process
70  // and connects to it.
71  // If a service process is already running this method will try to connect
72  // to it.
73  // |success_task| is called when we have successfully launched the process
74  // and connected to it.
75  // |failure_task| is called when we failed to connect to the service process.
76  // It is OK to pass the same value for |success_task| and |failure_task|. In
77  // this case, the task is invoked on success or failure.
78  // Note that if we are already connected to service process then
79  // |success_task| can be invoked in the context of the Launch call.
80  // Takes ownership of |success_task| and |failure_task|.
81  void Launch(Task* success_task, Task* failure_task);
82
83  // IPC::Channel::Listener implementation.
84  virtual bool OnMessageReceived(const IPC::Message& message);
85  virtual void OnChannelConnected(int32 peer_pid);
86  virtual void OnChannelError();
87
88  // IPC::Channel::Sender implementation
89  virtual bool Send(IPC::Message* message);
90
91  // NotificationObserver implementation.
92  virtual void Observe(NotificationType type,
93                       const NotificationSource& source,
94                       const NotificationDetails& details);
95
96  // Message handlers
97  void OnCloudPrintProxyIsEnabled(bool enabled, std::string email);
98  void OnRemotingHostInfo(const remoting::ChromotingHostInfo& host_info);
99
100  // Send a shutdown message to the service process. IPC channel will be
101  // destroyed after calling this method.
102  // Return true if the message was sent.
103  bool Shutdown();
104
105  // Send request for cloud print proxy status and the registered
106  // email address. The callback gets the information when received.
107  bool GetCloudPrintProxyStatus(
108      Callback2<bool, std::string>::Type* cloud_print_status_callback);
109
110  // Send a message to enable the remoting service in the service process.
111  // Return true if the message was sent.
112  bool SetRemotingHostCredentials(const std::string& user,
113                                  const std::string& auth_token);
114
115  bool EnableRemotingHost();
116  bool DisableRemotingHost();
117
118  // Send request for current status of the remoting service.
119  // MessageHandler::OnRemotingHostInfo() will be called when remoting host
120  // status is available.
121  bool RequestRemotingHostStatus();
122
123  // Add a message handler for receiving messages from the service
124  // process.
125  void AddMessageHandler(MessageHandler* message_handler);
126
127  // Remove a message handler from the list of message handlers. Must
128  // not be called from a message handler (i.e. while a message is
129  // being processed).
130  void RemoveMessageHandler(MessageHandler* message_handler);
131
132 private:
133  // This class is responsible for launching the service process on the
134  // PROCESS_LAUNCHER thread.
135  class Launcher
136      : public base::RefCountedThreadSafe<ServiceProcessControl::Launcher> {
137   public:
138    Launcher(ServiceProcessControl* process, CommandLine* cmd_line);
139    // Execute the command line to start the process asynchronously.
140    // After the comamnd is executed |task| is called with the process handle on
141    // the UI thread.
142    void Run(Task* task);
143
144    bool launched() const { return launched_; }
145
146   private:
147    friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>;
148    virtual ~Launcher();
149
150#if !defined(OS_MACOSX)
151    void DoDetectLaunched();
152#endif  // !OS_MACOSX
153
154    void DoRun();
155    void Notify();
156    ServiceProcessControl* process_;
157    scoped_ptr<CommandLine> cmd_line_;
158    scoped_ptr<Task> notify_task_;
159    bool launched_;
160    uint32 retry_count_;
161  };
162
163  typedef std::vector<Task*> TaskList;
164
165  // Helper method to invoke all the callbacks based on success on failure.
166  void RunConnectDoneTasks();
167
168  // Method called by Launcher when the service process is launched.
169  void OnProcessLaunched();
170
171  // Used internally to connect to the service process.
172  void ConnectInternal();
173
174  static void RunAllTasksHelper(TaskList* task_list);
175
176  Profile* profile_;
177
178  // IPC channel to the service process.
179  scoped_ptr<IPC::SyncChannel> channel_;
180
181  // Service process launcher.
182  scoped_refptr<Launcher> launcher_;
183
184  // Callbacks that get invoked when the channel is successfully connected or
185  // if there was a failure in connecting.
186  TaskList connect_done_tasks_;
187  // Callbacks that get invoked ONLY when the channel is successfully connected.
188  TaskList connect_success_tasks_;
189  // Callbacks that get invoked ONLY when there was a connection failure.
190  TaskList connect_failure_tasks_;
191
192  // Callback that gets invoked when a status message is received from
193  // the cloud print proxy.
194  scoped_ptr<Callback2<bool, std::string>::Type> cloud_print_status_callback_;
195
196  // Handler for messages from service process.
197  std::set<MessageHandler*> message_handlers_;
198
199  NotificationRegistrar registrar_;
200};
201
202#endif  // CHROME_BROWSER_SERVICE_SERVICE_PROCESS_CONTROL_H_
203