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 |