blob: ed96db00c273f3e2c8c8843c6a6003ff1818700f [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 Vakulenko266b2b12015-06-19 11:01:42 -070014#include <base/callback.h>
Alex Vakulenko132617a2014-09-04 08:59:43 -070015#include <base/macros.h>
Christopher Wileycd419662015-02-06 17:51:43 -080016#include <base/memory/weak_ptr.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070017#include <base/time/time.h>
Christopher Wiley34eae042015-03-18 10:25:08 -070018#include <base/timer/timer.h>
Alex Vakulenko266b2b12015-06-19 11:01:42 -070019#include <chromeos/backoff_entry.h>
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070020#include <chromeos/data_encoding.h>
Alex Vakulenkoa8b95bc2014-08-27 11:00:57 -070021#include <chromeos/errors/error.h>
22#include <chromeos/http/http_transport.h>
Alex Vakulenkoa3062c52014-04-21 17:05:51 -070023
Christopher Wiley583d64b2015-03-24 14:30:17 -070024#include "buffet/buffet_config.h"
Alex Vakulenko9ea5a322015-04-17 15:35:34 -070025#include "buffet/commands/command_manager.h"
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070026#include "buffet/notification/notification_channel.h"
27#include "buffet/notification/notification_delegate.h"
Alex Vakulenkod05725f2015-05-27 15:48:19 -070028#include "buffet/notification/pull_channel.h"
Christopher Wileyc900e482015-02-15 15:42:04 -080029#include "buffet/registration_status.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070030#include "buffet/storage_interface.h"
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070031
32namespace base {
Vitaly Buka6ca3ad62015-03-11 17:03:23 -070033class DictionaryValue;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070034} // namespace base
35
Anton Muhin332df192014-11-22 05:59:14 +040036namespace chromeos {
37class KeyValueStore;
38} // namespace chromeos
39
Vitaly Buka63cc3d22015-06-23 20:11:36 -070040namespace privetd {
41class ShillClient;
42}
43
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070044namespace buffet {
45
Alex Vakulenko07216fe2014-09-19 15:31:09 -070046class StateManager;
Alex Vakulenko1f30a622014-07-23 11:13:15 -070047
Alex Vakulenkob3aac252014-05-07 17:35:24 -070048extern const char kErrorDomainOAuth2[];
49extern const char kErrorDomainGCD[];
50extern const char kErrorDomainGCDServer[];
Alex Vakulenkob3aac252014-05-07 17:35:24 -070051
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070052// The DeviceRegistrationInfo class represents device registration information.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070053class DeviceRegistrationInfo : public NotificationDelegate {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070054 public:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070055 using OnRegistrationChangedCallback =
56 base::Callback<void(RegistrationStatus)>;
Alex Vakulenko266b2b12015-06-19 11:01:42 -070057 using CloudRequestCallback =
58 base::Callback<void(const base::DictionaryValue&)>;
59 using CloudRequestErrorCallback =
60 base::Callback<void(const chromeos::Error* error)>;
Christopher Wileye0fdeee2015-02-07 18:29:32 -080061
Alex Vakulenkocca20932014-08-20 17:35:12 -070062 DeviceRegistrationInfo(
63 const std::shared_ptr<CommandManager>& command_manager,
Anton Muhinb8315622014-11-20 03:17:05 +040064 const std::shared_ptr<StateManager>& state_manager,
Vitaly Buka867b0882015-04-16 10:03:26 -070065 std::unique_ptr<BuffetConfig> config,
Alex Vakulenkocca20932014-08-20 17:35:12 -070066 const std::shared_ptr<chromeos::http::Transport>& transport,
Vitaly Buka63cc3d22015-06-23 20:11:36 -070067 bool notifications_enabled,
68 privetd::ShillClient* shill_client);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070069
Alex Vakulenko534a3122015-05-22 15:48:53 -070070 ~DeviceRegistrationInfo() override;
Anton Muhin332df192014-11-22 05:59:14 +040071
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070072 // Add callback to listen for changes in registration status.
73 void AddOnRegistrationChangedCallback(
74 const OnRegistrationChangedCallback& callback);
Christopher Wileyc900e482015-02-15 15:42:04 -080075
Vitaly Buka7ab89ff2015-06-09 22:11:40 -070076 // Add callback to listen for changes in config.
77 void AddOnConfigChangedCallback(
78 const BuffetConfig::OnChangedCallback& callback);
79
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070080 // Returns the authorization HTTP header that can be used to talk
81 // to GCD server for authenticated device communication.
Alex Vakulenko8e34d392014-04-29 11:02:56 -070082 // Make sure ValidateAndRefreshAccessToken() is called before this call.
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070083 std::pair<std::string, std::string> GetAuthorizationHeader() const;
84
85 // Returns the GCD service request URL. If |subpath| is specified, it is
86 // appended to the base URL which is normally
87 // https://www.googleapis.com/clouddevices/v1/".
88 // If |params| are specified, each key-value pair is formatted using
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070089 // chromeos::data_encoding::WebParamsEncode() and appended to URL as a query
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070090 // string.
91 // So, calling:
92 // GetServiceURL("ticket", {{"key","apiKey"}})
93 // will return something like:
94 // https://www.googleapis.com/clouddevices/v1/ticket?key=apiKey
95 std::string GetServiceURL(
96 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070097 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070098
99 // Returns a service URL to access the registered device on GCD server.
100 // The base URL used to construct the full URL looks like this:
101 // https://www.googleapis.com/clouddevices/v1/devices/<device_id>/
102 std::string GetDeviceURL(
103 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -0700104 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700105
106 // Similar to GetServiceURL, GetOAuthURL() returns a URL of OAuth 2.0 server.
107 // The base URL used is https://accounts.google.com/o/oauth2/.
108 std::string GetOAuthURL(
109 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -0700110 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700111
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700112 // Starts GCD device if credentials available.
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700113 void Start();
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700114
Nathan Bullock5e022a32015-04-08 15:13:07 -0400115 // Checks whether we have credentials generated during registration.
116 bool HaveRegistrationCredentials(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700117
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700118 // Gets the full device description JSON object asynchronously.
119 // Passes the device info as the first argument to |callback|, or nullptr if
120 // the device is not registered or in case of communication failure.
121 void GetDeviceInfo(const CloudRequestCallback& success_callback,
122 const CloudRequestErrorCallback& error_callback);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700123
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400124 // Registers the device.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400125 // Returns a device ID on success.
Vitaly Bukacad2e332015-05-14 23:33:32 -0700126 std::string RegisterDevice(const std::string& ticket_id,
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700127 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700128
Anton Muhin59755522014-11-05 21:30:12 +0400129 // Updates a command.
Anton Muhin59755522014-11-05 21:30:12 +0400130 void UpdateCommand(const std::string& command_id,
Alex Vakulenkob211c102015-04-21 11:43:23 -0700131 const base::DictionaryValue& command_patch,
132 const base::Closure& on_success,
133 const base::Closure& on_error);
Anton Muhin59755522014-11-05 21:30:12 +0400134
Vitaly Bukafa947062015-04-17 00:41:31 -0700135 // Updates basic device information.
136 bool UpdateDeviceInfo(const std::string& name,
137 const std::string& description,
138 const std::string& location,
139 chromeos::ErrorPtr* error);
140
Vitaly Buka2f7efdb2015-05-27 16:00:21 -0700141 // Updates base device config.
142 bool UpdateBaseConfig(const std::string& anonymous_access_role,
143 bool local_discovery_enabled,
144 bool local_pairing_enabled,
145 chromeos::ErrorPtr* error);
146
Vitaly Bukaff81db62015-05-14 21:25:45 -0700147 // Updates GCD service configuration. Usually for testing.
148 bool UpdateServiceConfig(const std::string& client_id,
149 const std::string& client_secret,
150 const std::string& api_key,
151 const std::string& oauth_url,
152 const std::string& service_url,
153 chromeos::ErrorPtr* error);
154
Vitaly Bukab56872f2015-06-21 18:39:34 -0700155 // TODO(vitalybuka): remove getters and pass config to dependent code.
Vitaly Buka72410b22015-05-13 13:48:59 -0700156 const BuffetConfig& GetConfig() const { return *config_; }
Vitaly Bukab56872f2015-06-21 18:39:34 -0700157 BuffetConfig* GetMutableConfig() { return config_.get(); }
Vitaly Buka72410b22015-05-13 13:48:59 -0700158
159 base::WeakPtr<DeviceRegistrationInfo> AsWeakPtr() {
160 return weak_factory_.GetWeakPtr();
161 }
162
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700163 private:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700164 friend class DeviceRegistrationInfoTest;
165
Christopher Wileyba983c82015-03-05 16:32:23 -0800166 // Cause DeviceRegistrationInfo to attempt to StartDevice on its own later.
167 void ScheduleStartDevice(const base::TimeDelta& later);
168
169 // Starts device execution.
170 // Device will do required start up chores and then start to listen
171 // to new commands.
172 // TODO(antonm): Consider moving into some other class.
173 void StartDevice(chromeos::ErrorPtr* error,
174 const base::TimeDelta& retry_delay);
175
David Zeuthen390d1912015-03-03 14:54:48 -0500176 // Forcibly refreshes the access token.
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700177 void RefreshAccessToken(const base::Closure& success_callback,
178 const CloudRequestErrorCallback& error_callback);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700179
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700180 // Success callback for RefreshAccessToken().
181 void OnRefreshAccessTokenSuccess(
182 const base::Closure& success_callback,
183 const std::shared_ptr<CloudRequestErrorCallback>& error_callback,
184 chromeos::http::RequestID id,
185 std::unique_ptr<chromeos::http::Response> response);
Alex Vakulenko6b028ae2015-05-29 09:38:59 -0700186
Nathan Bullock24d189f2015-02-26 13:09:18 -0500187 // Parse the OAuth response, and sets registration status to
188 // kInvalidCredentials if our registration is no longer valid.
189 std::unique_ptr<base::DictionaryValue> ParseOAuthResponse(
Alex Vakulenkof71cca62015-04-09 15:17:17 -0700190 chromeos::http::Response* response, chromeos::ErrorPtr* error);
Nathan Bullock24d189f2015-02-26 13:09:18 -0500191
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700192 // This attempts to open a notification channel. The channel needs to be
Nathan Bullockbea91132015-02-19 09:13:33 -0500193 // restarted anytime the access_token is refreshed.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700194 void StartNotificationChannel();
Nathan Bullockbea91132015-02-19 09:13:33 -0500195
Anton Muhinac661ab2014-10-03 20:29:48 +0400196 // Do a HTTPS request to cloud services.
197 // Handles many cases like reauthorization, 5xx HTTP response codes
198 // and device removal. It is a recommended way to do cloud API
199 // requests.
200 // TODO(antonm): Consider moving into some other class.
201 void DoCloudRequest(
Anton Muhin233d2ee2014-10-22 15:16:24 +0400202 const std::string& method,
Anton Muhinac661ab2014-10-03 20:29:48 +0400203 const std::string& url,
204 const base::DictionaryValue* body,
Alex Vakulenko0357c032015-01-06 16:32:31 -0800205 const CloudRequestCallback& success_callback,
206 const CloudRequestErrorCallback& error_callback);
Anton Muhinac661ab2014-10-03 20:29:48 +0400207
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700208 // Helper for DoCloudRequest().
209 struct CloudRequestData {
210 std::string method;
211 std::string url;
212 std::string body;
213 CloudRequestCallback success_callback;
214 CloudRequestErrorCallback error_callback;
215 };
216 void SendCloudRequest(const std::shared_ptr<const CloudRequestData>& data);
217 void OnCloudRequestSuccess(
218 const std::shared_ptr<const CloudRequestData>& data,
219 chromeos::http::RequestID request_id,
220 std::unique_ptr<chromeos::http::Response> response);
221 void OnCloudRequestError(
222 const std::shared_ptr<const CloudRequestData>& data,
223 chromeos::http::RequestID request_id,
224 const chromeos::Error* error);
225 void RetryCloudRequest(
226 const std::shared_ptr<const CloudRequestData>& data);
227 void OnAccessTokenRefreshed(
228 const std::shared_ptr<const CloudRequestData>& data);
229 void OnAccessTokenError(
230 const std::shared_ptr<const CloudRequestData>& data,
231 const chromeos::Error* error);
232
Christopher Wileyba983c82015-03-05 16:32:23 -0800233 void UpdateDeviceResource(const base::Closure& on_success,
234 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400235
Christopher Wileyba983c82015-03-05 16:32:23 -0800236 void FetchCommands(
237 const base::Callback<void(const base::ListValue&)>& on_success,
238 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400239
Alex Vakulenkod05725f2015-05-27 15:48:19 -0700240 // Processes the command list that is fetched from the server on connection.
241 // Aborts commands which are in transitional states and publishes queued
242 // commands which are queued.
243 void ProcessInitialCommandList(const base::ListValue& commands);
Anton Muhinc635c592014-10-28 21:48:08 +0400244
Anton Muhind07e2062014-10-27 10:53:29 +0400245 void PublishCommands(const base::ListValue& commands);
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700246 void PublishCommand(const base::DictionaryValue& command);
Anton Muhind07e2062014-10-27 10:53:29 +0400247
Anton Muhinb8315622014-11-20 03:17:05 +0400248 void PublishStateUpdates();
Alex Vakulenko93ba0bd2015-06-19 14:06:46 -0700249 void OnPublishStateSuccess(const base::DictionaryValue& reply);
250 void OnPublishStateError(const chromeos::Error* error);
Anton Muhinb8315622014-11-20 03:17:05 +0400251
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700252 // If unrecoverable error occurred (e.g. error parsing command instance),
253 // notify the server that the command is aborted by the device.
254 void NotifyCommandAborted(const std::string& command_id,
255 chromeos::ErrorPtr error);
256
257 // When NotifyCommandAborted() fails, RetryNotifyCommandAborted() schedules
258 // a retry attempt.
259 void RetryNotifyCommandAborted(const std::string& command_id,
260 chromeos::ErrorPtr error);
261
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700262 // Builds Cloud API devices collection REST resource which matches
Anton Muhind8d32162014-10-02 20:37:00 +0400263 // current state of the device including command definitions
264 // for all supported commands and current device state.
265 std::unique_ptr<base::DictionaryValue> BuildDeviceResource(
266 chromeos::ErrorPtr* error);
267
Christopher Wileyc900e482015-02-15 15:42:04 -0800268 void SetRegistrationStatus(RegistrationStatus new_status);
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700269 void SetDeviceId(const std::string& device_id);
Christopher Wileyc900e482015-02-15 15:42:04 -0800270
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700271 // Callback called when command definitions are changed to re-publish new CDD.
272 void OnCommandDefsChanged();
Vitaly Bukac903d282015-05-26 17:03:08 -0700273 void OnStateChanged();
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700274
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700275 // Overrides from NotificationDelegate
276 void OnConnected(const std::string& channel_name) override;
277 void OnDisconnected() override;
278 void OnPermanentFailure() override;
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700279 void OnCommandCreated(const base::DictionaryValue& command) override;
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700280
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500281 // Transient data
282 std::string access_token_;
283 base::Time access_token_expiration_;
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500284
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700285 // HTTP transport used for communications.
Alex Vakulenkocca20932014-08-20 17:35:12 -0700286 std::shared_ptr<chromeos::http::Transport> transport_;
Alex Vakulenko1f30a622014-07-23 11:13:15 -0700287 // Global command manager.
288 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700289 // Device state manager.
Anton Muhinb8315622014-11-20 03:17:05 +0400290 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700291
Vitaly Buka867b0882015-04-16 10:03:26 -0700292 std::unique_ptr<BuffetConfig> config_;
Anton Muhin332df192014-11-22 05:59:14 +0400293
Alex Vakulenko266b2b12015-06-19 11:01:42 -0700294 // Backoff manager for DoCloudRequest() method.
295 std::unique_ptr<chromeos::BackoffEntry::Policy> cloud_backoff_policy_;
296 std::unique_ptr<chromeos::BackoffEntry> cloud_backoff_entry_;
297
Alex Vakulenko93ba0bd2015-06-19 14:06:46 -0700298 // Flag set to true while a device state update patch request is in flight
299 // to the cloud server.
300 bool device_state_update_pending_{false};
301
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700302 const bool notifications_enabled_;
303 std::unique_ptr<NotificationChannel> primary_notification_channel_;
Alex Vakulenkod05725f2015-05-27 15:48:19 -0700304 std::unique_ptr<PullChannel> pull_channel_;
305 NotificationChannel* current_notification_channel_{nullptr};
Alex Vakulenko6b028ae2015-05-29 09:38:59 -0700306 bool notification_channel_starting_{false};
Christopher Wileyd732bd02015-04-07 11:11:18 -0700307
Vitaly Buka63cc3d22015-06-23 20:11:36 -0700308 privetd::ShillClient* shill_client_{nullptr};
309
Christopher Wileyc900e482015-02-15 15:42:04 -0800310 // Tracks our current registration status.
Vitaly Bukab055f152015-03-12 13:41:43 -0700311 RegistrationStatus registration_status_{RegistrationStatus::kUnconfigured};
Christopher Wileyc900e482015-02-15 15:42:04 -0800312
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700313 std::vector<OnRegistrationChangedCallback> on_registration_changed_;
314
Christopher Wileycd419662015-02-06 17:51:43 -0800315 base::WeakPtrFactory<DeviceRegistrationInfo> weak_factory_{this};
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700316 DISALLOW_COPY_AND_ASSIGN(DeviceRegistrationInfo);
317};
318
319} // namespace buffet
320
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700321#endif // BUFFET_DEVICE_REGISTRATION_INFO_H_