blob: 9e8a8b05719b9b7d90bc832c2b2ed4f8eb13ef1a [file] [log] [blame]
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07001// Copyright 2014 The Chromium OS 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
Alex Vakulenkob3aac252014-05-07 17:35:24 -07005#ifndef BUFFET_DEVICE_REGISTRATION_INFO_H_
6#define BUFFET_DEVICE_REGISTRATION_INFO_H_
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07007
Alex Vakulenko3cb466c2014-04-15 11:36:32 -07008#include <map>
9#include <memory>
Alex Vakulenko5841c302014-07-23 10:49:49 -070010#include <string>
Alex Vakulenkob3aac252014-05-07 17:35:24 -070011#include <utility>
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070012#include <vector>
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070013
Alex Vakulenko132617a2014-09-04 08:59:43 -070014#include <base/macros.h>
Christopher Wileycd419662015-02-06 17:51:43 -080015#include <base/memory/weak_ptr.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070016#include <base/time/time.h>
Christopher Wiley34eae042015-03-18 10:25:08 -070017#include <base/timer/timer.h>
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070018#include <chromeos/data_encoding.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070019#include <chromeos/errors/error.h>
20#include <chromeos/http/http_transport.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070021
Christopher Wiley583d64b2015-03-24 14:30:17 -070022#include "buffet/buffet_config.h"
Alex Vakulenko9ea5a322015-04-17 15:35:34 -070023#include "buffet/commands/command_manager.h"
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070024#include "buffet/notification/notification_channel.h"
25#include "buffet/notification/notification_delegate.h"
Alex Vakulenkod05725f2015-05-27 15:48:19 -070026#include "buffet/notification/pull_channel.h"
Christopher Wileyc900e482015-02-15 15:42:04 -080027#include "buffet/registration_status.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070028#include "buffet/storage_interface.h"
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070029
30namespace base {
Vitaly Buka6ca3ad62015-03-11 17:03:23 -070031class DictionaryValue;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070032} // namespace base
33
Anton Muhin332df192014-11-22 05:59:14 +040034namespace chromeos {
35class KeyValueStore;
36} // namespace chromeos
37
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070038namespace buffet {
39
Alex Vakulenko07216fe2014-09-19 15:31:09 -070040class StateManager;
Alex Vakulenko1f30a622014-07-23 11:13:15 -070041
Alex Vakulenkob3aac252014-05-07 17:35:24 -070042extern const char kErrorDomainOAuth2[];
43extern const char kErrorDomainGCD[];
44extern const char kErrorDomainGCDServer[];
Alex Vakulenkob3aac252014-05-07 17:35:24 -070045
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070046// The DeviceRegistrationInfo class represents device registration information.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070047class DeviceRegistrationInfo : public NotificationDelegate {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070048 public:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070049 using OnRegistrationChangedCallback =
50 base::Callback<void(RegistrationStatus)>;
Christopher Wileye0fdeee2015-02-07 18:29:32 -080051
Alex Vakulenkocca20932014-08-20 17:35:12 -070052 DeviceRegistrationInfo(
53 const std::shared_ptr<CommandManager>& command_manager,
Anton Muhinb8315622014-11-20 03:17:05 +040054 const std::shared_ptr<StateManager>& state_manager,
Vitaly Buka867b0882015-04-16 10:03:26 -070055 std::unique_ptr<BuffetConfig> config,
Alex Vakulenkocca20932014-08-20 17:35:12 -070056 const std::shared_ptr<chromeos::http::Transport>& transport,
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070057 bool notifications_enabled);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070058
Alex Vakulenko534a3122015-05-22 15:48:53 -070059 ~DeviceRegistrationInfo() override;
Anton Muhin332df192014-11-22 05:59:14 +040060
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070061 // Add callback to listen for changes in registration status.
62 void AddOnRegistrationChangedCallback(
63 const OnRegistrationChangedCallback& callback);
Christopher Wileyc900e482015-02-15 15:42:04 -080064
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070065 // Returns the authorization HTTP header that can be used to talk
66 // to GCD server for authenticated device communication.
Alex Vakulenko8e34d392014-04-29 11:02:56 -070067 // Make sure ValidateAndRefreshAccessToken() is called before this call.
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070068 std::pair<std::string, std::string> GetAuthorizationHeader() const;
69
70 // Returns the GCD service request URL. If |subpath| is specified, it is
71 // appended to the base URL which is normally
72 // https://www.googleapis.com/clouddevices/v1/".
73 // If |params| are specified, each key-value pair is formatted using
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070074 // chromeos::data_encoding::WebParamsEncode() and appended to URL as a query
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070075 // string.
76 // So, calling:
77 // GetServiceURL("ticket", {{"key","apiKey"}})
78 // will return something like:
79 // https://www.googleapis.com/clouddevices/v1/ticket?key=apiKey
80 std::string GetServiceURL(
81 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070082 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070083
84 // Returns a service URL to access the registered device on GCD server.
85 // The base URL used to construct the full URL looks like this:
86 // https://www.googleapis.com/clouddevices/v1/devices/<device_id>/
87 std::string GetDeviceURL(
88 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070089 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070090
91 // Similar to GetServiceURL, GetOAuthURL() returns a URL of OAuth 2.0 server.
92 // The base URL used is https://accounts.google.com/o/oauth2/.
93 std::string GetOAuthURL(
94 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070095 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070096
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -070097 // Starts GCD device if credentials available.
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070098 void Start();
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070099
Nathan Bullock5e022a32015-04-08 15:13:07 -0400100 // Checks whether we have credentials generated during registration.
101 bool HaveRegistrationCredentials(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700102
103 // Gets the full device description JSON object, or nullptr if
104 // the device is not registered or communication failure.
Vitaly Buka6ca3ad62015-03-11 17:03:23 -0700105 std::unique_ptr<base::DictionaryValue> GetDeviceInfo(
106 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700107
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400108 // Registers the device.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400109 // Returns a device ID on success.
Vitaly Bukacad2e332015-05-14 23:33:32 -0700110 std::string RegisterDevice(const std::string& ticket_id,
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700111 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700112
Anton Muhin59755522014-11-05 21:30:12 +0400113 // Updates a command.
Anton Muhin59755522014-11-05 21:30:12 +0400114 void UpdateCommand(const std::string& command_id,
Alex Vakulenkob211c102015-04-21 11:43:23 -0700115 const base::DictionaryValue& command_patch,
116 const base::Closure& on_success,
117 const base::Closure& on_error);
Anton Muhin59755522014-11-05 21:30:12 +0400118
Vitaly Bukafa947062015-04-17 00:41:31 -0700119 // Updates basic device information.
120 bool UpdateDeviceInfo(const std::string& name,
121 const std::string& description,
122 const std::string& location,
123 chromeos::ErrorPtr* error);
124
Vitaly Buka2f7efdb2015-05-27 16:00:21 -0700125 // Updates base device config.
126 bool UpdateBaseConfig(const std::string& anonymous_access_role,
127 bool local_discovery_enabled,
128 bool local_pairing_enabled,
129 chromeos::ErrorPtr* error);
130
Vitaly Bukaff81db62015-05-14 21:25:45 -0700131 // Updates GCD service configuration. Usually for testing.
132 bool UpdateServiceConfig(const std::string& client_id,
133 const std::string& client_secret,
134 const std::string& api_key,
135 const std::string& oauth_url,
136 const std::string& service_url,
137 chromeos::ErrorPtr* error);
138
Vitaly Buka72410b22015-05-13 13:48:59 -0700139 const BuffetConfig& GetConfig() const { return *config_; }
140
141 base::WeakPtr<DeviceRegistrationInfo> AsWeakPtr() {
142 return weak_factory_.GetWeakPtr();
143 }
144
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700145 private:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700146 friend class DeviceRegistrationInfoTest;
147
Christopher Wileyba983c82015-03-05 16:32:23 -0800148 // Cause DeviceRegistrationInfo to attempt to StartDevice on its own later.
149 void ScheduleStartDevice(const base::TimeDelta& later);
150
151 // Starts device execution.
152 // Device will do required start up chores and then start to listen
153 // to new commands.
154 // TODO(antonm): Consider moving into some other class.
155 void StartDevice(chromeos::ErrorPtr* error,
156 const base::TimeDelta& retry_delay);
157
Nathan Bullock5e022a32015-04-08 15:13:07 -0400158 // Checks for the valid device registration as well as refreshes
159 // the device access token, if available.
160 bool CheckRegistration(chromeos::ErrorPtr* error);
Christopher Wileyc900e482015-02-15 15:42:04 -0800161
Nathan Bullock5e022a32015-04-08 15:13:07 -0400162 // If we currently have an access token and it doesn't look like it
David Zeuthen390d1912015-03-03 14:54:48 -0500163 // has expired yet, returns true immediately. Otherwise calls
164 // RefreshAccessToken().
165 bool MaybeRefreshAccessToken(chromeos::ErrorPtr* error);
166
167 // Forcibly refreshes the access token.
168 bool RefreshAccessToken(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700169
Alex Vakulenko6b028ae2015-05-29 09:38:59 -0700170 // Calls RefreshAccessToken(nullptr). Used as a closure.
171 void RunRefreshAccessToken();
172
Nathan Bullock24d189f2015-02-26 13:09:18 -0500173 // Parse the OAuth response, and sets registration status to
174 // kInvalidCredentials if our registration is no longer valid.
175 std::unique_ptr<base::DictionaryValue> ParseOAuthResponse(
Alex Vakulenkof71cca62015-04-09 15:17:17 -0700176 chromeos::http::Response* response, chromeos::ErrorPtr* error);
Nathan Bullock24d189f2015-02-26 13:09:18 -0500177
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700178 // This attempts to open a notification channel. The channel needs to be
Nathan Bullockbea91132015-02-19 09:13:33 -0500179 // restarted anytime the access_token is refreshed.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700180 void StartNotificationChannel();
Nathan Bullockbea91132015-02-19 09:13:33 -0500181
Anton Muhinac661ab2014-10-03 20:29:48 +0400182 using CloudRequestCallback =
183 base::Callback<void(const base::DictionaryValue&)>;
Alex Vakulenko0357c032015-01-06 16:32:31 -0800184 using CloudRequestErrorCallback =
185 base::Callback<void(const chromeos::Error* error)>;
Anton Muhinac661ab2014-10-03 20:29:48 +0400186
187 // Do a HTTPS request to cloud services.
188 // Handles many cases like reauthorization, 5xx HTTP response codes
189 // and device removal. It is a recommended way to do cloud API
190 // requests.
191 // TODO(antonm): Consider moving into some other class.
192 void DoCloudRequest(
Anton Muhin233d2ee2014-10-22 15:16:24 +0400193 const std::string& method,
Anton Muhinac661ab2014-10-03 20:29:48 +0400194 const std::string& url,
195 const base::DictionaryValue* body,
Alex Vakulenko0357c032015-01-06 16:32:31 -0800196 const CloudRequestCallback& success_callback,
197 const CloudRequestErrorCallback& error_callback);
Anton Muhinac661ab2014-10-03 20:29:48 +0400198
Christopher Wileyba983c82015-03-05 16:32:23 -0800199 void UpdateDeviceResource(const base::Closure& on_success,
200 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400201
Christopher Wileyba983c82015-03-05 16:32:23 -0800202 void FetchCommands(
203 const base::Callback<void(const base::ListValue&)>& on_success,
204 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400205
Alex Vakulenkod05725f2015-05-27 15:48:19 -0700206 // Processes the command list that is fetched from the server on connection.
207 // Aborts commands which are in transitional states and publishes queued
208 // commands which are queued.
209 void ProcessInitialCommandList(const base::ListValue& commands);
Anton Muhinc635c592014-10-28 21:48:08 +0400210
Anton Muhind07e2062014-10-27 10:53:29 +0400211 void PublishCommands(const base::ListValue& commands);
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700212 void PublishCommand(const base::DictionaryValue& command);
Anton Muhind07e2062014-10-27 10:53:29 +0400213
Anton Muhinb8315622014-11-20 03:17:05 +0400214 void PublishStateUpdates();
215
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700216 // If unrecoverable error occurred (e.g. error parsing command instance),
217 // notify the server that the command is aborted by the device.
218 void NotifyCommandAborted(const std::string& command_id,
219 chromeos::ErrorPtr error);
220
221 // When NotifyCommandAborted() fails, RetryNotifyCommandAborted() schedules
222 // a retry attempt.
223 void RetryNotifyCommandAborted(const std::string& command_id,
224 chromeos::ErrorPtr error);
225
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700226 // Builds Cloud API devices collection REST resource which matches
Anton Muhind8d32162014-10-02 20:37:00 +0400227 // current state of the device including command definitions
228 // for all supported commands and current device state.
229 std::unique_ptr<base::DictionaryValue> BuildDeviceResource(
230 chromeos::ErrorPtr* error);
231
Christopher Wileyc900e482015-02-15 15:42:04 -0800232 void SetRegistrationStatus(RegistrationStatus new_status);
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700233 void SetDeviceId(const std::string& device_id);
Christopher Wileyc900e482015-02-15 15:42:04 -0800234
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700235 // Callback called when command definitions are changed to re-publish new CDD.
236 void OnCommandDefsChanged();
Vitaly Bukac903d282015-05-26 17:03:08 -0700237 void OnStateChanged();
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700238
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700239 // Overrides from NotificationDelegate
240 void OnConnected(const std::string& channel_name) override;
241 void OnDisconnected() override;
242 void OnPermanentFailure() override;
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700243 void OnCommandCreated(const base::DictionaryValue& command) override;
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700244
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500245 // Transient data
246 std::string access_token_;
247 base::Time access_token_expiration_;
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500248
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700249 // HTTP transport used for communications.
Alex Vakulenkocca20932014-08-20 17:35:12 -0700250 std::shared_ptr<chromeos::http::Transport> transport_;
Alex Vakulenko1f30a622014-07-23 11:13:15 -0700251 // Global command manager.
252 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700253 // Device state manager.
Anton Muhinb8315622014-11-20 03:17:05 +0400254 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700255
Vitaly Buka867b0882015-04-16 10:03:26 -0700256 std::unique_ptr<BuffetConfig> config_;
Anton Muhin332df192014-11-22 05:59:14 +0400257
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700258 const bool notifications_enabled_;
259 std::unique_ptr<NotificationChannel> primary_notification_channel_;
Alex Vakulenkod05725f2015-05-27 15:48:19 -0700260 std::unique_ptr<PullChannel> pull_channel_;
261 NotificationChannel* current_notification_channel_{nullptr};
Alex Vakulenko6b028ae2015-05-29 09:38:59 -0700262 bool notification_channel_starting_{false};
Christopher Wileyd732bd02015-04-07 11:11:18 -0700263
Christopher Wileyc900e482015-02-15 15:42:04 -0800264 // Tracks our current registration status.
Vitaly Bukab055f152015-03-12 13:41:43 -0700265 RegistrationStatus registration_status_{RegistrationStatus::kUnconfigured};
Christopher Wileyc900e482015-02-15 15:42:04 -0800266
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700267 std::vector<OnRegistrationChangedCallback> on_registration_changed_;
268
Christopher Wileycd419662015-02-06 17:51:43 -0800269 base::WeakPtrFactory<DeviceRegistrationInfo> weak_factory_{this};
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700270 DISALLOW_COPY_AND_ASSIGN(DeviceRegistrationInfo);
271};
272
273} // namespace buffet
274
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700275#endif // BUFFET_DEVICE_REGISTRATION_INFO_H_