blob: 674bbd61f0d6c34f08493b5fcc2fc3f90f55e767 [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"
Christopher Wileyc900e482015-02-15 15:42:04 -080026#include "buffet/registration_status.h"
Christopher Wiley006e94e2014-05-02 13:44:48 -070027#include "buffet/storage_interface.h"
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070028
29namespace base {
Vitaly Buka6ca3ad62015-03-11 17:03:23 -070030class DictionaryValue;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070031} // namespace base
32
Anton Muhin332df192014-11-22 05:59:14 +040033namespace chromeos {
34class KeyValueStore;
35} // namespace chromeos
36
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070037namespace buffet {
38
Alex Vakulenko07216fe2014-09-19 15:31:09 -070039class StateManager;
Alex Vakulenko1f30a622014-07-23 11:13:15 -070040
Alex Vakulenkob3aac252014-05-07 17:35:24 -070041extern const char kErrorDomainOAuth2[];
42extern const char kErrorDomainGCD[];
43extern const char kErrorDomainGCDServer[];
Alex Vakulenkob3aac252014-05-07 17:35:24 -070044
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070045// The DeviceRegistrationInfo class represents device registration information.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070046class DeviceRegistrationInfo : public NotificationDelegate {
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070047 public:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070048 using OnRegistrationChangedCallback =
49 base::Callback<void(RegistrationStatus)>;
Christopher Wileye0fdeee2015-02-07 18:29:32 -080050
Alex Vakulenkocca20932014-08-20 17:35:12 -070051 DeviceRegistrationInfo(
52 const std::shared_ptr<CommandManager>& command_manager,
Anton Muhinb8315622014-11-20 03:17:05 +040053 const std::shared_ptr<StateManager>& state_manager,
Vitaly Buka867b0882015-04-16 10:03:26 -070054 std::unique_ptr<BuffetConfig> config,
Alex Vakulenkocca20932014-08-20 17:35:12 -070055 const std::shared_ptr<chromeos::http::Transport>& transport,
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070056 bool notifications_enabled);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070057
Alex Vakulenko534a3122015-05-22 15:48:53 -070058 ~DeviceRegistrationInfo() override;
Anton Muhin332df192014-11-22 05:59:14 +040059
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070060 // Add callback to listen for changes in registration status.
61 void AddOnRegistrationChangedCallback(
62 const OnRegistrationChangedCallback& callback);
Christopher Wileyc900e482015-02-15 15:42:04 -080063
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070064 // Returns the authorization HTTP header that can be used to talk
65 // to GCD server for authenticated device communication.
Alex Vakulenko8e34d392014-04-29 11:02:56 -070066 // Make sure ValidateAndRefreshAccessToken() is called before this call.
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070067 std::pair<std::string, std::string> GetAuthorizationHeader() const;
68
69 // Returns the GCD service request URL. If |subpath| is specified, it is
70 // appended to the base URL which is normally
71 // https://www.googleapis.com/clouddevices/v1/".
72 // If |params| are specified, each key-value pair is formatted using
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070073 // chromeos::data_encoding::WebParamsEncode() and appended to URL as a query
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070074 // string.
75 // So, calling:
76 // GetServiceURL("ticket", {{"key","apiKey"}})
77 // will return something like:
78 // https://www.googleapis.com/clouddevices/v1/ticket?key=apiKey
79 std::string GetServiceURL(
80 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070081 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070082
83 // Returns a service URL to access the registered device on GCD server.
84 // The base URL used to construct the full URL looks like this:
85 // https://www.googleapis.com/clouddevices/v1/devices/<device_id>/
86 std::string GetDeviceURL(
87 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070088 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070089
90 // Similar to GetServiceURL, GetOAuthURL() returns a URL of OAuth 2.0 server.
91 // The base URL used is https://accounts.google.com/o/oauth2/.
92 std::string GetOAuthURL(
93 const std::string& subpath = {},
Alex Vakulenkoe4879a22014-08-20 15:47:36 -070094 const chromeos::data_encoding::WebParamList& params = {}) const;
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070095
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -070096 // Starts GCD device if credentials available.
Vitaly Bukaee7a3af2015-05-14 16:57:23 -070097 void Start();
Alex Vakulenko3cb466c2014-04-15 11:36:32 -070098
Nathan Bullock5e022a32015-04-08 15:13:07 -040099 // Checks whether we have credentials generated during registration.
100 bool HaveRegistrationCredentials(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700101
102 // Gets the full device description JSON object, or nullptr if
103 // the device is not registered or communication failure.
Vitaly Buka6ca3ad62015-03-11 17:03:23 -0700104 std::unique_ptr<base::DictionaryValue> GetDeviceInfo(
105 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700106
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400107 // Registers the device.
Anton Muhinbeb1c5b2014-10-16 18:59:57 +0400108 // Returns a device ID on success.
Vitaly Bukacad2e332015-05-14 23:33:32 -0700109 std::string RegisterDevice(const std::string& ticket_id,
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700110 chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700111
Anton Muhin59755522014-11-05 21:30:12 +0400112 // Updates a command.
Anton Muhin59755522014-11-05 21:30:12 +0400113 void UpdateCommand(const std::string& command_id,
Alex Vakulenkob211c102015-04-21 11:43:23 -0700114 const base::DictionaryValue& command_patch,
115 const base::Closure& on_success,
116 const base::Closure& on_error);
Anton Muhin59755522014-11-05 21:30:12 +0400117
Vitaly Bukafa947062015-04-17 00:41:31 -0700118 // Updates basic device information.
119 bool UpdateDeviceInfo(const std::string& name,
120 const std::string& description,
121 const std::string& location,
122 chromeos::ErrorPtr* error);
123
Vitaly Bukaff81db62015-05-14 21:25:45 -0700124 // Updates GCD service configuration. Usually for testing.
125 bool UpdateServiceConfig(const std::string& client_id,
126 const std::string& client_secret,
127 const std::string& api_key,
128 const std::string& oauth_url,
129 const std::string& service_url,
130 chromeos::ErrorPtr* error);
131
Vitaly Buka72410b22015-05-13 13:48:59 -0700132 const BuffetConfig& GetConfig() const { return *config_; }
133
134 base::WeakPtr<DeviceRegistrationInfo> AsWeakPtr() {
135 return weak_factory_.GetWeakPtr();
136 }
137
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700138 private:
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700139 friend class DeviceRegistrationInfoTest;
140
Christopher Wileyba983c82015-03-05 16:32:23 -0800141 // Cause DeviceRegistrationInfo to attempt to StartDevice on its own later.
142 void ScheduleStartDevice(const base::TimeDelta& later);
143
144 // Starts device execution.
145 // Device will do required start up chores and then start to listen
146 // to new commands.
147 // TODO(antonm): Consider moving into some other class.
148 void StartDevice(chromeos::ErrorPtr* error,
149 const base::TimeDelta& retry_delay);
150
Nathan Bullock5e022a32015-04-08 15:13:07 -0400151 // Checks for the valid device registration as well as refreshes
152 // the device access token, if available.
153 bool CheckRegistration(chromeos::ErrorPtr* error);
Christopher Wileyc900e482015-02-15 15:42:04 -0800154
Nathan Bullock5e022a32015-04-08 15:13:07 -0400155 // If we currently have an access token and it doesn't look like it
David Zeuthen390d1912015-03-03 14:54:48 -0500156 // has expired yet, returns true immediately. Otherwise calls
157 // RefreshAccessToken().
158 bool MaybeRefreshAccessToken(chromeos::ErrorPtr* error);
159
160 // Forcibly refreshes the access token.
161 bool RefreshAccessToken(chromeos::ErrorPtr* error);
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700162
Nathan Bullock24d189f2015-02-26 13:09:18 -0500163 // Parse the OAuth response, and sets registration status to
164 // kInvalidCredentials if our registration is no longer valid.
165 std::unique_ptr<base::DictionaryValue> ParseOAuthResponse(
Alex Vakulenkof71cca62015-04-09 15:17:17 -0700166 chromeos::http::Response* response, chromeos::ErrorPtr* error);
Nathan Bullock24d189f2015-02-26 13:09:18 -0500167
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700168 // This attempts to open a notification channel. The channel needs to be
Nathan Bullockbea91132015-02-19 09:13:33 -0500169 // restarted anytime the access_token is refreshed.
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700170 void StartNotificationChannel();
Nathan Bullockbea91132015-02-19 09:13:33 -0500171
Anton Muhinac661ab2014-10-03 20:29:48 +0400172 using CloudRequestCallback =
173 base::Callback<void(const base::DictionaryValue&)>;
Alex Vakulenko0357c032015-01-06 16:32:31 -0800174 using CloudRequestErrorCallback =
175 base::Callback<void(const chromeos::Error* error)>;
Anton Muhinac661ab2014-10-03 20:29:48 +0400176
177 // Do a HTTPS request to cloud services.
178 // Handles many cases like reauthorization, 5xx HTTP response codes
179 // and device removal. It is a recommended way to do cloud API
180 // requests.
181 // TODO(antonm): Consider moving into some other class.
182 void DoCloudRequest(
Anton Muhin233d2ee2014-10-22 15:16:24 +0400183 const std::string& method,
Anton Muhinac661ab2014-10-03 20:29:48 +0400184 const std::string& url,
185 const base::DictionaryValue* body,
Alex Vakulenko0357c032015-01-06 16:32:31 -0800186 const CloudRequestCallback& success_callback,
187 const CloudRequestErrorCallback& error_callback);
Anton Muhinac661ab2014-10-03 20:29:48 +0400188
Christopher Wileyba983c82015-03-05 16:32:23 -0800189 void UpdateDeviceResource(const base::Closure& on_success,
190 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400191
Christopher Wileyba983c82015-03-05 16:32:23 -0800192 void FetchCommands(
193 const base::Callback<void(const base::ListValue&)>& on_success,
194 const CloudRequestErrorCallback& on_failure);
Anton Muhinc635c592014-10-28 21:48:08 +0400195
Christopher Wileyba983c82015-03-05 16:32:23 -0800196 void AbortLimboCommands(const base::Closure& callback,
Anton Muhinc635c592014-10-28 21:48:08 +0400197 const base::ListValue& commands);
198
199 void PeriodicallyPollCommands();
200
Anton Muhind07e2062014-10-27 10:53:29 +0400201 void PublishCommands(const base::ListValue& commands);
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700202 void PublishCommand(const base::DictionaryValue& command);
Anton Muhind07e2062014-10-27 10:53:29 +0400203
Anton Muhinb8315622014-11-20 03:17:05 +0400204 void PublishStateUpdates();
205
Alex Vakulenkod1978d32015-04-29 17:33:26 -0700206 // If unrecoverable error occurred (e.g. error parsing command instance),
207 // notify the server that the command is aborted by the device.
208 void NotifyCommandAborted(const std::string& command_id,
209 chromeos::ErrorPtr error);
210
211 // When NotifyCommandAborted() fails, RetryNotifyCommandAborted() schedules
212 // a retry attempt.
213 void RetryNotifyCommandAborted(const std::string& command_id,
214 chromeos::ErrorPtr error);
215
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700216 // Builds Cloud API devices collection REST resource which matches
Anton Muhind8d32162014-10-02 20:37:00 +0400217 // current state of the device including command definitions
218 // for all supported commands and current device state.
219 std::unique_ptr<base::DictionaryValue> BuildDeviceResource(
220 chromeos::ErrorPtr* error);
221
Christopher Wileyc900e482015-02-15 15:42:04 -0800222 void SetRegistrationStatus(RegistrationStatus new_status);
Vitaly Buka620bd7e2015-03-16 01:07:01 -0700223 void SetDeviceId(const std::string& device_id);
Christopher Wileyc900e482015-02-15 15:42:04 -0800224
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700225 // Callback called when command definitions are changed to re-publish new CDD.
226 void OnCommandDefsChanged();
Vitaly Bukac903d282015-05-26 17:03:08 -0700227 void OnStateChanged();
Alex Vakulenko9ea5a322015-04-17 15:35:34 -0700228
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700229 // Overrides from NotificationDelegate
230 void OnConnected(const std::string& channel_name) override;
231 void OnDisconnected() override;
232 void OnPermanentFailure() override;
Alex Vakulenko6e3c30e2015-05-21 17:39:25 -0700233 void OnCommandCreated(const base::DictionaryValue& command) override;
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700234
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500235 // Transient data
236 std::string access_token_;
237 base::Time access_token_expiration_;
Nathan Bullockd9e0bcd2015-02-11 11:36:39 -0500238
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700239 // HTTP transport used for communications.
Alex Vakulenkocca20932014-08-20 17:35:12 -0700240 std::shared_ptr<chromeos::http::Transport> transport_;
Alex Vakulenko1f30a622014-07-23 11:13:15 -0700241 // Global command manager.
242 std::shared_ptr<CommandManager> command_manager_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700243 // Device state manager.
Anton Muhinb8315622014-11-20 03:17:05 +0400244 std::shared_ptr<StateManager> state_manager_;
Alex Vakulenkoa3062c52014-04-21 17:05:51 -0700245
Vitaly Buka867b0882015-04-16 10:03:26 -0700246 std::unique_ptr<BuffetConfig> config_;
Anton Muhin332df192014-11-22 05:59:14 +0400247
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -0700248 const bool notifications_enabled_;
249 std::unique_ptr<NotificationChannel> primary_notification_channel_;
Christopher Wileyd732bd02015-04-07 11:11:18 -0700250
Christopher Wileyc900e482015-02-15 15:42:04 -0800251 // Tracks our current registration status.
Vitaly Bukab055f152015-03-12 13:41:43 -0700252 RegistrationStatus registration_status_{RegistrationStatus::kUnconfigured};
Christopher Wileyc900e482015-02-15 15:42:04 -0800253
Christopher Wiley34eae042015-03-18 10:25:08 -0700254 base::RepeatingTimer<DeviceRegistrationInfo> command_poll_timer_;
Christopher Wiley34eae042015-03-18 10:25:08 -0700255
Vitaly Bukaee7a3af2015-05-14 16:57:23 -0700256 std::vector<OnRegistrationChangedCallback> on_registration_changed_;
257
Christopher Wileycd419662015-02-06 17:51:43 -0800258 base::WeakPtrFactory<DeviceRegistrationInfo> weak_factory_{this};
Alex Vakulenko3cb466c2014-04-15 11:36:32 -0700259 DISALLOW_COPY_AND_ASSIGN(DeviceRegistrationInfo);
260};
261
262} // namespace buffet
263
Alex Vakulenkob3aac252014-05-07 17:35:24 -0700264#endif // BUFFET_DEVICE_REGISTRATION_INFO_H_