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
5 #include "chromeos/services/multidevice_setup/host_status_provider_impl.h"
6
7 #include <algorithm>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "chromeos/components/multidevice/logging/logging.h"
12 #include "chromeos/services/multidevice_setup/eligible_host_devices_provider.h"
13
14 namespace chromeos {
15
16 namespace multidevice_setup {
17
18 namespace {
19
RecordMultiDeviceHostStatus(mojom::HostStatus host_status)20 static void RecordMultiDeviceHostStatus(mojom::HostStatus host_status) {
21 UMA_HISTOGRAM_ENUMERATION("MultiDevice.Setup.HostStatus", host_status);
22 }
23
24 } // namespace
25
26 // static
27 HostStatusProviderImpl::Factory*
28 HostStatusProviderImpl::Factory::test_factory_ = nullptr;
29
30 // static
Create(EligibleHostDevicesProvider * eligible_host_devices_provider,HostBackendDelegate * host_backend_delegate,HostVerifier * host_verifier,device_sync::DeviceSyncClient * device_sync_client)31 std::unique_ptr<HostStatusProvider> HostStatusProviderImpl::Factory::Create(
32 EligibleHostDevicesProvider* eligible_host_devices_provider,
33 HostBackendDelegate* host_backend_delegate,
34 HostVerifier* host_verifier,
35 device_sync::DeviceSyncClient* device_sync_client) {
36 if (test_factory_) {
37 return test_factory_->CreateInstance(eligible_host_devices_provider,
38 host_backend_delegate, host_verifier,
39 device_sync_client);
40 }
41
42 return base::WrapUnique(new HostStatusProviderImpl(
43 eligible_host_devices_provider, host_backend_delegate, host_verifier,
44 device_sync_client));
45 }
46
47 // static
SetFactoryForTesting(Factory * test_factory)48 void HostStatusProviderImpl::Factory::SetFactoryForTesting(
49 Factory* test_factory) {
50 test_factory_ = test_factory;
51 }
52
53 HostStatusProviderImpl::Factory::~Factory() = default;
54
HostStatusProviderImpl(EligibleHostDevicesProvider * eligible_host_devices_provider,HostBackendDelegate * host_backend_delegate,HostVerifier * host_verifier,device_sync::DeviceSyncClient * device_sync_client)55 HostStatusProviderImpl::HostStatusProviderImpl(
56 EligibleHostDevicesProvider* eligible_host_devices_provider,
57 HostBackendDelegate* host_backend_delegate,
58 HostVerifier* host_verifier,
59 device_sync::DeviceSyncClient* device_sync_client)
60 : eligible_host_devices_provider_(eligible_host_devices_provider),
61 host_backend_delegate_(host_backend_delegate),
62 host_verifier_(host_verifier),
63 device_sync_client_(device_sync_client),
64 current_status_and_device_(mojom::HostStatus::kNoEligibleHosts,
65 base::nullopt /* host_device */) {
66 host_backend_delegate_->AddObserver(this);
67 host_verifier_->AddObserver(this);
68 device_sync_client_->AddObserver(this);
69
70 CheckForUpdatedStatusAndNotifyIfChanged(
71 /*force_notify_host_status_change=*/false);
72 RecordMultiDeviceHostStatus(current_status_and_device_.host_status());
73 }
74
~HostStatusProviderImpl()75 HostStatusProviderImpl::~HostStatusProviderImpl() {
76 host_backend_delegate_->RemoveObserver(this);
77 host_verifier_->RemoveObserver(this);
78 device_sync_client_->RemoveObserver(this);
79 }
80
81 HostStatusProvider::HostStatusWithDevice
GetHostWithStatus() const82 HostStatusProviderImpl::GetHostWithStatus() const {
83 return current_status_and_device_;
84 }
85
OnHostChangedOnBackend()86 void HostStatusProviderImpl::OnHostChangedOnBackend() {
87 CheckForUpdatedStatusAndNotifyIfChanged(
88 /*force_notify_host_status_change=*/false);
89 }
90
OnPendingHostRequestChange()91 void HostStatusProviderImpl::OnPendingHostRequestChange() {
92 CheckForUpdatedStatusAndNotifyIfChanged(
93 /*force_notify_host_status_change=*/false);
94 }
95
OnHostVerified()96 void HostStatusProviderImpl::OnHostVerified() {
97 CheckForUpdatedStatusAndNotifyIfChanged(
98 /*force_notify_host_status_change=*/false);
99 }
100
OnNewDevicesSynced()101 void HostStatusProviderImpl::OnNewDevicesSynced() {
102 CheckForUpdatedStatusAndNotifyIfChanged(
103 /*force_notify_host_status_change=*/true);
104 }
105
CheckForUpdatedStatusAndNotifyIfChanged(bool force_notify_host_status_change)106 void HostStatusProviderImpl::CheckForUpdatedStatusAndNotifyIfChanged(
107 bool force_notify_host_status_change) {
108 HostStatusWithDevice current_status_and_device = GetCurrentStatus();
109 if (current_status_and_device == current_status_and_device_) {
110 if (force_notify_host_status_change) {
111 // If the RemoteDevice the host device references has changed, but not its
112 // contents, fire a host status change. Note that since the status doesn't
113 // actually change, neither logging nor metric collection should occur.
114 NotifyHostStatusChange(current_status_and_device_.host_status(),
115 current_status_and_device_.host_device());
116 }
117 return;
118 }
119
120 PA_LOG(VERBOSE) << "HostStatusProviderImpl::"
121 << "CheckForUpdatedStatusAndNotifyIfChanged(): Host status "
122 << "changed. New status: "
123 << current_status_and_device.host_status() << ", Old status: "
124 << current_status_and_device_.host_status()
125 << ", Host device: "
126 << (current_status_and_device.host_device()
127 ? current_status_and_device.host_device()
128 ->GetInstanceIdDeviceIdForLogs()
129 : "[no host]");
130
131 current_status_and_device_ = current_status_and_device;
132 NotifyHostStatusChange(current_status_and_device_.host_status(),
133 current_status_and_device_.host_device());
134 RecordMultiDeviceHostStatus(current_status_and_device_.host_status());
135 }
136
137 HostStatusProvider::HostStatusWithDevice
GetCurrentStatus()138 HostStatusProviderImpl::GetCurrentStatus() {
139 if (host_verifier_->IsHostVerified()) {
140 return HostStatusWithDevice(
141 mojom::HostStatus::kHostVerified,
142 *host_backend_delegate_->GetMultiDeviceHostFromBackend());
143 }
144
145 if (host_backend_delegate_->GetMultiDeviceHostFromBackend() &&
146 !host_backend_delegate_->HasPendingHostRequest()) {
147 return HostStatusWithDevice(
148 mojom::HostStatus::kHostSetButNotYetVerified,
149 *host_backend_delegate_->GetMultiDeviceHostFromBackend());
150 }
151
152 if (host_backend_delegate_->HasPendingHostRequest() &&
153 host_backend_delegate_->GetPendingHostRequest()) {
154 return HostStatusWithDevice(
155 mojom::HostStatus::kHostSetLocallyButWaitingForBackendConfirmation,
156 *host_backend_delegate_->GetPendingHostRequest());
157 }
158
159 if (!eligible_host_devices_provider_->GetEligibleHostDevices().empty()) {
160 return HostStatusWithDevice(
161 mojom::HostStatus::kEligibleHostExistsButNoHostSet,
162 base::nullopt /* host_device */);
163 }
164
165 return HostStatusWithDevice(mojom::HostStatus::kNoEligibleHosts,
166 base::nullopt /* host_device */);
167 }
168
169 } // namespace multidevice_setup
170
171 } // namespace chromeos
172