1 // Copyright 2016 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/components/tether/tether_component_impl.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/ptr_util.h"
12 #include "chromeos/components/multidevice/logging/logging.h"
13 #include "chromeos/components/tether/active_host.h"
14 #include "chromeos/components/tether/asynchronous_shutdown_object_container_impl.h"
15 #include "chromeos/components/tether/crash_recovery_manager_impl.h"
16 #include "chromeos/components/tether/host_scan_scheduler.h"
17 #include "chromeos/components/tether/persistent_host_scan_cache_impl.h"
18 #include "chromeos/components/tether/synchronous_shutdown_object_container_impl.h"
19 #include "chromeos/components/tether/tether_disconnector.h"
20 #include "chromeos/components/tether/tether_host_response_recorder.h"
21 #include "chromeos/components/tether/tether_session_completion_logger.h"
22 #include "chromeos/components/tether/wifi_hotspot_disconnector_impl.h"
23 #include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
24 #include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client.h"
25 #include "components/pref_registry/pref_registry_syncable.h"
26
27 namespace chromeos {
28
29 namespace tether {
30
31 namespace {
32
OnDisconnectErrorDuringShutdown(const std::string & error_name)33 void OnDisconnectErrorDuringShutdown(const std::string& error_name) {
34 PA_LOG(WARNING) << "Error disconnecting from Tether network during shutdown; "
35 << "Error name: " << error_name;
36 }
37
38 TetherSessionCompletionLogger::SessionCompletionReason
GetSessionCompletionReasonFromShutdownReason(TetherComponent::ShutdownReason shutdown_reason)39 GetSessionCompletionReasonFromShutdownReason(
40 TetherComponent::ShutdownReason shutdown_reason) {
41 switch (shutdown_reason) {
42 case TetherComponent::ShutdownReason::OTHER:
43 return TetherSessionCompletionLogger::SessionCompletionReason::OTHER;
44 case TetherComponent::ShutdownReason::USER_LOGGED_OUT:
45 return TetherSessionCompletionLogger::SessionCompletionReason::
46 USER_LOGGED_OUT;
47 case TetherComponent::ShutdownReason::USER_CLOSED_LID:
48 return TetherSessionCompletionLogger::SessionCompletionReason::
49 USER_CLOSED_LID;
50 case TetherComponent::ShutdownReason::PREF_DISABLED:
51 return TetherSessionCompletionLogger::SessionCompletionReason::
52 PREF_DISABLED;
53 case TetherComponent::ShutdownReason::BLUETOOTH_DISABLED:
54 return TetherSessionCompletionLogger::SessionCompletionReason::
55 BLUETOOTH_DISABLED;
56 case TetherComponent::ShutdownReason::CELLULAR_DISABLED:
57 return TetherSessionCompletionLogger::SessionCompletionReason::
58 CELLULAR_DISABLED;
59 case TetherComponent::ShutdownReason::MULTIDEVICE_HOST_UNVERIFIED:
60 return TetherSessionCompletionLogger::SessionCompletionReason::
61 MULTIDEVICE_HOST_UNVERIFIED;
62 case TetherComponent::ShutdownReason::BETTER_TOGETHER_SUITE_DISABLED:
63 return TetherSessionCompletionLogger::SessionCompletionReason::
64 BETTER_TOGETHER_SUITE_DISABLED;
65 default:
66 break;
67 }
68
69 return TetherSessionCompletionLogger::SessionCompletionReason::OTHER;
70 }
71
72 } // namespace
73
74 // static
75 TetherComponentImpl::Factory* TetherComponentImpl::Factory::factory_instance_ =
76 nullptr;
77
78 // static
Create(device_sync::DeviceSyncClient * device_sync_client,secure_channel::SecureChannelClient * secure_channel_client,TetherHostFetcher * tether_host_fetcher,NotificationPresenter * notification_presenter,GmsCoreNotificationsStateTrackerImpl * gms_core_notifications_state_tracker,PrefService * pref_service,NetworkStateHandler * network_state_handler,ManagedNetworkConfigurationHandler * managed_network_configuration_handler,NetworkConnect * network_connect,NetworkConnectionHandler * network_connection_handler,scoped_refptr<device::BluetoothAdapter> adapter,session_manager::SessionManager * session_manager)79 std::unique_ptr<TetherComponent> TetherComponentImpl::Factory::Create(
80 device_sync::DeviceSyncClient* device_sync_client,
81 secure_channel::SecureChannelClient* secure_channel_client,
82 TetherHostFetcher* tether_host_fetcher,
83 NotificationPresenter* notification_presenter,
84 GmsCoreNotificationsStateTrackerImpl* gms_core_notifications_state_tracker,
85 PrefService* pref_service,
86 NetworkStateHandler* network_state_handler,
87 ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
88 NetworkConnect* network_connect,
89 NetworkConnectionHandler* network_connection_handler,
90 scoped_refptr<device::BluetoothAdapter> adapter,
91 session_manager::SessionManager* session_manager) {
92 if (factory_instance_) {
93 return factory_instance_->CreateInstance(
94 device_sync_client, secure_channel_client, tether_host_fetcher,
95 notification_presenter, gms_core_notifications_state_tracker,
96 pref_service, network_state_handler,
97 managed_network_configuration_handler, network_connect,
98 network_connection_handler, adapter, session_manager);
99 }
100
101 return base::WrapUnique(new TetherComponentImpl(
102 device_sync_client, secure_channel_client, tether_host_fetcher,
103 notification_presenter, gms_core_notifications_state_tracker,
104 pref_service, network_state_handler,
105 managed_network_configuration_handler, network_connect,
106 network_connection_handler, adapter, session_manager));
107 }
108
109 // static
SetFactoryForTesting(Factory * factory)110 void TetherComponentImpl::Factory::SetFactoryForTesting(Factory* factory) {
111 factory_instance_ = factory;
112 }
113
114 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)115 void TetherComponentImpl::RegisterProfilePrefs(
116 user_prefs::PrefRegistrySyncable* registry) {
117 ActiveHost::RegisterPrefs(registry);
118 PersistentHostScanCacheImpl::RegisterPrefs(registry);
119 TetherHostResponseRecorder::RegisterPrefs(registry);
120 WifiHotspotDisconnectorImpl::RegisterPrefs(registry);
121 }
122
TetherComponentImpl(device_sync::DeviceSyncClient * device_sync_client,secure_channel::SecureChannelClient * secure_channel_client,TetherHostFetcher * tether_host_fetcher,NotificationPresenter * notification_presenter,GmsCoreNotificationsStateTrackerImpl * gms_core_notifications_state_tracker,PrefService * pref_service,NetworkStateHandler * network_state_handler,ManagedNetworkConfigurationHandler * managed_network_configuration_handler,NetworkConnect * network_connect,NetworkConnectionHandler * network_connection_handler,scoped_refptr<device::BluetoothAdapter> adapter,session_manager::SessionManager * session_manager)123 TetherComponentImpl::TetherComponentImpl(
124 device_sync::DeviceSyncClient* device_sync_client,
125 secure_channel::SecureChannelClient* secure_channel_client,
126 TetherHostFetcher* tether_host_fetcher,
127 NotificationPresenter* notification_presenter,
128 GmsCoreNotificationsStateTrackerImpl* gms_core_notifications_state_tracker,
129 PrefService* pref_service,
130 NetworkStateHandler* network_state_handler,
131 ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
132 NetworkConnect* network_connect,
133 NetworkConnectionHandler* network_connection_handler,
134 scoped_refptr<device::BluetoothAdapter> adapter,
135 session_manager::SessionManager* session_manager)
136 : asynchronous_shutdown_object_container_(
137 AsynchronousShutdownObjectContainerImpl::Factory::Create(
138 device_sync_client,
139 secure_channel_client,
140 tether_host_fetcher,
141 network_state_handler,
142 managed_network_configuration_handler,
143 network_connection_handler,
144 pref_service)),
145 synchronous_shutdown_object_container_(
146 SynchronousShutdownObjectContainerImpl::Factory::Create(
147 asynchronous_shutdown_object_container_.get(),
148 notification_presenter,
149 gms_core_notifications_state_tracker,
150 pref_service,
151 network_state_handler,
152 network_connect,
153 network_connection_handler,
154 session_manager,
155 device_sync_client,
156 secure_channel_client)),
157 crash_recovery_manager_(CrashRecoveryManagerImpl::Factory::Create(
158 network_state_handler,
159 synchronous_shutdown_object_container_->active_host(),
160 synchronous_shutdown_object_container_->host_scan_cache())) {
161 crash_recovery_manager_->RestorePreCrashStateIfNecessary(
162 base::Bind(&TetherComponentImpl::OnPreCrashStateRestored,
163 weak_ptr_factory_.GetWeakPtr()));
164 }
165
166 TetherComponentImpl::~TetherComponentImpl() = default;
167
RequestShutdown(const ShutdownReason & shutdown_reason)168 void TetherComponentImpl::RequestShutdown(
169 const ShutdownReason& shutdown_reason) {
170 has_shutdown_been_requested_ = true;
171
172 // If shutdown has already happened, there is nothing else to do.
173 if (status() != TetherComponent::Status::ACTIVE)
174 return;
175
176 shutdown_reason_ = shutdown_reason;
177
178 // If crash recovery has not yet completed, wait for it to complete before
179 // continuing.
180 if (crash_recovery_manager_)
181 return;
182
183 InitiateShutdown();
184 }
185
OnPreCrashStateRestored()186 void TetherComponentImpl::OnPreCrashStateRestored() {
187 // |crash_recovery_manager_| is no longer needed since it has completed.
188 crash_recovery_manager_.reset();
189
190 if (has_shutdown_been_requested_) {
191 InitiateShutdown();
192 return;
193 }
194
195 // Start a scan now that the Tether module has started up.
196 synchronous_shutdown_object_container_->host_scan_scheduler()
197 ->AttemptScanIfOffline();
198 }
199
InitiateShutdown()200 void TetherComponentImpl::InitiateShutdown() {
201 DCHECK(has_shutdown_been_requested_);
202 DCHECK(!crash_recovery_manager_);
203 DCHECK(status() == TetherComponent::Status::ACTIVE);
204
205 ActiveHost* active_host =
206 synchronous_shutdown_object_container_->active_host();
207 TetherDisconnector* tether_disconnector =
208 synchronous_shutdown_object_container_->tether_disconnector();
209
210 // If there is an active connection, it needs to be disconnected before the
211 // Tether component is shut down.
212 if (active_host->GetActiveHostStatus() !=
213 ActiveHost::ActiveHostStatus::DISCONNECTED) {
214 PA_LOG(VERBOSE) << "There was an active connection during Tether shutdown. "
215 << "Initiating disconnection from device ID \""
216 << multidevice::RemoteDeviceRef::TruncateDeviceIdForLogs(
217 active_host->GetActiveHostDeviceId())
218 << "\".";
219 tether_disconnector->DisconnectFromNetwork(
220 active_host->GetTetherNetworkGuid(), base::DoNothing(),
221 base::Bind(&OnDisconnectErrorDuringShutdown),
222 GetSessionCompletionReasonFromShutdownReason(shutdown_reason_));
223 }
224
225 TransitionToStatus(TetherComponent::Status::SHUTTING_DOWN);
226
227 // Delete objects which can shutdown synchronously immediately.
228 synchronous_shutdown_object_container_.reset();
229
230 // Start the shutdown process for objects which shutdown asynchronously.
231 asynchronous_shutdown_object_container_->Shutdown(
232 base::Bind(&TetherComponentImpl::OnShutdownComplete,
233 weak_ptr_factory_.GetWeakPtr()));
234 }
235
OnShutdownComplete()236 void TetherComponentImpl::OnShutdownComplete() {
237 DCHECK(status() == TetherComponent::Status::SHUTTING_DOWN);
238
239 // Shutdown has completed. The asynchronous objects can now be deleted as
240 // well.
241 asynchronous_shutdown_object_container_.reset();
242
243 TransitionToStatus(TetherComponent::Status::SHUT_DOWN);
244 }
245
246 } // namespace tether
247
248 } // namespace chromeos
249