host_verifier_impl.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Copyright 2018 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.
  4. #include "ash/services/multidevice_setup/host_verifier_impl.h"
  5. #include <utility>
  6. #include "ash/components/multidevice/logging/logging.h"
  7. #include "ash/components/multidevice/software_feature.h"
  8. #include "ash/constants/ash_features.h"
  9. #include "ash/services/device_sync/proto/cryptauth_common.pb.h"
  10. #include "base/bind.h"
  11. #include "base/callback_helpers.h"
  12. #include "base/logging.h"
  13. #include "base/memory/ptr_util.h"
  14. #include "base/metrics/histogram_functions.h"
  15. #include "base/time/time.h"
  16. #include "components/prefs/pref_registry_simple.h"
  17. #include "components/prefs/pref_service.h"
  18. namespace ash {
  19. namespace multidevice_setup {
  20. namespace {
  21. // Software features which, when enabled, represent a verified host.
  22. constexpr const multidevice::SoftwareFeature kPotentialHostFeatures[] = {
  23. multidevice::SoftwareFeature::kSmartLockHost,
  24. multidevice::SoftwareFeature::kInstantTetheringHost,
  25. multidevice::SoftwareFeature::kMessagesForWebHost};
  26. // Name of the preference containing the time (in milliseconds since Unix
  27. // epoch) at which a verification attempt should be retried. If the preference
  28. // value is kTimestampNotSet, no retry is scheduled.
  29. const char kRetryTimestampPrefName[] =
  30. "multidevice_setup.current_retry_timestamp_ms";
  31. // Value set for the kRetryTimestampPrefName preference when no retry attempt is
  32. // underway (i.e., verification is complete or there is no current host).
  33. const int64_t kTimestampNotSet = 0;
  34. // Name of the preference containing the time delta (in ms) between the
  35. // timestamp present in the kRetryTimestampPrefName preference and the attempt
  36. // before that one. If the value of kRetryTimestampPrefName is kTimestampNotSet,
  37. // the value at this preference is meaningless.
  38. const char kLastUsedTimeDeltaMsPrefName[] =
  39. "multidevice_setup.last_used_time_delta_ms";
  40. // Delta to set for the first retry.
  41. constexpr const base::TimeDelta kFirstRetryDelta = base::Minutes(10);
  42. // Delta for the time between a successful FindEligibleDevices call and a
  43. // request to sync devices.
  44. constexpr const base::TimeDelta kSyncDelay = base::Seconds(5);
  45. // The multiplier for increasing the backoff timer between retries.
  46. const double kExponentialBackoffMultiplier = 1.5;
  47. } // namespace
  48. // static
  49. HostVerifierImpl::Factory* HostVerifierImpl::Factory::test_factory_ = nullptr;
  50. // static
  51. std::unique_ptr<HostVerifier> HostVerifierImpl::Factory::Create(
  52. HostBackendDelegate* host_backend_delegate,
  53. device_sync::DeviceSyncClient* device_sync_client,
  54. PrefService* pref_service,
  55. base::Clock* clock,
  56. std::unique_ptr<base::OneShotTimer> retry_timer,
  57. std::unique_ptr<base::OneShotTimer> sync_timer) {
  58. if (test_factory_) {
  59. return test_factory_->CreateInstance(
  60. host_backend_delegate, device_sync_client, pref_service, clock,
  61. std::move(retry_timer), std::move(sync_timer));
  62. }
  63. return base::WrapUnique(new HostVerifierImpl(
  64. host_backend_delegate, device_sync_client, pref_service, clock,
  65. std::move(retry_timer), std::move(sync_timer)));
  66. }
  67. // static
  68. void HostVerifierImpl::Factory::SetFactoryForTesting(Factory* test_factory) {
  69. test_factory_ = test_factory;
  70. }
  71. HostVerifierImpl::Factory::~Factory() = default;
  72. // static
  73. void HostVerifierImpl::RegisterPrefs(PrefRegistrySimple* registry) {
  74. registry->RegisterInt64Pref(kRetryTimestampPrefName, kTimestampNotSet);
  75. registry->RegisterInt64Pref(kLastUsedTimeDeltaMsPrefName, 0);
  76. }
  77. HostVerifierImpl::HostVerifierImpl(
  78. HostBackendDelegate* host_backend_delegate,
  79. device_sync::DeviceSyncClient* device_sync_client,
  80. PrefService* pref_service,
  81. base::Clock* clock,
  82. std::unique_ptr<base::OneShotTimer> retry_timer,
  83. std::unique_ptr<base::OneShotTimer> sync_timer)
  84. : host_backend_delegate_(host_backend_delegate),
  85. device_sync_client_(device_sync_client),
  86. pref_service_(pref_service),
  87. clock_(clock),
  88. retry_timer_(std::move(retry_timer)),
  89. sync_timer_(std::move(sync_timer)) {
  90. host_backend_delegate_->AddObserver(this);
  91. device_sync_client_->AddObserver(this);
  92. UpdateRetryState();
  93. }
  94. HostVerifierImpl::~HostVerifierImpl() {
  95. host_backend_delegate_->RemoveObserver(this);
  96. device_sync_client_->RemoveObserver(this);
  97. }
  98. bool HostVerifierImpl::IsHostVerified() {
  99. absl::optional<multidevice::RemoteDeviceRef> current_host =
  100. host_backend_delegate_->GetMultiDeviceHostFromBackend();
  101. if (!current_host)
  102. return false;
  103. // If a host exists on the back-end but there is a pending request to remove
  104. // that host, the device pending removal is no longer considered verified.
  105. if (host_backend_delegate_->HasPendingHostRequest() &&
  106. !host_backend_delegate_->GetPendingHostRequest()) {
  107. return false;
  108. }
  109. // The host is not considered verified if it does not have the data needed for
  110. // secure communication via Bluetooth. These values could be missing if v2
  111. // DeviceSync data was not decrypted, for instance.
  112. bool has_crypto_data = !current_host->public_key().empty() &&
  113. !current_host->persistent_symmetric_key().empty() &&
  114. !current_host->beacon_seeds().empty();
  115. base::UmaHistogramBoolean(
  116. "MultiDevice.Setup.HostVerifier.DoesHostHaveCryptoData", has_crypto_data);
  117. if (!has_crypto_data) {
  118. return false;
  119. }
  120. // If one or more potential host sofware features is enabled, the host is
  121. // considered verified.
  122. for (const auto& software_feature : kPotentialHostFeatures) {
  123. if (current_host->GetSoftwareFeatureState(software_feature) ==
  124. multidevice::SoftwareFeatureState::kEnabled) {
  125. return true;
  126. }
  127. }
  128. return false;
  129. }
  130. void HostVerifierImpl::PerformAttemptVerificationNow() {
  131. AttemptHostVerification();
  132. }
  133. void HostVerifierImpl::OnHostChangedOnBackend() {
  134. UpdateRetryState();
  135. }
  136. void HostVerifierImpl::OnNewDevicesSynced() {
  137. UpdateRetryState();
  138. }
  139. void HostVerifierImpl::UpdateRetryState() {
  140. // If there is no host, verification is not applicable.
  141. if (!host_backend_delegate_->GetMultiDeviceHostFromBackend()) {
  142. StopRetryTimerAndClearPrefs();
  143. return;
  144. }
  145. // If there is a host and it is verified, verification is no longer necessary.
  146. if (IsHostVerified()) {
  147. sync_timer_->Stop();
  148. bool was_retry_timer_running = retry_timer_->IsRunning();
  149. StopRetryTimerAndClearPrefs();
  150. if (was_retry_timer_running)
  151. NotifyHostVerified();
  152. return;
  153. }
  154. // If |retry_timer_| is running, an ongoing retry attempt is in progress.
  155. if (retry_timer_->IsRunning())
  156. return;
  157. int64_t timestamp_from_prefs =
  158. pref_service_->GetInt64(kRetryTimestampPrefName);
  159. // If no retry timer was set, set the timer to the initial value and attempt
  160. // to verify now.
  161. if (timestamp_from_prefs == kTimestampNotSet) {
  162. AttemptVerificationWithInitialTimeout();
  163. return;
  164. }
  165. base::Time retry_time_from_prefs =
  166. base::Time::FromJavaTime(timestamp_from_prefs);
  167. // If a timeout value was set but has not yet occurred, start the timer.
  168. if (clock_->Now() < retry_time_from_prefs) {
  169. StartRetryTimer(retry_time_from_prefs);
  170. return;
  171. }
  172. AttemptVerificationAfterInitialTimeout(retry_time_from_prefs);
  173. }
  174. void HostVerifierImpl::StopRetryTimerAndClearPrefs() {
  175. retry_timer_->Stop();
  176. pref_service_->SetInt64(kRetryTimestampPrefName, kTimestampNotSet);
  177. pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, 0);
  178. }
  179. void HostVerifierImpl::AttemptVerificationWithInitialTimeout() {
  180. base::Time retry_time = clock_->Now() + kFirstRetryDelta;
  181. pref_service_->SetInt64(kRetryTimestampPrefName, retry_time.ToJavaTime());
  182. pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName,
  183. kFirstRetryDelta.InMilliseconds());
  184. StartRetryTimer(retry_time);
  185. AttemptHostVerification();
  186. }
  187. void HostVerifierImpl::AttemptVerificationAfterInitialTimeout(
  188. const base::Time& retry_time_from_prefs) {
  189. int64_t time_delta_ms = pref_service_->GetInt64(kLastUsedTimeDeltaMsPrefName);
  190. DCHECK(time_delta_ms > 0);
  191. base::Time retry_time = retry_time_from_prefs;
  192. while (clock_->Now() >= retry_time) {
  193. time_delta_ms *= kExponentialBackoffMultiplier;
  194. retry_time += base::Milliseconds(time_delta_ms);
  195. }
  196. pref_service_->SetInt64(kRetryTimestampPrefName, retry_time.ToJavaTime());
  197. pref_service_->SetInt64(kLastUsedTimeDeltaMsPrefName, time_delta_ms);
  198. StartRetryTimer(retry_time);
  199. AttemptHostVerification();
  200. }
  201. void HostVerifierImpl::StartRetryTimer(const base::Time& time_to_fire) {
  202. base::Time now = clock_->Now();
  203. DCHECK(now < time_to_fire);
  204. retry_timer_->Start(FROM_HERE, time_to_fire - now /* delay */,
  205. base::BindOnce(&HostVerifierImpl::UpdateRetryState,
  206. base::Unretained(this)));
  207. }
  208. void HostVerifierImpl::AttemptHostVerification() {
  209. absl::optional<multidevice::RemoteDeviceRef> current_host =
  210. host_backend_delegate_->GetMultiDeviceHostFromBackend();
  211. if (!current_host) {
  212. PA_LOG(WARNING) << "HostVerifierImpl::AttemptHostVerification(): Cannot "
  213. << "attempt verification because there is no active host.";
  214. return;
  215. }
  216. PA_LOG(VERBOSE) << "HostVerifierImpl::AttemptHostVerification(): Attempting "
  217. << "host verification now.";
  218. if (features::ShouldUseV1DeviceSync()) {
  219. if (current_host->instance_id().empty()) {
  220. device_sync_client_->FindEligibleDevices(
  221. multidevice::SoftwareFeature::kBetterTogetherHost,
  222. base::BindOnce(&HostVerifierImpl::OnFindEligibleDevicesResult,
  223. weak_ptr_factory_.GetWeakPtr()));
  224. } else {
  225. device_sync_client_->NotifyDevices(
  226. {current_host->instance_id()},
  227. cryptauthv2::TargetService::DEVICE_SYNC,
  228. multidevice::SoftwareFeature::kBetterTogetherHost,
  229. base::BindOnce(&HostVerifierImpl::OnNotifyDevicesFinished,
  230. weak_ptr_factory_.GetWeakPtr()));
  231. }
  232. } else {
  233. DCHECK(!current_host->instance_id().empty());
  234. device_sync_client_->NotifyDevices(
  235. {current_host->instance_id()}, cryptauthv2::TargetService::DEVICE_SYNC,
  236. multidevice::SoftwareFeature::kBetterTogetherHost,
  237. base::BindOnce(&HostVerifierImpl::OnNotifyDevicesFinished,
  238. weak_ptr_factory_.GetWeakPtr()));
  239. }
  240. }
  241. void HostVerifierImpl::OnFindEligibleDevicesResult(
  242. device_sync::mojom::NetworkRequestResult result,
  243. multidevice::RemoteDeviceRefList eligible_devices,
  244. multidevice::RemoteDeviceRefList ineligible_devices) {
  245. if (result != device_sync::mojom::NetworkRequestResult::kSuccess) {
  246. PA_LOG(WARNING) << "HostVerifierImpl::OnFindEligibleDevicesResult(): "
  247. << "FindEligibleDevices call failed. Retry is scheduled.";
  248. return;
  249. }
  250. // Now that the FindEligibleDevices call was sent successfully, the host phone
  251. // is expected to enable its supported features. This should trigger a push
  252. // message asking this Chromebook to sync these updated features, but in
  253. // practice it has been observed that the Chromebook sometimes does not
  254. // receive this message (see https://crbug.com/913816). Thus, schedule a sync
  255. // after the phone has had enough time to enable its features. Note that this
  256. // sync is canceled if the Chromebook does receive the push message.
  257. sync_timer_->Start(FROM_HERE, kSyncDelay,
  258. base::BindOnce(&HostVerifierImpl::OnSyncTimerFired,
  259. base::Unretained(this)));
  260. }
  261. void HostVerifierImpl::OnNotifyDevicesFinished(
  262. device_sync::mojom::NetworkRequestResult result) {
  263. if (result != device_sync::mojom::NetworkRequestResult::kSuccess) {
  264. PA_LOG(WARNING) << "HostVerifierImpl::OnNotifyDevicesFinished(): "
  265. << "NotifyDevices call failed. Retry is scheduled.";
  266. return;
  267. }
  268. // Now that the NotifyDevices call was sent successfully, the host phone is
  269. // expected to enable its supported features. This should trigger a push
  270. // message asking this Chromebook to sync these updated features, but in
  271. // practice it has been observed that the Chromebook sometimes does not
  272. // receive this message (see https://crbug.com/913816). Thus, schedule a sync
  273. // after the phone has had enough time to enable its features. Note that this
  274. // sync is canceled if the Chromebook does receive the push message.
  275. sync_timer_->Start(FROM_HERE, kSyncDelay,
  276. base::BindOnce(&HostVerifierImpl::OnSyncTimerFired,
  277. base::Unretained(this)));
  278. }
  279. void HostVerifierImpl::OnSyncTimerFired() {
  280. device_sync_client_->ForceSyncNow(base::DoNothing());
  281. }
  282. } // namespace multidevice_setup
  283. } // namespace ash