grandfathered_easy_unlock_host_disabler.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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/grandfathered_easy_unlock_host_disabler.h"
  5. #include "ash/components/multidevice/logging/logging.h"
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/services/device_sync/public/cpp/device_sync_client.h"
  8. #include "base/bind.h"
  9. #include "base/memory/ptr_util.h"
  10. #include "base/timer/timer.h"
  11. #include "components/prefs/pref_registry_simple.h"
  12. #include "components/prefs/pref_service.h"
  13. namespace ash {
  14. namespace multidevice_setup {
  15. namespace {
  16. // Name of the prefs that stores the legacy device ID and Instance ID of the
  17. // device which still potentially needs to have kSmartLockHost disabled on it.
  18. const char kEasyUnlockHostIdToDisablePrefName[] =
  19. "multidevice_setup.easy_unlock_host_id_to_disable";
  20. const char kEasyUnlockHostInstanceIdToDisablePrefName[] =
  21. "multidevice_setup.easy_unlock_host_instance_id_to_disable";
  22. const char kNoDevice[] = "";
  23. // The number of minutes to wait before retrying a failed attempt.
  24. const int kNumMinutesBetweenRetries = 5;
  25. bool IsEasyUnlockHost(const multidevice::RemoteDeviceRef& device) {
  26. return device.GetSoftwareFeatureState(
  27. multidevice::SoftwareFeature::kSmartLockHost) ==
  28. multidevice::SoftwareFeatureState::kEnabled;
  29. }
  30. } // namespace
  31. // static
  32. GrandfatheredEasyUnlockHostDisabler::Factory*
  33. GrandfatheredEasyUnlockHostDisabler::Factory::test_factory_ = nullptr;
  34. // static
  35. std::unique_ptr<GrandfatheredEasyUnlockHostDisabler>
  36. GrandfatheredEasyUnlockHostDisabler::Factory::Create(
  37. HostBackendDelegate* host_backend_delegate,
  38. device_sync::DeviceSyncClient* device_sync_client,
  39. PrefService* pref_service,
  40. std::unique_ptr<base::OneShotTimer> timer) {
  41. if (test_factory_) {
  42. return test_factory_->CreateInstance(host_backend_delegate,
  43. device_sync_client, pref_service,
  44. std::move(timer));
  45. }
  46. return base::WrapUnique(new GrandfatheredEasyUnlockHostDisabler(
  47. host_backend_delegate, device_sync_client, pref_service,
  48. std::move(timer)));
  49. }
  50. // static
  51. void GrandfatheredEasyUnlockHostDisabler::Factory::SetFactoryForTesting(
  52. Factory* test_factory) {
  53. test_factory_ = test_factory;
  54. }
  55. GrandfatheredEasyUnlockHostDisabler::Factory::~Factory() = default;
  56. // static
  57. void GrandfatheredEasyUnlockHostDisabler::RegisterPrefs(
  58. PrefRegistrySimple* registry) {
  59. registry->RegisterStringPref(kEasyUnlockHostIdToDisablePrefName, kNoDevice);
  60. registry->RegisterStringPref(kEasyUnlockHostInstanceIdToDisablePrefName,
  61. kNoDevice);
  62. }
  63. GrandfatheredEasyUnlockHostDisabler::~GrandfatheredEasyUnlockHostDisabler() {
  64. host_backend_delegate_->RemoveObserver(this);
  65. }
  66. GrandfatheredEasyUnlockHostDisabler::GrandfatheredEasyUnlockHostDisabler(
  67. HostBackendDelegate* host_backend_delegate,
  68. device_sync::DeviceSyncClient* device_sync_client,
  69. PrefService* pref_service,
  70. std::unique_ptr<base::OneShotTimer> timer)
  71. : host_backend_delegate_(host_backend_delegate),
  72. device_sync_client_(device_sync_client),
  73. pref_service_(pref_service),
  74. timer_(std::move(timer)),
  75. current_better_together_host_(
  76. host_backend_delegate_->GetMultiDeviceHostFromBackend()) {
  77. host_backend_delegate_->AddObserver(this);
  78. // There might be a device stored in the pref waiting for kSmartLockHost to
  79. // be disabled.
  80. DisableEasyUnlockHostIfNecessary();
  81. }
  82. void GrandfatheredEasyUnlockHostDisabler::OnHostChangedOnBackend() {
  83. // kSmartLockHost possibly needs to be disabled on the previous
  84. // BetterTogether host.
  85. SetPotentialEasyUnlockHostToDisable(current_better_together_host_);
  86. // Retrieve the new BetterTogether host.
  87. current_better_together_host_ =
  88. host_backend_delegate_->GetMultiDeviceHostFromBackend();
  89. DisableEasyUnlockHostIfNecessary();
  90. }
  91. void GrandfatheredEasyUnlockHostDisabler::DisableEasyUnlockHostIfNecessary() {
  92. timer_->Stop();
  93. absl::optional<multidevice::RemoteDeviceRef> host_to_disable =
  94. GetEasyUnlockHostToDisable();
  95. if (!host_to_disable)
  96. return;
  97. PA_LOG(VERBOSE) << "Attempting to disable kSmartLockHost on device "
  98. << host_to_disable->GetInstanceIdDeviceIdForLogs();
  99. if (features::ShouldUseV1DeviceSync()) {
  100. // Even if the host has a non-trivial Instance ID, we still invoke the v1
  101. // DeviceSync RPC to set the feature state. This ensures that GmsCore will
  102. // be notified of the change regardless of what version of DeviceSync it is
  103. // running. The v1 and v2 RPCs to change feature states ultimately update
  104. // the same backend database entry. Note: The RemoteDeviceProvider
  105. // guarantees that every device will have a public key while v1 DeviceSync
  106. // is enabled.
  107. DCHECK(!host_to_disable->public_key().empty());
  108. device_sync_client_->SetSoftwareFeatureState(
  109. host_to_disable->public_key(),
  110. multidevice::SoftwareFeature::kSmartLockHost, false /* enabled */,
  111. false /* is_exclusive */,
  112. base::BindOnce(
  113. &GrandfatheredEasyUnlockHostDisabler::OnDisableEasyUnlockHostResult,
  114. weak_ptr_factory_.GetWeakPtr(), *host_to_disable));
  115. } else {
  116. DCHECK(!host_to_disable->instance_id().empty());
  117. device_sync_client_->SetFeatureStatus(
  118. host_to_disable->instance_id(),
  119. multidevice::SoftwareFeature::kSmartLockHost,
  120. device_sync::FeatureStatusChange::kDisable,
  121. base::BindOnce(
  122. &GrandfatheredEasyUnlockHostDisabler::OnDisableEasyUnlockHostResult,
  123. weak_ptr_factory_.GetWeakPtr(), *host_to_disable));
  124. }
  125. }
  126. void GrandfatheredEasyUnlockHostDisabler::OnDisableEasyUnlockHostResult(
  127. multidevice::RemoteDeviceRef device,
  128. device_sync::mojom::NetworkRequestResult result_code) {
  129. bool success =
  130. result_code == device_sync::mojom::NetworkRequestResult::kSuccess;
  131. if (success) {
  132. PA_LOG(VERBOSE) << "Successfully disabled kSmartLockHost on device "
  133. << device.GetInstanceIdDeviceIdForLogs();
  134. } else {
  135. PA_LOG(WARNING) << "Failed to disable kSmartLockHost on device "
  136. << device.GetInstanceIdDeviceIdForLogs()
  137. << ", Error code: " << result_code;
  138. }
  139. // Return if the EasyUnlock host to disable changed between calls to
  140. // DisableEasyUnlockHostIfNecessary() and OnDisableEasyUnlockHostResult().
  141. if (device != GetEasyUnlockHostToDisable())
  142. return;
  143. if (success) {
  144. SetPotentialEasyUnlockHostToDisable(absl::nullopt);
  145. return;
  146. }
  147. PA_LOG(WARNING) << "Retrying in " << kNumMinutesBetweenRetries
  148. << " minutes if necessary.";
  149. timer_->Start(FROM_HERE, base::Minutes(kNumMinutesBetweenRetries),
  150. base::BindOnce(&GrandfatheredEasyUnlockHostDisabler::
  151. DisableEasyUnlockHostIfNecessary,
  152. base::Unretained(this)));
  153. }
  154. void GrandfatheredEasyUnlockHostDisabler::SetPotentialEasyUnlockHostToDisable(
  155. absl::optional<multidevice::RemoteDeviceRef> device) {
  156. pref_service_->SetString(kEasyUnlockHostIdToDisablePrefName,
  157. !device || device->GetDeviceId().empty()
  158. ? kNoDevice
  159. : device->GetDeviceId());
  160. pref_service_->SetString(kEasyUnlockHostInstanceIdToDisablePrefName,
  161. !device || device->instance_id().empty()
  162. ? kNoDevice
  163. : device->instance_id());
  164. }
  165. absl::optional<multidevice::RemoteDeviceRef>
  166. GrandfatheredEasyUnlockHostDisabler::GetEasyUnlockHostToDisable() {
  167. std::string legacy_device_id =
  168. pref_service_->GetString(kEasyUnlockHostIdToDisablePrefName);
  169. std::string instance_id =
  170. pref_service_->GetString(kEasyUnlockHostInstanceIdToDisablePrefName);
  171. if (legacy_device_id == kNoDevice && instance_id == kNoDevice)
  172. return absl::nullopt;
  173. multidevice::RemoteDeviceRefList synced_devices =
  174. device_sync_client_->GetSyncedDevices();
  175. auto it = std::find_if(
  176. synced_devices.begin(), synced_devices.end(),
  177. [&legacy_device_id, &instance_id](const auto& remote_device) {
  178. return (legacy_device_id != kNoDevice &&
  179. remote_device.GetDeviceId() == legacy_device_id) ||
  180. (instance_id != kNoDevice &&
  181. remote_device.instance_id() == instance_id);
  182. });
  183. // The device does not need to have kSmartLockHost disabled if any of the
  184. // following are true:
  185. // - the device is not in the list of synced devices anymore,
  186. // - the device is not the current EasyUnlock host, or
  187. // - the device is the BetterTogether host.
  188. if (it == synced_devices.end() || !IsEasyUnlockHost(*it) ||
  189. *it == current_better_together_host_) {
  190. SetPotentialEasyUnlockHostToDisable(absl::nullopt);
  191. return absl::nullopt;
  192. }
  193. return *it;
  194. }
  195. } // namespace multidevice_setup
  196. } // namespace ash