Don't preload rarely seen large images
[chromium-blink-merge.git] / components / proximity_auth / cryptauth / cryptauth_device_manager.cc
blob709161e4141a823a7edffa56838b88e4774f49d8
1 // Copyright 2015 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.
5 #include "components/proximity_auth/cryptauth/cryptauth_device_manager.h"
7 #include "base/prefs/pref_registry_simple.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/prefs/scoped_user_pref_update.h"
10 #include "components/proximity_auth/cryptauth/cryptauth_client.h"
11 #include "components/proximity_auth/cryptauth/pref_names.h"
12 #include "components/proximity_auth/cryptauth/sync_scheduler_impl.h"
13 #include "components/proximity_auth/logging/logging.h"
15 namespace proximity_auth {
17 namespace {
19 // The normal period between successful syncs, in hours.
20 const int kRefreshPeriodHours = 24;
22 // A more aggressive period between sync attempts to recover when the last
23 // sync attempt fails, in minutes. This is a base time that increases for each
24 // subsequent failure.
25 const int kDeviceSyncBaseRecoveryPeriodMinutes = 10;
27 // The bound on the amount to jitter the period between syncs.
28 const double kDeviceSyncMaxJitterRatio = 0.2;
30 // Keys for ExternalDeviceInfo dictionaries that are stored in the user's prefs.
31 const char kExternalDeviceKeyPublicKey[] = "public_key";
32 const char kExternalDeviceKeyDeviceName[] = "device_name";
33 const char kExternalDeviceKeyBluetoothAddress[] = "bluetooth_address";
35 // Converts an unlock key proto to a dictionary that can be stored in user
36 // prefs.
37 scoped_ptr<base::DictionaryValue> UnlockKeyToDictionary(
38 const cryptauth::ExternalDeviceInfo& device) {
39 scoped_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue());
40 dictionary->SetString(kExternalDeviceKeyPublicKey, device.public_key());
41 dictionary->SetString(kExternalDeviceKeyDeviceName,
42 device.friendly_device_name());
43 dictionary->SetString(kExternalDeviceKeyBluetoothAddress,
44 device.bluetooth_address());
45 return dictionary.Pass();
48 // Converts an unlock key dictionary stored in user prefs to an
49 // ExternalDeviceInfo proto. Returns true if the dictionary is valid, and the
50 // parsed proto is written to |external_device|.
51 bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary,
52 cryptauth::ExternalDeviceInfo* external_device) {
53 std::string public_key, device_name, bluetooth_address;
54 if (!dictionary.GetString(kExternalDeviceKeyPublicKey, &public_key) ||
55 !dictionary.GetString(kExternalDeviceKeyDeviceName, &device_name) ||
56 !dictionary.GetString(kExternalDeviceKeyBluetoothAddress,
57 &bluetooth_address)) {
58 return false;
61 external_device->set_public_key(public_key);
62 external_device->set_friendly_device_name(device_name);
63 external_device->set_bluetooth_address(bluetooth_address);
64 external_device->set_unlock_key(true);
65 external_device->set_unlockable(false);
66 return true;
69 } // namespace
71 CryptAuthDeviceManager::CryptAuthDeviceManager(
72 scoped_ptr<base::Clock> clock,
73 scoped_ptr<CryptAuthClientFactory> client_factory,
74 PrefService* pref_service)
75 : clock_(clock.Pass()),
76 client_factory_(client_factory.Pass()),
77 pref_service_(pref_service),
78 weak_ptr_factory_(this) {
81 CryptAuthDeviceManager::~CryptAuthDeviceManager() {
84 // static
85 void CryptAuthDeviceManager::RegisterPrefs(PrefRegistrySimple* registry) {
86 registry->RegisterDoublePref(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
87 0.0);
88 registry->RegisterBooleanPref(
89 prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure, false);
90 registry->RegisterIntegerPref(prefs::kCryptAuthDeviceSyncReason,
91 cryptauth::INVOCATION_REASON_UNKNOWN);
92 registry->RegisterListPref(prefs::kCryptAuthDeviceSyncUnlockKeys);
95 void CryptAuthDeviceManager::Start() {
96 UpdateUnlockKeysFromPrefs();
98 base::Time last_successful_sync = GetLastSyncTime();
99 base::TimeDelta elapsed_time_since_last_sync =
100 clock_->Now() - last_successful_sync;
102 bool is_recovering_from_failure =
103 pref_service_->GetBoolean(
104 prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure) ||
105 last_successful_sync.is_null();
107 scheduler_ = CreateSyncScheduler();
108 scheduler_->Start(elapsed_time_since_last_sync,
109 is_recovering_from_failure
110 ? SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
111 : SyncScheduler::Strategy::PERIODIC_REFRESH);
114 void CryptAuthDeviceManager::AddObserver(Observer* observer) {
115 observers_.AddObserver(observer);
118 void CryptAuthDeviceManager::RemoveObserver(Observer* observer) {
119 observers_.RemoveObserver(observer);
122 void CryptAuthDeviceManager::ForceSyncNow(
123 cryptauth::InvocationReason invocation_reason) {
124 pref_service_->SetInteger(prefs::kCryptAuthDeviceSyncReason,
125 invocation_reason);
126 scheduler_->ForceSync();
129 base::Time CryptAuthDeviceManager::GetLastSyncTime() const {
130 return base::Time::FromDoubleT(
131 pref_service_->GetDouble(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds));
134 base::TimeDelta CryptAuthDeviceManager::GetTimeToNextAttempt() const {
135 return scheduler_->GetTimeToNextSync();
138 bool CryptAuthDeviceManager::IsSyncInProgress() const {
139 return scheduler_->GetSyncState() ==
140 SyncScheduler::SyncState::SYNC_IN_PROGRESS;
143 bool CryptAuthDeviceManager::IsRecoveringFromFailure() const {
144 return scheduler_->GetStrategy() ==
145 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY;
148 void CryptAuthDeviceManager::OnGetMyDevicesSuccess(
149 const cryptauth::GetMyDevicesResponse& response) {
150 // Update the unlock keys stored in the user's prefs.
151 scoped_ptr<base::ListValue> unlock_keys_pref(new base::ListValue());
152 for (const auto& device : response.devices()) {
153 if (device.unlock_key())
154 unlock_keys_pref->Append(UnlockKeyToDictionary(device));
157 bool unlock_keys_changed = !unlock_keys_pref->Equals(
158 pref_service_->GetList(prefs::kCryptAuthDeviceSyncUnlockKeys));
160 ListPrefUpdate update(pref_service_, prefs::kCryptAuthDeviceSyncUnlockKeys);
161 update.Get()->Swap(unlock_keys_pref.get());
163 UpdateUnlockKeysFromPrefs();
165 // Reset metadata used for scheduling syncing.
166 pref_service_->SetBoolean(prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure,
167 false);
168 pref_service_->SetDouble(prefs::kCryptAuthDeviceSyncLastSyncTimeSeconds,
169 clock_->Now().ToDoubleT());
170 pref_service_->SetInteger(prefs::kCryptAuthDeviceSyncReason,
171 cryptauth::INVOCATION_REASON_UNKNOWN);
173 sync_request_->OnDidComplete(true);
174 cryptauth_client_.reset();
175 sync_request_.reset();
176 FOR_EACH_OBSERVER(
177 Observer, observers_,
178 OnSyncFinished(SyncResult::SUCCESS, unlock_keys_changed
179 ? DeviceChangeResult::CHANGED
180 : DeviceChangeResult::UNCHANGED));
183 void CryptAuthDeviceManager::OnGetMyDevicesFailure(const std::string& error) {
184 PA_LOG(ERROR) << "GetMyDevices API failed: " << error;
185 pref_service_->SetBoolean(prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure,
186 true);
187 sync_request_->OnDidComplete(false);
188 cryptauth_client_.reset();
189 sync_request_.reset();
190 FOR_EACH_OBSERVER(
191 Observer, observers_,
192 OnSyncFinished(SyncResult::FAILURE, DeviceChangeResult::UNCHANGED));
195 scoped_ptr<SyncScheduler> CryptAuthDeviceManager::CreateSyncScheduler() {
196 return make_scoped_ptr(new SyncSchedulerImpl(
197 this, base::TimeDelta::FromHours(kRefreshPeriodHours),
198 base::TimeDelta::FromMinutes(kDeviceSyncBaseRecoveryPeriodMinutes),
199 kDeviceSyncMaxJitterRatio, "CryptAuth DeviceSync"));
202 void CryptAuthDeviceManager::UpdateUnlockKeysFromPrefs() {
203 const base::ListValue* unlock_key_list =
204 pref_service_->GetList(prefs::kCryptAuthDeviceSyncUnlockKeys);
205 unlock_keys_.clear();
206 for (size_t i = 0; i < unlock_key_list->GetSize(); ++i) {
207 const base::DictionaryValue* unlock_key_dictionary;
208 if (unlock_key_list->GetDictionary(i, &unlock_key_dictionary)) {
209 cryptauth::ExternalDeviceInfo unlock_key;
210 if (DictionaryToUnlockKey(*unlock_key_dictionary, &unlock_key)) {
211 unlock_keys_.push_back(unlock_key);
212 } else {
213 PA_LOG(ERROR) << "Unable to deserialize unlock key dictionary "
214 << "(index=" << i << "):\n" << *unlock_key_dictionary;
216 } else {
217 PA_LOG(ERROR) << "Can not get dictionary in list of unlock keys "
218 << "(index=" << i << "):\n" << *unlock_key_list;
223 void CryptAuthDeviceManager::OnSyncRequested(
224 scoped_ptr<SyncScheduler::SyncRequest> sync_request) {
225 FOR_EACH_OBSERVER(Observer, observers_, OnSyncStarted());
227 sync_request_ = sync_request.Pass();
228 cryptauth_client_ = client_factory_->CreateInstance();
230 cryptauth::InvocationReason invocation_reason =
231 cryptauth::INVOCATION_REASON_UNKNOWN;
233 int reason_stored_in_prefs =
234 pref_service_->GetInteger(prefs::kCryptAuthDeviceSyncReason);
236 if (cryptauth::InvocationReason_IsValid(reason_stored_in_prefs) &&
237 reason_stored_in_prefs != cryptauth::INVOCATION_REASON_UNKNOWN) {
238 invocation_reason =
239 static_cast<cryptauth::InvocationReason>(reason_stored_in_prefs);
240 } else if (GetLastSyncTime().is_null()) {
241 invocation_reason = cryptauth::INVOCATION_REASON_INITIALIZATION;
242 } else if (IsRecoveringFromFailure()) {
243 invocation_reason = cryptauth::INVOCATION_REASON_FAILURE_RECOVERY;
244 } else {
245 invocation_reason = cryptauth::INVOCATION_REASON_PERIODIC;
248 cryptauth::GetMyDevicesRequest request;
249 request.set_invocation_reason(invocation_reason);
250 cryptauth_client_->GetMyDevices(
251 request, base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesSuccess,
252 weak_ptr_factory_.GetWeakPtr()),
253 base::Bind(&CryptAuthDeviceManager::OnGetMyDevicesFailure,
254 weak_ptr_factory_.GetWeakPtr()));
257 } // namespace proximity_auth