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 REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_
6#define REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_
7
8#include <queue>
9#include <string>
10
11#include "base/callback.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14
15namespace base {
16class DictionaryValue;
17class SingleThreadTaskRunner;
18}  // namespace base
19
20namespace remoting {
21
22class AutoThread;
23class AutoThreadTaskRunner;
24
25class DaemonController : public base::RefCountedThreadSafe<DaemonController> {
26 public:
27  // Note that these enumeration values are duplicated in host_controller.js and
28  // must be kept in sync.
29  enum State {
30    // Placeholder state for platforms on which the daemon process is not
31    // implemented. The web-app will not show the corresponding UI. This value
32    // will eventually be deprecated or removed.
33    STATE_NOT_IMPLEMENTED = -1,
34    // The daemon is not installed. This is functionally equivalent to
35    // STATE_STOPPED, but the start method is expected to be significantly
36    // slower, and might involve user interaction. It might be appropriate to
37    // indicate this in the UI.
38    STATE_NOT_INSTALLED = 0,
39    // The daemon is being installed.
40    STATE_INSTALLING = 1,
41    // The daemon is installed but not running. Call Start to start it.
42    STATE_STOPPED = 2,
43    // The daemon process is starting.
44    STATE_STARTING = 3,
45    // The daemon process is running. Call Start again to change the PIN or
46    // Stop to stop it.
47    STATE_STARTED = 4,
48    // The daemon process is stopping.
49    STATE_STOPPING = 5,
50    // The state cannot be determined. This could indicate that the plugin
51    // has not been provided with sufficient information, for example, the
52    // user for which to query state on a multi-user system.
53    STATE_UNKNOWN = 6
54  };
55
56  // Enum used for completion callback.
57  enum AsyncResult {
58    RESULT_OK = 0,
59
60    // The operation has FAILED.
61    RESULT_FAILED = 1,
62
63    // User has cancelled the action (e.g. rejected UAC prompt).
64    // TODO(sergeyu): Current implementations don't return this value.
65    RESULT_CANCELLED = 2,
66
67    // Failed to access host directory.
68    RESULT_FAILED_DIRECTORY = 3
69
70    // TODO(sergeyu): Add more error codes when we know how to handle
71    // them in the webapp.
72  };
73
74  // Callback type for GetConfig(). If the host is configured then a dictionary
75  // is returned containing host_id and xmpp_login, with security-sensitive
76  // fields filtered out. An empty dictionary is returned if the host is not
77  // configured, and NULL if the configuration is corrupt or cannot be read.
78  typedef base::Callback<void (scoped_ptr<base::DictionaryValue> config)>
79      GetConfigCallback;
80
81  // Callback used for asynchronous operations, e.g. when
82  // starting/stopping the service.
83  typedef base::Callback<void (AsyncResult result)> CompletionCallback;
84
85  // Callback type for GetVersion().
86  typedef base::Callback<void (const std::string&)> GetVersionCallback;
87
88  struct UsageStatsConsent {
89    // Indicates whether crash dump reporting is supported by the host.
90    bool supported;
91
92    // Indicates if crash dump reporting is allowed by the user.
93    bool allowed;
94
95    // Carries information whether the crash dump reporting is controlled by
96    // policy.
97    bool set_by_policy;
98  };
99
100  // Callback type for GetUsageStatsConsent().
101  typedef base::Callback<void (const UsageStatsConsent&)>
102      GetUsageStatsConsentCallback;
103
104  // Interface representing the platform-spacific back-end. Most of its methods
105  // are blocking and should be called on a background thread. There are two
106  // exceptions:
107  //   - GetState() is synchronous and called on the UI thread. It should avoid
108  //         accessing any data members of the implementation.
109  //   - SetConfigAndStart(), UpdateConfig() and Stop() indicate completion via
110  //         a callback. There methods can be long running and should be caled
111  //         on a background thread.
112  class Delegate {
113   public:
114    virtual ~Delegate() {}
115
116    // Return the "installed/running" state of the daemon process. This method
117    // should avoid accessing any data members of the implementation.
118    virtual State GetState() = 0;
119
120    // Queries current host configuration. Any values that might be security
121    // sensitive have been filtered out.
122    virtual scoped_ptr<base::DictionaryValue> GetConfig() = 0;
123
124    // Download and install the host component. |done| is invoked on the
125    // calling thread when the operation is completed.
126    virtual void InstallHost(const CompletionCallback& done) = 0;
127
128    // Starts the daemon process. This may require that the daemon be
129    // downloaded and installed. |done| is invoked on the calling thread when
130    // the operation is completed.
131    virtual void SetConfigAndStart(
132        scoped_ptr<base::DictionaryValue> config,
133        bool consent,
134        const CompletionCallback& done) = 0;
135
136    // Updates current host configuration with the values specified in
137    // |config|. Any value in the existing configuration that isn't specified in
138    // |config| is preserved. |config| must not contain host_id or xmpp_login
139    // values, because implementations of this method cannot change them. |done|
140    // is invoked on the calling thread when the operation is completed.
141    virtual void UpdateConfig(
142        scoped_ptr<base::DictionaryValue> config,
143        const CompletionCallback& done) = 0;
144
145    // Stops the daemon process. |done| is invoked on the calling thread when
146    // the operation is completed.
147    virtual void Stop(const CompletionCallback& done) = 0;
148
149    // Caches the native handle of the plugin window so it can be used to focus
150    // elevation prompts properly.
151    virtual void SetWindow(void* window_handle) = 0;
152
153    // Get the version of the daemon as a dotted decimal string of the form
154    // major.minor.build.patch, if it is installed, or "" otherwise.
155    virtual std::string GetVersion() = 0;
156
157    // Get the user's consent to crash reporting.
158    virtual UsageStatsConsent GetUsageStatsConsent() = 0;
159  };
160
161  static scoped_refptr<DaemonController> Create();
162
163  explicit DaemonController(scoped_ptr<Delegate> delegate);
164
165  // Return the "installed/running" state of the daemon process.
166  //
167  // TODO(sergeyu): This method is called synchronously from the
168  // webapp. In most cases it requires IO operations, so it may block
169  // the user interface. Replace it with asynchronous notifications,
170  // e.g. with StartStateNotifications()/StopStateNotifications() methods.
171  State GetState();
172
173  // Queries current host configuration. The |done| is called
174  // after the configuration is read, and any values that might be security
175  // sensitive have been filtered out.
176  void GetConfig(const GetConfigCallback& done);
177
178  // Download and install the host component. |done| is called when the
179  // operation is finished or fails.
180  void InstallHost(const CompletionCallback& done);
181
182  // Start the daemon process. This may require that the daemon be
183  // downloaded and installed. |done| is called when the
184  // operation is finished or fails.
185  //
186  // TODO(sergeyu): This method writes config and starts the host -
187  // these two steps are merged for simplicity. Consider splitting it
188  // into SetConfig() and Start() once we have basic host setup flow
189  // working.
190  void SetConfigAndStart(scoped_ptr<base::DictionaryValue> config,
191                         bool consent,
192                         const CompletionCallback& done);
193
194  // Updates current host configuration with the values specified in
195  // |config|. Changes must take effect before the call completes.
196  // Any value in the existing configuration that isn't specified in |config|
197  // is preserved. |config| must not contain host_id or xmpp_login values,
198  // because implementations of this method cannot change them.
199  void UpdateConfig(scoped_ptr<base::DictionaryValue> config,
200                    const CompletionCallback& done);
201
202  // Stop the daemon process. It is permitted to call Stop while the daemon
203  // process is being installed, in which case the installation should be
204  // aborted if possible; if not then it is sufficient to ensure that the
205  // daemon process is not started automatically upon successful installation.
206  // As with Start, Stop may return before the operation is complete--poll
207  // GetState until the state is STATE_STOPPED.
208  void Stop(const CompletionCallback& done);
209
210  // Caches the native handle of the plugin window so it can be used to focus
211  // elevation prompts properly.
212  void SetWindow(void* window_handle);
213
214  // Get the version of the daemon as a dotted decimal string of the form
215  // major.minor.build.patch, if it is installed, or "" otherwise.
216  void GetVersion(const GetVersionCallback& done);
217
218  // Get the user's consent to crash reporting.
219  void GetUsageStatsConsent(const GetUsageStatsConsentCallback& done);
220
221 private:
222  friend class base::RefCountedThreadSafe<DaemonController>;
223  virtual ~DaemonController();
224
225  // Blocking helper methods used to call the delegate.
226  void DoGetConfig(const GetConfigCallback& done);
227  void DoInstallHost(const CompletionCallback& done);
228  void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config,
229                           bool consent,
230                           const CompletionCallback& done);
231  void DoUpdateConfig(scoped_ptr<base::DictionaryValue> config,
232                      const CompletionCallback& done);
233  void DoStop(const CompletionCallback& done);
234  void DoSetWindow(void* window_handle, const base::Closure& done);
235  void DoGetVersion(const GetVersionCallback& done);
236  void DoGetUsageStatsConsent(const GetUsageStatsConsentCallback& done);
237
238  // "Trampoline" callbacks that schedule the next pending request and then
239  // invoke the original caller-supplied callback.
240  void InvokeCompletionCallbackAndScheduleNext(
241      const CompletionCallback& done,
242      AsyncResult result);
243  void InvokeConfigCallbackAndScheduleNext(
244      const GetConfigCallback& done,
245      scoped_ptr<base::DictionaryValue> config);
246  void InvokeConsentCallbackAndScheduleNext(
247      const GetUsageStatsConsentCallback& done,
248      const UsageStatsConsent& consent);
249  void InvokeVersionCallbackAndScheduleNext(
250      const GetVersionCallback& done,
251      const std::string& version);
252
253  // Queue management methods.
254  void ScheduleNext();
255  void ServiceOrQueueRequest(const base::Closure& request);
256  void ServiceNextRequest();
257
258  // Task runner on which all public methods of this class should be called.
259  scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
260
261  // Task runner used to run blocking calls to the delegate. A single thread
262  // task runner is used to guarantee that one method of the delegate is
263  // called at a time.
264  scoped_refptr<AutoThreadTaskRunner> delegate_task_runner_;
265
266  scoped_ptr<AutoThread> delegate_thread_;
267
268  scoped_ptr<Delegate> delegate_;
269
270  std::queue<base::Closure> pending_requests_;
271
272  DISALLOW_COPY_AND_ASSIGN(DaemonController);
273};
274
275}  // namespace remoting
276
277#endif  // REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_
278