Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: chrome/browser/extensions/api/dial/dial_registry.cc

Issue 2756483007: [Device Discovery] Move files from browser/extensions/api/dial to browser/media/router/discovery/di… (Closed)
Patch Set: resolve code review comments from Devlin Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/dial/dial_registry.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/memory/ptr_util.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/time/time.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/api/dial/dial_api.h"
17 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
18 #include "chrome/browser/extensions/api/dial/dial_service.h"
19 #include "chrome/common/extensions/api/dial.h"
20 #include "components/net_log/chrome_net_log.h"
21 #include "content/public/browser/browser_thread.h"
22
23 using base::Time;
24 using base::TimeDelta;
25 using content::BrowserThread;
26 using net::NetworkChangeNotifier;
27
28 namespace extensions {
29 namespace api {
30 namespace dial {
31
32 DialRegistry::DialRegistry(base::TimeDelta refresh_interval,
33 base::TimeDelta expiration,
34 const size_t max_devices)
35 : num_listeners_(0),
36 registry_generation_(0),
37 last_event_registry_generation_(0),
38 label_count_(0),
39 refresh_interval_delta_(refresh_interval),
40 expiration_delta_(expiration),
41 max_devices_(max_devices) {
42 DCHECK_CURRENTLY_ON(BrowserThread::IO);
43 DCHECK_GT(max_devices_, 0U);
44 NetworkChangeNotifier::AddNetworkChangeObserver(this);
45 }
46
47 DialRegistry::~DialRegistry() {
48 DCHECK_CURRENTLY_ON(BrowserThread::IO);
49 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
50 }
51
52 std::unique_ptr<DialService> DialRegistry::CreateDialService() {
53 DCHECK(g_browser_process->net_log());
54 return base::MakeUnique<DialServiceImpl>(g_browser_process->net_log());
55 }
56
57 void DialRegistry::ClearDialService() {
58 dial_.reset();
59 }
60
61 base::Time DialRegistry::Now() const {
62 return Time::Now();
63 }
64
65 void DialRegistry::OnListenerAdded() {
66 DCHECK_CURRENTLY_ON(BrowserThread::IO);
67 if (++num_listeners_ == 1) {
68 VLOG(2) << "Listener added; starting periodic discovery.";
69 StartPeriodicDiscovery();
70 }
71 // Event listeners with the current device list.
72 // TODO(crbug.com/576817): Rework the DIAL API so we don't need to have extra
73 // behaviors when adding listeners.
74 SendEvent();
75 }
76
77 void DialRegistry::OnListenerRemoved() {
78 DCHECK_CURRENTLY_ON(BrowserThread::IO);
79 DCHECK_GT(num_listeners_, 0);
80 if (--num_listeners_ == 0) {
81 VLOG(2) << "Listeners removed; stopping periodic discovery.";
82 StopPeriodicDiscovery();
83 }
84 }
85
86 void DialRegistry::RegisterObserver(Observer* observer) {
87 DCHECK_CURRENTLY_ON(BrowserThread::IO);
88 observers_.AddObserver(observer);
89 }
90
91 void DialRegistry::UnregisterObserver(Observer* observer) {
92 DCHECK_CURRENTLY_ON(BrowserThread::IO);
93 observers_.RemoveObserver(observer);
94 }
95
96 GURL DialRegistry::GetDeviceDescriptionURL(const std::string& label) const {
97 const auto device_it = device_by_label_map_.find(label);
98 if (device_it != device_by_label_map_.end())
99 return device_it->second->device_description_url();
100
101 return GURL();
102 }
103
104 void DialRegistry::AddDeviceForTest(const DialDeviceData& device_data) {
105 std::unique_ptr<DialDeviceData> test_data =
106 base::MakeUnique<DialDeviceData>(device_data);
107 device_by_label_map_.insert(
108 std::make_pair(device_data.label(), test_data.get()));
109 device_by_id_map_.insert(
110 std::make_pair(device_data.device_id(), std::move(test_data)));
111 }
112
113 bool DialRegistry::ReadyToDiscover() {
114 if (num_listeners_ == 0) {
115 OnDialError(DIAL_NO_LISTENERS);
116 return false;
117 }
118 if (NetworkChangeNotifier::IsOffline()) {
119 OnDialError(DIAL_NETWORK_DISCONNECTED);
120 return false;
121 }
122 if (NetworkChangeNotifier::IsConnectionCellular(
123 NetworkChangeNotifier::GetConnectionType())) {
124 OnDialError(DIAL_CELLULAR_NETWORK);
125 return false;
126 }
127 return true;
128 }
129
130 bool DialRegistry::DiscoverNow() {
131 DCHECK_CURRENTLY_ON(BrowserThread::IO);
132 if (!ReadyToDiscover()) {
133 return false;
134 }
135 if (!dial_) {
136 OnDialError(DIAL_UNKNOWN);
137 return false;
138 }
139
140 if (!dial_->HasObserver(this))
141 NOTREACHED() << "DiscoverNow() called without observing dial_";
142
143 // Force increment |registry_generation_| to ensure an event is sent even if
144 // the device list did not change.
145 bool started = dial_->Discover();
146 if (started)
147 ++registry_generation_;
148
149 return started;
150 }
151
152 void DialRegistry::StartPeriodicDiscovery() {
153 DCHECK_CURRENTLY_ON(BrowserThread::IO);
154 if (!ReadyToDiscover() || dial_)
155 return;
156
157 dial_ = CreateDialService();
158 dial_->AddObserver(this);
159 DoDiscovery();
160 repeating_timer_.Start(FROM_HERE,
161 refresh_interval_delta_,
162 this,
163 &DialRegistry::DoDiscovery);
164 }
165
166 void DialRegistry::DoDiscovery() {
167 DCHECK_CURRENTLY_ON(BrowserThread::IO);
168 DCHECK(dial_);
169 VLOG(2) << "About to discover!";
170 dial_->Discover();
171 }
172
173 void DialRegistry::StopPeriodicDiscovery() {
174 DCHECK_CURRENTLY_ON(BrowserThread::IO);
175 if (!dial_)
176 return;
177
178 repeating_timer_.Stop();
179 dial_->RemoveObserver(this);
180 ClearDialService();
181 }
182
183 bool DialRegistry::PruneExpiredDevices() {
184 DCHECK_CURRENTLY_ON(BrowserThread::IO);
185 bool pruned_device = false;
186 DeviceByLabelMap::iterator it = device_by_label_map_.begin();
187 while (it != device_by_label_map_.end()) {
188 auto* device = it->second;
189 if (IsDeviceExpired(*device)) {
190 VLOG(2) << "Device " << device->label() << " expired, removing";
191
192 // Make a copy of the device ID here since |device| will be destroyed
193 // during erase().
194 std::string device_id = device->device_id();
195 const size_t num_erased_by_id = device_by_id_map_.erase(device_id);
196 DCHECK_EQ(1U, num_erased_by_id);
197 device_by_label_map_.erase(it++);
198 pruned_device = true;
199 } else {
200 ++it;
201 }
202 }
203 return pruned_device;
204 }
205
206 bool DialRegistry::IsDeviceExpired(const DialDeviceData& device) const {
207 Time now = Now();
208
209 // Check against our default expiration timeout.
210 Time default_expiration_time = device.response_time() + expiration_delta_;
211 if (now > default_expiration_time)
212 return true;
213
214 // Check against the device's cache-control header, if set.
215 if (device.has_max_age()) {
216 Time max_age_expiration_time =
217 device.response_time() + TimeDelta::FromSeconds(device.max_age());
218 if (now > max_age_expiration_time)
219 return true;
220 }
221 return false;
222 }
223
224 void DialRegistry::Clear() {
225 DCHECK_CURRENTLY_ON(BrowserThread::IO);
226 device_by_id_map_.clear();
227 device_by_label_map_.clear();
228 registry_generation_++;
229 }
230
231 void DialRegistry::MaybeSendEvent() {
232 // Send an event if the device list has changed since the last event.
233 bool needs_event = last_event_registry_generation_ < registry_generation_;
234 VLOG(2) << "lerg = " << last_event_registry_generation_ << ", rg = "
235 << registry_generation_ << ", needs_event = " << needs_event;
236 if (needs_event)
237 SendEvent();
238 }
239
240 void DialRegistry::SendEvent() {
241 DeviceList device_list;
242 for (DeviceByLabelMap::const_iterator it = device_by_label_map_.begin();
243 it != device_by_label_map_.end(); ++it) {
244 device_list.push_back(*(it->second));
245 }
246 OnDialDeviceEvent(device_list);
247
248 // Reset watermark.
249 last_event_registry_generation_ = registry_generation_;
250 }
251
252 std::string DialRegistry::NextLabel() {
253 DCHECK_CURRENTLY_ON(BrowserThread::IO);
254 return base::IntToString(++label_count_);
255 }
256
257 void DialRegistry::OnDiscoveryRequest(DialService* service) {
258 DCHECK_CURRENTLY_ON(BrowserThread::IO);
259 MaybeSendEvent();
260 }
261
262 void DialRegistry::OnDeviceDiscovered(DialService* service,
263 const DialDeviceData& device) {
264 DCHECK_CURRENTLY_ON(BrowserThread::IO);
265
266 // Adds |device| to our list of devices or updates an existing device, unless
267 // |device| is a duplicate. Returns true if the list was modified and
268 // increments the list generation.
269 auto device_data = base::MakeUnique<DialDeviceData>(device);
270 DCHECK(!device_data->device_id().empty());
271 DCHECK(device_data->label().empty());
272
273 bool did_modify_list = false;
274 DeviceByIdMap::iterator lookup_result =
275 device_by_id_map_.find(device_data->device_id());
276
277 if (lookup_result != device_by_id_map_.end()) {
278 VLOG(2) << "Found device " << device_data->device_id() << ", merging";
279
280 // Already have previous response. Merge in data from this response and
281 // track if there were any API visible changes.
282 did_modify_list = lookup_result->second->UpdateFrom(*device_data);
283 } else {
284 did_modify_list = MaybeAddDevice(std::move(device_data));
285 }
286
287 if (did_modify_list)
288 registry_generation_++;
289
290 VLOG(2) << "did_modify_list = " << did_modify_list
291 << ", generation = " << registry_generation_;
292 }
293
294 bool DialRegistry::MaybeAddDevice(std::unique_ptr<DialDeviceData> device_data) {
295 DCHECK_CURRENTLY_ON(BrowserThread::IO);
296 if (device_by_id_map_.size() == max_devices_) {
297 VLOG(1) << "Maximum registry size reached. Cannot add device.";
298 return false;
299 }
300 device_data->set_label(NextLabel());
301 DialDeviceData* device_data_ptr = device_data.get();
302 device_by_id_map_[device_data_ptr->device_id()] = std::move(device_data);
303 device_by_label_map_[device_data_ptr->label()] = device_data_ptr;
304 VLOG(2) << "Added device, id = " << device_data_ptr->device_id()
305 << ", label = " << device_data_ptr->label();
306 return true;
307 }
308
309 void DialRegistry::OnDiscoveryFinished(DialService* service) {
310 DCHECK_CURRENTLY_ON(BrowserThread::IO);
311 if (PruneExpiredDevices())
312 registry_generation_++;
313 MaybeSendEvent();
314 }
315
316 void DialRegistry::OnError(DialService* service,
317 const DialService::DialServiceErrorCode& code) {
318 DCHECK_CURRENTLY_ON(BrowserThread::IO);
319 switch (code) {
320 case DialService::DIAL_SERVICE_SOCKET_ERROR:
321 OnDialError(DIAL_SOCKET_ERROR);
322 break;
323 case DialService::DIAL_SERVICE_NO_INTERFACES:
324 OnDialError(DIAL_NO_INTERFACES);
325 break;
326 default:
327 NOTREACHED();
328 OnDialError(DIAL_UNKNOWN);
329 break;
330 }
331 }
332
333 void DialRegistry::OnNetworkChanged(
334 NetworkChangeNotifier::ConnectionType type) {
335 switch (type) {
336 case NetworkChangeNotifier::CONNECTION_NONE:
337 if (dial_) {
338 VLOG(2) << "Lost connection, shutting down discovery and clearing"
339 << " list.";
340 OnDialError(DIAL_NETWORK_DISCONNECTED);
341
342 StopPeriodicDiscovery();
343 // TODO(justinlin): As an optimization, we can probably keep our device
344 // list around and restore it if we reconnected to the exact same
345 // network.
346 Clear();
347 MaybeSendEvent();
348 }
349 break;
350 case NetworkChangeNotifier::CONNECTION_2G:
351 case NetworkChangeNotifier::CONNECTION_3G:
352 case NetworkChangeNotifier::CONNECTION_4G:
353 case NetworkChangeNotifier::CONNECTION_ETHERNET:
354 case NetworkChangeNotifier::CONNECTION_WIFI:
355 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
356 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
357 if (!dial_) {
358 VLOG(2) << "Connection detected, restarting discovery.";
359 StartPeriodicDiscovery();
360 }
361 break;
362 }
363 }
364
365 void DialRegistry::OnDialDeviceEvent(const DeviceList& devices) {
366 for (auto& observer : observers_)
367 observer.OnDialDeviceEvent(devices);
368 }
369
370 void DialRegistry::OnDialError(DialErrorCode type) {
371 for (auto& observer : observers_)
372 observer.OnDialError(type);
373 }
374
375 } // namespace dial
376 } // namespace api
377 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/dial/dial_registry.h ('k') | chrome/browser/extensions/api/dial/dial_registry_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698