123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <utility>
- #include <vector>
- #include "ash/services/multidevice_setup/multidevice_setup_impl.h"
- #include "ash/components/multidevice/logging/logging.h"
- #include "ash/constants/ash_features.h"
- #include "ash/services/multidevice_setup/account_status_change_delegate_notifier_impl.h"
- #include "ash/services/multidevice_setup/android_sms_app_installing_status_observer.h"
- #include "ash/services/multidevice_setup/eligible_host_devices_provider_impl.h"
- #include "ash/services/multidevice_setup/feature_state_manager_impl.h"
- #include "ash/services/multidevice_setup/global_state_feature_manager.h"
- #include "ash/services/multidevice_setup/global_state_feature_manager_impl.h"
- #include "ash/services/multidevice_setup/grandfathered_easy_unlock_host_disabler.h"
- #include "ash/services/multidevice_setup/host_backend_delegate_impl.h"
- #include "ash/services/multidevice_setup/host_device_timestamp_manager_impl.h"
- #include "ash/services/multidevice_setup/host_status_provider_impl.h"
- #include "ash/services/multidevice_setup/host_verifier_impl.h"
- #include "ash/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h"
- #include "ash/services/multidevice_setup/public/cpp/android_sms_pairing_state_tracker.h"
- #include "ash/services/multidevice_setup/public/cpp/auth_token_validator.h"
- #include "ash/services/multidevice_setup/public/cpp/oobe_completion_tracker.h"
- #include "ash/services/multidevice_setup/public/mojom/multidevice_setup.mojom.h"
- #include "ash/services/multidevice_setup/wifi_sync_notification_controller.h"
- #include "base/containers/contains.h"
- #include "base/containers/flat_set.h"
- #include "base/memory/ptr_util.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/histogram_macros.h"
- #include "base/time/default_clock.h"
- namespace ash {
- namespace multidevice_setup {
- namespace {
- const char kTestDeviceNameForDebugNotification[] = "Test Device";
- // This enum is tied directly to a UMA enum defined in
- // //tools/metrics/histograms/enums.xml, and should always reflect it (do not
- // change one without changing the other). Entries should be never modified
- // or deleted. Only additions possible.
- enum class VerifyAndForgetHostConfirmationState {
- kButtonClickedState = 0,
- kCompletedSetupState = 1,
- kMaxValue = kCompletedSetupState,
- };
- static void LogForgetHostConfirmed(VerifyAndForgetHostConfirmationState state) {
- UMA_HISTOGRAM_ENUMERATION("MultiDevice.ForgetHostConfirmed", state);
- }
- static void LogVerifyButtonClicked(VerifyAndForgetHostConfirmationState state) {
- UMA_HISTOGRAM_ENUMERATION("MultiDevice.VerifyButtonClicked", state);
- }
- } // namespace
- // static
- MultiDeviceSetupImpl::Factory* MultiDeviceSetupImpl::Factory::test_factory_ =
- nullptr;
- // static
- std::unique_ptr<MultiDeviceSetupBase> MultiDeviceSetupImpl::Factory::Create(
- PrefService* pref_service,
- device_sync::DeviceSyncClient* device_sync_client,
- AuthTokenValidator* auth_token_validator,
- OobeCompletionTracker* oobe_completion_tracker,
- AndroidSmsAppHelperDelegate* android_sms_app_helper_delegate,
- AndroidSmsPairingStateTracker* android_sms_pairing_state_tracker,
- const device_sync::GcmDeviceInfoProvider* gcm_device_info_provider,
- bool is_secondary_user) {
- if (test_factory_) {
- return test_factory_->CreateInstance(
- pref_service, device_sync_client, auth_token_validator,
- oobe_completion_tracker, android_sms_app_helper_delegate,
- android_sms_pairing_state_tracker, gcm_device_info_provider,
- is_secondary_user);
- }
- return base::WrapUnique(new MultiDeviceSetupImpl(
- pref_service, device_sync_client, auth_token_validator,
- oobe_completion_tracker, android_sms_app_helper_delegate,
- android_sms_pairing_state_tracker, gcm_device_info_provider,
- is_secondary_user));
- }
- // static
- void MultiDeviceSetupImpl::Factory::SetFactoryForTesting(
- Factory* test_factory) {
- test_factory_ = test_factory;
- }
- MultiDeviceSetupImpl::Factory::~Factory() = default;
- MultiDeviceSetupImpl::MultiDeviceSetupImpl(
- PrefService* pref_service,
- device_sync::DeviceSyncClient* device_sync_client,
- AuthTokenValidator* auth_token_validator,
- OobeCompletionTracker* oobe_completion_tracker,
- AndroidSmsAppHelperDelegate* android_sms_app_helper_delegate,
- AndroidSmsPairingStateTracker* android_sms_pairing_state_tracker,
- const device_sync::GcmDeviceInfoProvider* gcm_device_info_provider,
- bool is_secondary_user)
- : eligible_host_devices_provider_(
- EligibleHostDevicesProviderImpl::Factory::Create(device_sync_client)),
- host_backend_delegate_(HostBackendDelegateImpl::Factory::Create(
- eligible_host_devices_provider_.get(),
- pref_service,
- device_sync_client)),
- host_verifier_(
- HostVerifierImpl::Factory::Create(host_backend_delegate_.get(),
- device_sync_client,
- pref_service)),
- host_status_provider_(HostStatusProviderImpl::Factory::Create(
- eligible_host_devices_provider_.get(),
- host_backend_delegate_.get(),
- host_verifier_.get(),
- device_sync_client)),
- grandfathered_easy_unlock_host_disabler_(
- GrandfatheredEasyUnlockHostDisabler::Factory::Create(
- host_backend_delegate_.get(),
- device_sync_client,
- pref_service)),
- host_device_timestamp_manager_(
- HostDeviceTimestampManagerImpl::Factory::Create(
- host_status_provider_.get(),
- pref_service,
- base::DefaultClock::GetInstance())),
- delegate_notifier_(
- AccountStatusChangeDelegateNotifierImpl::Factory::Create(
- host_status_provider_.get(),
- pref_service,
- host_device_timestamp_manager_.get(),
- oobe_completion_tracker,
- base::DefaultClock::GetInstance())),
- wifi_sync_feature_manager_(GlobalStateFeatureManagerImpl::Factory::Create(
- GlobalStateFeatureManagerImpl::Factory::Option::kWifiSync,
- host_status_provider_.get(),
- pref_service,
- device_sync_client)),
- wifi_sync_notification_controller_(
- WifiSyncNotificationController::Factory::Create(
- wifi_sync_feature_manager_.get(),
- host_status_provider_.get(),
- pref_service,
- device_sync_client,
- delegate_notifier_.get())),
- feature_state_manager_(FeatureStateManagerImpl::Factory::Create(
- pref_service,
- host_status_provider_.get(),
- device_sync_client,
- android_sms_pairing_state_tracker,
- {{mojom::Feature::kWifiSync, wifi_sync_feature_manager_.get()}},
- is_secondary_user)),
- android_sms_app_installing_host_observer_(
- android_sms_app_helper_delegate
- ? AndroidSmsAppInstallingStatusObserver::Factory::Create(
- host_status_provider_.get(),
- feature_state_manager_.get(),
- android_sms_app_helper_delegate,
- pref_service)
- : nullptr),
- auth_token_validator_(auth_token_validator) {
- host_status_provider_->AddObserver(this);
- feature_state_manager_->AddObserver(this);
- }
- MultiDeviceSetupImpl::~MultiDeviceSetupImpl() {
- host_status_provider_->RemoveObserver(this);
- feature_state_manager_->RemoveObserver(this);
- }
- void MultiDeviceSetupImpl::SetAccountStatusChangeDelegate(
- mojo::PendingRemote<mojom::AccountStatusChangeDelegate> delegate) {
- delegate_notifier_->SetAccountStatusChangeDelegateRemote(std::move(delegate));
- }
- void MultiDeviceSetupImpl::AddHostStatusObserver(
- mojo::PendingRemote<mojom::HostStatusObserver> observer) {
- host_status_observers_.Add(std::move(observer));
- }
- void MultiDeviceSetupImpl::AddFeatureStateObserver(
- mojo::PendingRemote<mojom::FeatureStateObserver> observer) {
- feature_state_observers_.Add(std::move(observer));
- }
- void MultiDeviceSetupImpl::GetEligibleHostDevices(
- GetEligibleHostDevicesCallback callback) {
- std::vector<multidevice::RemoteDevice> eligible_remote_devices;
- for (const auto& remote_device_ref :
- eligible_host_devices_provider_->GetEligibleHostDevices()) {
- eligible_remote_devices.push_back(remote_device_ref.GetRemoteDevice());
- }
- std::move(callback).Run(eligible_remote_devices);
- }
- void MultiDeviceSetupImpl::GetEligibleActiveHostDevices(
- GetEligibleActiveHostDevicesCallback callback) {
- // For metrics.
- bool has_duplicate_host_name = false;
- base::flat_set<std::string> name_set;
- std::vector<mojom::HostDevicePtr> eligible_active_hosts;
- for (const auto& host_device :
- eligible_host_devices_provider_->GetEligibleActiveHostDevices()) {
- // For metrics.
- if (base::Contains(name_set, host_device.remote_device.name())) {
- has_duplicate_host_name = true;
- PA_LOG(WARNING) << "MultiDeviceSetupImpl::GetEligibleActiveHostDevices: "
- << "Detected duplicate eligible host device name \""
- << host_device.remote_device.name() << "\"";
- } else {
- name_set.insert(host_device.remote_device.name());
- }
- eligible_active_hosts.push_back(
- mojom::HostDevice::New(host_device.remote_device.GetRemoteDevice(),
- host_device.connectivity_status));
- }
- base::UmaHistogramBoolean(
- "MultiDevice.Setup.HasDuplicateEligibleHostDeviceNames",
- has_duplicate_host_name);
- std::move(callback).Run(std::move(eligible_active_hosts));
- }
- void MultiDeviceSetupImpl::SetHostDevice(
- const std::string& host_instance_id_or_legacy_device_id,
- const std::string& auth_token,
- SetHostDeviceCallback callback) {
- if (!auth_token_validator_->IsAuthTokenValid(auth_token)) {
- std::move(callback).Run(false /* success */);
- return;
- }
- std::move(callback).Run(AttemptSetHost(host_instance_id_or_legacy_device_id));
- }
- void MultiDeviceSetupImpl::RemoveHostDevice() {
- LogForgetHostConfirmed(
- VerifyAndForgetHostConfirmationState::kButtonClickedState);
- host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(
- absl::nullopt /* host_device */);
- }
- void MultiDeviceSetupImpl::GetHostStatus(GetHostStatusCallback callback) {
- HostStatusProvider::HostStatusWithDevice host_status_with_device =
- host_status_provider_->GetHostWithStatus();
- // The Mojo API requires a raw multidevice::RemoteDevice instead of a
- // multidevice::RemoteDeviceRef.
- absl::optional<multidevice::RemoteDevice> device_for_callback;
- if (host_status_with_device.host_device()) {
- device_for_callback =
- host_status_with_device.host_device()->GetRemoteDevice();
- }
- std::move(callback).Run(host_status_with_device.host_status(),
- device_for_callback);
- }
- void MultiDeviceSetupImpl::SetFeatureEnabledState(
- mojom::Feature feature,
- bool enabled,
- const absl::optional<std::string>& auth_token,
- SetFeatureEnabledStateCallback callback) {
- if (IsAuthTokenRequiredForFeatureStateChange(feature, enabled) &&
- (!auth_token || !auth_token_validator_->IsAuthTokenValid(*auth_token))) {
- PA_LOG(ERROR) << __func__ << " Cannot " << (enabled ? "enable" : "disable")
- << " " << feature << "; auth token invalid";
- std::move(callback).Run(false /* success */);
- return;
- }
- std::move(callback).Run(
- feature_state_manager_->SetFeatureEnabledState(feature, enabled));
- }
- void MultiDeviceSetupImpl::GetFeatureStates(GetFeatureStatesCallback callback) {
- std::move(callback).Run(feature_state_manager_->GetFeatureStates());
- }
- void MultiDeviceSetupImpl::RetrySetHostNow(RetrySetHostNowCallback callback) {
- LogVerifyButtonClicked(
- VerifyAndForgetHostConfirmationState::kButtonClickedState);
- HostStatusProvider::HostStatusWithDevice host_status_with_device =
- host_status_provider_->GetHostWithStatus();
- if (host_status_with_device.host_status() ==
- mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation) {
- host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(
- *host_backend_delegate_->GetPendingHostRequest());
- std::move(callback).Run(true /* success */);
- return;
- }
- if (host_status_with_device.host_status() ==
- mojom::HostStatus::kHostSetButNotYetVerified) {
- host_verifier_->AttemptVerificationNow();
- std::move(callback).Run(true /* success */);
- return;
- }
- // RetrySetHostNow() was called when there was nothing to retry.
- std::move(callback).Run(false /* success */);
- }
- void MultiDeviceSetupImpl::TriggerEventForDebugging(
- mojom::EventTypeForDebugging type,
- TriggerEventForDebuggingCallback callback) {
- if (!delegate_notifier_->delegate_remote_) {
- PA_LOG(ERROR) << "MultiDeviceSetupImpl::TriggerEventForDebugging(): No "
- << "delgate has been set; cannot proceed.";
- std::move(callback).Run(false /* success */);
- return;
- }
- PA_LOG(VERBOSE) << "MultiDeviceSetupImpl::TriggerEventForDebugging(" << type
- << ") called.";
- mojom::AccountStatusChangeDelegate* delegate =
- delegate_notifier_->delegate_remote_.get();
- switch (type) {
- case mojom::EventTypeForDebugging::kNewUserPotentialHostExists:
- delegate->OnPotentialHostExistsForNewUser();
- break;
- case mojom::EventTypeForDebugging::kExistingUserConnectedHostSwitched:
- delegate->OnConnectedHostSwitchedForExistingUser(
- kTestDeviceNameForDebugNotification);
- break;
- case mojom::EventTypeForDebugging::kExistingUserNewChromebookAdded:
- delegate->OnNewChromebookAddedForExistingUser(
- kTestDeviceNameForDebugNotification);
- break;
- default:
- NOTREACHED();
- }
- std::move(callback).Run(true /* success */);
- }
- void MultiDeviceSetupImpl::SetHostDeviceWithoutAuthToken(
- const std::string& host_instance_id_or_legacy_device_id,
- mojom::PrivilegedHostDeviceSetter::SetHostDeviceCallback callback) {
- std::move(callback).Run(AttemptSetHost(host_instance_id_or_legacy_device_id));
- }
- void MultiDeviceSetupImpl::OnHostStatusChange(
- const HostStatusProvider::HostStatusWithDevice& host_status_with_device) {
- mojom::HostStatus status_for_callback = host_status_with_device.host_status();
- // The Mojo API requires a raw multidevice::RemoteDevice instead of a
- // multidevice::RemoteDeviceRef.
- absl::optional<multidevice::RemoteDevice> device_for_callback;
- if (host_status_with_device.host_device()) {
- device_for_callback =
- host_status_with_device.host_device()->GetRemoteDevice();
- }
- for (auto& observer : host_status_observers_)
- observer->OnHostStatusChanged(status_for_callback, device_for_callback);
- }
- void MultiDeviceSetupImpl::OnFeatureStatesChange(
- const FeatureStateManager::FeatureStatesMap& feature_states_map) {
- for (auto& observer : feature_state_observers_)
- observer->OnFeatureStatesChanged(feature_states_map);
- }
- bool MultiDeviceSetupImpl::AttemptSetHost(
- const std::string& host_instance_id_or_legacy_device_id) {
- DCHECK(!host_instance_id_or_legacy_device_id.empty());
- multidevice::RemoteDeviceRefList eligible_devices =
- eligible_host_devices_provider_->GetEligibleHostDevices();
- auto it = std::find_if(
- eligible_devices.begin(), eligible_devices.end(),
- [&host_instance_id_or_legacy_device_id](const auto& eligible_device) {
- if (features::ShouldUseV1DeviceSync()) {
- return eligible_device.instance_id() ==
- host_instance_id_or_legacy_device_id ||
- eligible_device.GetDeviceId() ==
- host_instance_id_or_legacy_device_id;
- }
- return eligible_device.instance_id() ==
- host_instance_id_or_legacy_device_id;
- });
- if (it == eligible_devices.end())
- return false;
- LogForgetHostConfirmed(
- VerifyAndForgetHostConfirmationState::kCompletedSetupState);
- LogVerifyButtonClicked(
- VerifyAndForgetHostConfirmationState::kCompletedSetupState);
- host_backend_delegate_->AttemptToSetMultiDeviceHostOnBackend(*it);
- return true;
- }
- bool MultiDeviceSetupImpl::IsAuthTokenRequiredForFeatureStateChange(
- mojom::Feature feature,
- bool enabled) {
- // Disabling a feature never requires authentication.
- if (!enabled)
- return false;
- // Enabling SmartLock always requires authentication.
- if (feature == mojom::Feature::kSmartLock)
- return true;
- // Enabling any feature besides SmartLock and the Better Together suite does
- // not require authentication.
- if (feature != mojom::Feature::kBetterTogetherSuite)
- return false;
- mojom::FeatureState smart_lock_state =
- feature_state_manager_->GetFeatureStates()[mojom::Feature::kSmartLock];
- // If the user is enabling the Better Together suite and this change would
- // result in SmartLock being implicitly enabled, authentication is required.
- // SmartLock is implicitly enabled if it is only currently not enabled due
- // to the suite being disabled or due to the SmartLock host device not
- // having a lock screen set.
- return smart_lock_state == mojom::FeatureState::kUnavailableSuiteDisabled ||
- smart_lock_state ==
- mojom::FeatureState::kUnavailableInsufficientSecurity;
- }
- void MultiDeviceSetupImpl::FlushForTesting() {
- host_status_observers_.FlushForTesting();
- feature_state_observers_.FlushForTesting();
- }
- } // namespace multidevice_setup
- } // namespace ash
|