// 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 REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_
#define REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_
#include <queue>
#include <string>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
namespace base {
class DictionaryValue;
class SingleThreadTaskRunner;
} // namespace base
namespace remoting {
class AutoThread;
class AutoThreadTaskRunner;
class DaemonController : public base::RefCountedThreadSafe<DaemonController> {
public:
// Note that these enumeration values are duplicated in host_controller.js and
// must be kept in sync.
enum State {
// Placeholder state for platforms on which the daemon process is not
// implemented. The web-app will not show the corresponding UI. This value
// will eventually be deprecated or removed.
STATE_NOT_IMPLEMENTED = -1,
// The daemon is not installed. This is functionally equivalent to
// STATE_STOPPED, but the start method is expected to be significantly
// slower, and might involve user interaction. It might be appropriate to
// indicate this in the UI.
STATE_NOT_INSTALLED = 0,
// The daemon is being installed.
STATE_INSTALLING = 1,
// The daemon is installed but not running. Call Start to start it.
STATE_STOPPED = 2,
// The daemon process is starting.
STATE_STARTING = 3,
// The daemon process is running. Call Start again to change the PIN or
// Stop to stop it.
STATE_STARTED = 4,
// The daemon process is stopping.
STATE_STOPPING = 5,
// The state cannot be determined. This could indicate that the plugin
// has not been provided with sufficient information, for example, the
// user for which to query state on a multi-user system.
STATE_UNKNOWN = 6
};
// Enum used for completion callback.
enum AsyncResult {
RESULT_OK = 0,
// The operation has FAILED.
RESULT_FAILED = 1,
// User has cancelled the action (e.g. rejected UAC prompt).
// TODO(sergeyu): Current implementations don't return this value.
RESULT_CANCELLED = 2,
// Failed to access host directory.
RESULT_FAILED_DIRECTORY = 3
// TODO(sergeyu): Add more error codes when we know how to handle
// them in the webapp.
};
// Callback type for GetConfig(). If the host is configured then a dictionary
// is returned containing host_id and xmpp_login, with security-sensitive
// fields filtered out. An empty dictionary is returned if the host is not
// configured, and NULL if the configuration is corrupt or cannot be read.
typedef base::Callback<void (scoped_ptr<base::DictionaryValue> config)>
GetConfigCallback;
// Callback used for asynchronous operations, e.g. when
// starting/stopping the service.
typedef base::Callback<void (AsyncResult result)> CompletionCallback;
// Callback type for GetVersion().
typedef base::Callback<void (const std::string&)> GetVersionCallback;
struct UsageStatsConsent {
// Indicates whether crash dump reporting is supported by the host.
bool supported;
// Indicates if crash dump reporting is allowed by the user.
bool allowed;
// Carries information whether the crash dump reporting is controlled by
// policy.
bool set_by_policy;
};
// Callback type for GetUsageStatsConsent().
typedef base::Callback<void (const UsageStatsConsent&)>
GetUsageStatsConsentCallback;
// Interface representing the platform-spacific back-end. Most of its methods
// are blocking and should be called on a background thread. There are two
// exceptions:
// - GetState() is synchronous and called on the UI thread. It should avoid
// accessing any data members of the implementation.
// - SetConfigAndStart(), UpdateConfig() and Stop() indicate completion via
// a callback. There methods can be long running and should be caled
// on a background thread.
class Delegate {
public:
virtual ~Delegate() {}
// Return the "installed/running" state of the daemon process. This method
// should avoid accessing any data members of the implementation.
virtual State GetState() = 0;
// Queries current host configuration. Any values that might be security
// sensitive have been filtered out.
virtual scoped_ptr<base::DictionaryValue> GetConfig() = 0;
// Download and install the host component. |done| is invoked on the
// calling thread when the operation is completed.
virtual void InstallHost(const CompletionCallback& done) = 0;
// Starts the daemon process. This may require that the daemon be
// downloaded and installed. |done| is invoked on the calling thread when
// the operation is completed.
virtual void SetConfigAndStart(
scoped_ptr<base::DictionaryValue> config,
bool consent,
const CompletionCallback& done) = 0;
// Updates current host configuration with the values specified in
// |config|. Any value in the existing configuration that isn't specified in
// |config| is preserved. |config| must not contain host_id or xmpp_login
// values, because implementations of this method cannot change them. |done|
// is invoked on the calling thread when the operation is completed.
virtual void UpdateConfig(
scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done) = 0;
// Stops the daemon process. |done| is invoked on the calling thread when
// the operation is completed.
virtual void Stop(const CompletionCallback& done) = 0;
// Caches the native handle of the plugin window so it can be used to focus
// elevation prompts properly.
virtual void SetWindow(void* window_handle) = 0;
// Get the version of the daemon as a dotted decimal string of the form
// major.minor.build.patch, if it is installed, or "" otherwise.
virtual std::string GetVersion() = 0;
// Get the user's consent to crash reporting.
virtual UsageStatsConsent GetUsageStatsConsent() = 0;
};
static scoped_refptr<DaemonController> Create();
explicit DaemonController(scoped_ptr<Delegate> delegate);
// Return the "installed/running" state of the daemon process.
//
// TODO(sergeyu): This method is called synchronously from the
// webapp. In most cases it requires IO operations, so it may block
// the user interface. Replace it with asynchronous notifications,
// e.g. with StartStateNotifications()/StopStateNotifications() methods.
State GetState();
// Queries current host configuration. The |done| is called
// after the configuration is read, and any values that might be security
// sensitive have been filtered out.
void GetConfig(const GetConfigCallback& done);
// Download and install the host component. |done| is called when the
// operation is finished or fails.
void InstallHost(const CompletionCallback& done);
// Start the daemon process. This may require that the daemon be
// downloaded and installed. |done| is called when the
// operation is finished or fails.
//
// TODO(sergeyu): This method writes config and starts the host -
// these two steps are merged for simplicity. Consider splitting it
// into SetConfig() and Start() once we have basic host setup flow
// working.
void SetConfigAndStart(scoped_ptr<base::DictionaryValue> config,
bool consent,
const CompletionCallback& done);
// Updates current host configuration with the values specified in
// |config|. Changes must take effect before the call completes.
// Any value in the existing configuration that isn't specified in |config|
// is preserved. |config| must not contain host_id or xmpp_login values,
// because implementations of this method cannot change them.
void UpdateConfig(scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done);
// Stop the daemon process. It is permitted to call Stop while the daemon
// process is being installed, in which case the installation should be
// aborted if possible; if not then it is sufficient to ensure that the
// daemon process is not started automatically upon successful installation.
// As with Start, Stop may return before the operation is complete--poll
// GetState until the state is STATE_STOPPED.
void Stop(const CompletionCallback& done);
// Caches the native handle of the plugin window so it can be used to focus
// elevation prompts properly.
void SetWindow(void* window_handle);
// Get the version of the daemon as a dotted decimal string of the form
// major.minor.build.patch, if it is installed, or "" otherwise.
void GetVersion(const GetVersionCallback& done);
// Get the user's consent to crash reporting.
void GetUsageStatsConsent(const GetUsageStatsConsentCallback& done);
private:
friend class base::RefCountedThreadSafe<DaemonController>;
virtual ~DaemonController();
// Blocking helper methods used to call the delegate.
void DoGetConfig(const GetConfigCallback& done);
void DoInstallHost(const CompletionCallback& done);
void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config,
bool consent,
const CompletionCallback& done);
void DoUpdateConfig(scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done);
void DoStop(const CompletionCallback& done);
void DoSetWindow(void* window_handle, const base::Closure& done);
void DoGetVersion(const GetVersionCallback& done);
void DoGetUsageStatsConsent(const GetUsageStatsConsentCallback& done);
// "Trampoline" callbacks that schedule the next pending request and then
// invoke the original caller-supplied callback.
void InvokeCompletionCallbackAndScheduleNext(
const CompletionCallback& done,
AsyncResult result);
void InvokeConfigCallbackAndScheduleNext(
const GetConfigCallback& done,
scoped_ptr<base::DictionaryValue> config);
void InvokeConsentCallbackAndScheduleNext(
const GetUsageStatsConsentCallback& done,
const UsageStatsConsent& consent);
void InvokeVersionCallbackAndScheduleNext(
const GetVersionCallback& done,
const std::string& version);
// Queue management methods.
void ScheduleNext();
void ServiceOrQueueRequest(const base::Closure& request);
void ServiceNextRequest();
// Task runner on which all public methods of this class should be called.
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
// Task runner used to run blocking calls to the delegate. A single thread
// task runner is used to guarantee that one method of the delegate is
// called at a time.
scoped_refptr<AutoThreadTaskRunner> delegate_task_runner_;
scoped_ptr<AutoThread> delegate_thread_;
scoped_ptr<Delegate> delegate_;
std::queue<base::Closure> pending_requests_;
DISALLOW_COPY_AND_ASSIGN(DaemonController);
};
} // namespace remoting
#endif // REMOTING_HOST_SETUP_DAEMON_CONTROLLER_H_