OLD | NEW |
| (Empty) |
1 // Copyright 2017 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/host_scan_cache.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "chromeos/components/tether/active_host.h" | |
12 #include "chromeos/components/tether/device_id_tether_network_guid_map.h" | |
13 #include "chromeos/components/tether/tether_host_response_recorder.h" | |
14 #include "chromeos/network/network_state_handler.h" | |
15 #include "components/proximity_auth/logging/logging.h" | |
16 | |
17 namespace chromeos { | |
18 | |
19 namespace tether { | |
20 | |
21 namespace { | |
22 | |
23 class TimerFactoryImpl : public HostScanCache::TimerFactory { | |
24 public: | |
25 TimerFactoryImpl() {} | |
26 ~TimerFactoryImpl() {} | |
27 | |
28 // HostScanCache::TimerFactory: | |
29 std::unique_ptr<base::Timer> CreateOneShotTimer() override { | |
30 return base::MakeUnique<base::OneShotTimer>(); | |
31 } | |
32 }; | |
33 | |
34 } // namespace | |
35 | |
36 HostScanCache::HostScanCache( | |
37 NetworkStateHandler* network_state_handler, | |
38 ActiveHost* active_host, | |
39 TetherHostResponseRecorder* tether_host_response_recorder, | |
40 DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map) | |
41 : timer_factory_(base::MakeUnique<TimerFactoryImpl>()), | |
42 network_state_handler_(network_state_handler), | |
43 active_host_(active_host), | |
44 tether_host_response_recorder_(tether_host_response_recorder), | |
45 device_id_tether_network_guid_map_(device_id_tether_network_guid_map), | |
46 weak_ptr_factory_(this) { | |
47 tether_host_response_recorder_->AddObserver(this); | |
48 } | |
49 | |
50 HostScanCache::~HostScanCache() { | |
51 tether_host_response_recorder_->RemoveObserver(this); | |
52 } | |
53 | |
54 void HostScanCache::SetHostScanResult(const std::string& tether_network_guid, | |
55 const std::string& device_name, | |
56 const std::string& carrier, | |
57 int battery_percentage, | |
58 int signal_strength) { | |
59 DCHECK(!tether_network_guid.empty()); | |
60 | |
61 auto found_iter = tether_guid_to_timer_map_.find(tether_network_guid); | |
62 | |
63 if (found_iter == tether_guid_to_timer_map_.end()) { | |
64 // Add the Tether network to NetworkStateHandler and create an associated | |
65 // Timer. | |
66 network_state_handler_->AddTetherNetworkState( | |
67 tether_network_guid, device_name, carrier, battery_percentage, | |
68 signal_strength, HasConnectedToHost(tether_network_guid)); | |
69 tether_guid_to_timer_map_.emplace(tether_network_guid, | |
70 timer_factory_->CreateOneShotTimer()); | |
71 | |
72 PA_LOG(INFO) << "Added scan result for Tether network with GUID " | |
73 << tether_network_guid << ". Device name: " << device_name | |
74 << ", carrier: " << carrier | |
75 << ", battery percentage: " << battery_percentage | |
76 << ", signal strength: " << signal_strength; | |
77 } else { | |
78 // Update the existing network and stop the associated Timer. | |
79 network_state_handler_->UpdateTetherNetworkProperties( | |
80 tether_network_guid, carrier, battery_percentage, signal_strength); | |
81 found_iter->second->Stop(); | |
82 | |
83 PA_LOG(INFO) << "Updated scan result for Tether network with GUID " | |
84 << tether_network_guid << ". New carrier: " << carrier << ", " | |
85 << "new battery percentage: " << battery_percentage << ", " | |
86 << "new signal strength: " << signal_strength; | |
87 } | |
88 | |
89 StartTimer(tether_network_guid); | |
90 } | |
91 | |
92 bool HostScanCache::RemoveHostScanResult( | |
93 const std::string& tether_network_guid) { | |
94 DCHECK(!tether_network_guid.empty()); | |
95 | |
96 auto it = tether_guid_to_timer_map_.find(tether_network_guid); | |
97 if (it == tether_guid_to_timer_map_.end()) { | |
98 PA_LOG(ERROR) << "Attempted to remove a host scan result which does not " | |
99 << "exist in the cache. GUID: " << tether_network_guid; | |
100 return false; | |
101 } | |
102 | |
103 if (active_host_->GetTetherNetworkGuid() == tether_network_guid) { | |
104 PA_LOG(ERROR) << "RemoveHostScanResult() called for Tether network with " | |
105 << "GUID " << tether_network_guid << ", but the " | |
106 << "corresponding device is the active host. Not removing " | |
107 << "this scan result from the cache."; | |
108 return false; | |
109 } | |
110 | |
111 tether_guid_to_timer_map_.erase(it); | |
112 return network_state_handler_->RemoveTetherNetworkState(tether_network_guid); | |
113 } | |
114 | |
115 void HostScanCache::ClearCacheExceptForActiveHost() { | |
116 // Create a list of all Tether network GUIDs serving as keys to | |
117 // |tether_guid_to_timer_map_|. | |
118 std::vector<std::string> tether_network_guids; | |
119 tether_network_guids.reserve(tether_guid_to_timer_map_.size()); | |
120 for (auto& it : tether_guid_to_timer_map_) | |
121 tether_network_guids.push_back(it.first); | |
122 | |
123 std::string active_host_tether_guid = active_host_->GetTetherNetworkGuid(); | |
124 if (active_host_tether_guid.empty()) { | |
125 PA_LOG(INFO) << "Clearing all " << tether_guid_to_timer_map_.size() << " " | |
126 << "entries from the cache."; | |
127 } else { | |
128 PA_LOG(INFO) << "Clearing " << (tether_guid_to_timer_map_.size() - 1) << " " | |
129 << "of the " << tether_guid_to_timer_map_.size() << " " | |
130 << "entries from the cache. Not removing the entry " | |
131 << "corresponding to the Tether network with GUID " | |
132 << active_host_tether_guid << " because it represents the " | |
133 << "active host."; | |
134 } | |
135 | |
136 // Iterate through the keys, removing all scan results not corresponding to | |
137 // the active host. Iteration is done via a list of pre-computed keys instead | |
138 // if iterating through the map because RemoteHostScanResult() will remove | |
139 // key/value pairs from the map, which would invalidate the map iterator. | |
140 for (auto& tether_network_guid : tether_network_guids) { | |
141 if (active_host_->GetTetherNetworkGuid() == tether_network_guid) { | |
142 // Do not remove the active host from the cache. | |
143 continue; | |
144 } | |
145 | |
146 RemoveHostScanResult(tether_network_guid); | |
147 } | |
148 } | |
149 | |
150 void HostScanCache::OnPreviouslyConnectedHostIdsChanged() { | |
151 for (auto& map_entry : tether_guid_to_timer_map_) { | |
152 const std::string& tether_network_guid = map_entry.first; | |
153 if (!HasConnectedToHost(tether_network_guid)) | |
154 continue; | |
155 | |
156 // If a the current device has connected to the Tether network with GUID | |
157 // |tether_network_guid|, alert |network_state_handler_|. Note that this | |
158 // function is a no-op if it is called on a network which already has its | |
159 // HasConnectedToHost property set to true. | |
160 bool update_successful = | |
161 network_state_handler_->SetTetherNetworkHasConnectedToHost( | |
162 tether_network_guid); | |
163 | |
164 if (update_successful) { | |
165 PA_LOG(INFO) << "Successfully set the HasConnectedToHost property of " | |
166 << "the Tether network with GUID " << tether_network_guid | |
167 << " to true."; | |
168 } | |
169 } | |
170 } | |
171 | |
172 void HostScanCache::SetTimerFactoryForTest( | |
173 std::unique_ptr<TimerFactory> timer_factory_for_test) { | |
174 timer_factory_ = std::move(timer_factory_for_test); | |
175 } | |
176 | |
177 bool HostScanCache::HasConnectedToHost(const std::string& tether_network_guid) { | |
178 std::string device_id = | |
179 device_id_tether_network_guid_map_->GetDeviceIdForTetherNetworkGuid( | |
180 tether_network_guid); | |
181 std::vector<std::string> connected_device_ids = | |
182 tether_host_response_recorder_->GetPreviouslyConnectedHostIds(); | |
183 return std::find(connected_device_ids.begin(), connected_device_ids.end(), | |
184 device_id) != connected_device_ids.end(); | |
185 } | |
186 | |
187 void HostScanCache::StartTimer(const std::string& tether_network_guid) { | |
188 auto found_iter = tether_guid_to_timer_map_.find(tether_network_guid); | |
189 DCHECK(found_iter != tether_guid_to_timer_map_.end()); | |
190 DCHECK(!found_iter->second->IsRunning()); | |
191 | |
192 PA_LOG(INFO) << "Starting host scan cache timer for Tether network with GUID " | |
193 << tether_network_guid << ". Will fire in " | |
194 << kNumMinutesBeforeCacheEntryExpires << " minutes."; | |
195 | |
196 found_iter->second->Start( | |
197 FROM_HERE, | |
198 base::TimeDelta::FromMinutes(kNumMinutesBeforeCacheEntryExpires), | |
199 base::Bind(&HostScanCache::OnTimerFired, weak_ptr_factory_.GetWeakPtr(), | |
200 tether_network_guid)); | |
201 } | |
202 | |
203 void HostScanCache::OnTimerFired(const std::string& tether_network_guid) { | |
204 if (active_host_->GetTetherNetworkGuid() == tether_network_guid) { | |
205 // Log as a warning. This situation should be uncommon in practice since | |
206 // KeepAliveScheduler should schedule a new keep-alive status update every | |
207 // 4 minutes. | |
208 PA_LOG(WARNING) << "Timer fired for Tether network GUID " | |
209 << tether_network_guid << ", but the corresponding device " | |
210 << "is the active host. Restarting timer."; | |
211 | |
212 // If the Timer which fired corresponds to the active host, do not remove | |
213 // the cache entry. The active host must always remain in the cache so that | |
214 // the UI can reflect that it is the connecting/connected network. In this | |
215 // case, just restart the timer. | |
216 StartTimer(tether_network_guid); | |
217 return; | |
218 } | |
219 | |
220 PA_LOG(INFO) << "Timer fired for Tether network GUID " << tether_network_guid | |
221 << ". Removing stale scan result."; | |
222 RemoveHostScanResult(tether_network_guid); | |
223 } | |
224 | |
225 } // namespace tether | |
226 | |
227 } // namespace chromeos | |
OLD | NEW |