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

Side by Side Diff: chrome/browser/geolocation/network_location_provider.cc

Issue 552250: Port the gears geolocation network provider to Chromium... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2008, Google Inc. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // 2 // Use of this source code is governed by a BSD-style license that can be
3 // Redistribution and use in source and binary forms, with or without 3 // found in the LICENSE file.
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 4
26 // TODO(joth): port to chromium 5 #include "chrome/browser/geolocation/network_location_provider.h"
27 #if 0
28 6
29 #include "gears/geolocation/network_location_provider.h" 7 #include "base/time.h"
30 8
31 #include "gears/base/common/base_class.h" 9 namespace {
32 #include "gears/base/common/stopwatch.h" // For GetCurrentTimeMillis
33 #include "gears/geolocation/access_token_manager.h"
34 #include "gears/geolocation/backoff_manager.h"
35
36 // The maximum period of time we'll wait for a complete set of device data 10 // The maximum period of time we'll wait for a complete set of device data
37 // before sending the request. 11 // before sending the request.
38 static const int kDataCompleteWaitPeriod = 1000 * 2; // 2 seconds 12 const int kDataCompleteWaitPeriod = 1000 * 2; // 2 seconds
39 13
40 // The maximum size of the cache of positions for previously requested device 14 // The maximum size of the cache of positions for previously requested device
41 // data. 15 // data.
42 static const size_t kMaximumCacheSize = 10; 16 const size_t kMaximumCacheSize = 10;
43 17
18 // TODO(joth): Share, or remove usage by porting callers to Time et al.
19 int64 GetCurrentTimeMillis() {
20 return static_cast<int64>(base::Time::Now().ToDoubleT() * 1000);
21 }
22 } // namespace
44 23
45 // The PositionCache handles caching and retrieving a position returned by a 24 // The PositionCache handles caching and retrieving a position returned by a
46 // network location provider. It is not thread safe. It's methods are called on 25 // network location provider. It is not thread safe. It's methods are called on
47 // multiple threads by NetworkLocationProvider, but the timing is such that 26 // multiple threads by NetworkLocationProvider, but the timing is such that
48 // thread safety is not required. 27 // thread safety is not required.
49 class PositionCache { 28 class NetworkLocationProvider::PositionCache {
50 public: 29 public:
51 // Caches the current position response for the current set of cell ID and 30 // Caches the current position response for the current set of cell ID and
52 // WiFi data. Returns true on success, false otherwise. 31 // WiFi data. Returns true on success, false otherwise.
53 bool CachePosition(const RadioData &radio_data, 32 bool CachePosition(const RadioData& radio_data,
54 const WifiData &wifi_data, 33 const WifiData& wifi_data,
55 const Position &position) { 34 const Position& position) {
56 // Check that we can generate a valid key for the device data. 35 // Check that we can generate a valid key for the device data.
57 std::string16 key; 36 string16 key;
58 if (!MakeKey(radio_data, wifi_data, &key)) { 37 if (!MakeKey(radio_data, wifi_data, &key)) {
59 return false; 38 return false;
60 } 39 }
61 // If the cache is full, remove the oldest entry. 40 // If the cache is full, remove the oldest entry.
62 if (cache_.size() == kMaximumCacheSize) { 41 if (cache_.size() == kMaximumCacheSize) {
63 assert(cache_times_.size() == kMaximumCacheSize); 42 DCHECK(cache_times_.size() == kMaximumCacheSize);
64 CacheTimesMap::iterator oldest_entry = cache_times_.begin(); 43 CacheTimesMap::iterator oldest_entry = cache_times_.begin();
65 assert(oldest_entry != cache_times_.end()); 44 DCHECK(oldest_entry != cache_times_.end());
66 cache_.erase(oldest_entry->second); 45 cache_.erase(oldest_entry->second);
67 cache_times_.erase(oldest_entry); 46 cache_times_.erase(oldest_entry);
68 } 47 }
69 // Insert the position into the cache. 48 // Insert the position into the cache.
70 std::pair<CacheMap::iterator, bool> result = 49 std::pair<CacheMap::iterator, bool> result =
71 cache_.insert(std::make_pair(key, position)); 50 cache_.insert(std::make_pair(key, position));
72 assert(result.second); 51 DCHECK(result.second);
73 cache_times_[position.timestamp] = result.first; 52 cache_times_[position.timestamp] = result.first;
74 assert(cache_.size() == cache_times_.size()); 53 DCHECK(cache_.size() == cache_times_.size());
75 return true; 54 return true;
76 } 55 }
77 56
78 // Searches for a cached position response for the current set of cell ID and 57 // Searches for a cached position response for the current set of cell ID and
79 // WiFi data. Returns the cached position if available, NULL otherwise. 58 // WiFi data. Returns the cached position if available, NULL otherwise.
80 const Position *FindPosition(const RadioData &radio_data, 59 const Position *FindPosition(const RadioData &radio_data,
81 const WifiData &wifi_data) { 60 const WifiData &wifi_data) {
82 std::string16 key; 61 string16 key;
83 if (!MakeKey(radio_data, wifi_data, &key)) { 62 if (!MakeKey(radio_data, wifi_data, &key)) {
84 return NULL; 63 return NULL;
85 } 64 }
86 CacheMap::const_iterator iter = cache_.find(key); 65 CacheMap::const_iterator iter = cache_.find(key);
87 return iter == cache_.end() ? NULL : &iter->second; 66 return iter == cache_.end() ? NULL : &iter->second;
88 } 67 }
89 68
90 // Makes the key for the map of cached positions, using a set of 69 // Makes the key for the map of cached positions, using a set of
91 // device data. Returns true if a good key was generated, false otherwise. 70 // device data. Returns true if a good key was generated, false otherwise.
92 static bool MakeKey(const RadioData& /*radio_data*/, 71 static bool MakeKey(const RadioData& /*radio_data*/,
93 const WifiData &wifi_data, 72 const WifiData& wifi_data,
94 std::string16 *key) { 73 string16* key) {
95 // Currently we use only the WiFi data, and base the key only on the MAC 74 // Currently we use only the WiFi data, and base the key only on the MAC
96 // addresses. 75 // addresses.
97 // TODO(steveblock): Make use of radio_data. 76 // TODO(steveblock): Make use of radio_data.
77 DCHECK(key);
98 key->clear(); 78 key->clear();
79 key->reserve(wifi_data.access_point_data.size() * 19);
80 const string16 separator(ASCIIToUTF16("|"));
99 for (WifiData::AccessPointDataSet::const_iterator iter = 81 for (WifiData::AccessPointDataSet::const_iterator iter =
100 wifi_data.access_point_data.begin(); 82 wifi_data.access_point_data.begin();
101 iter != wifi_data.access_point_data.begin(); 83 iter != wifi_data.access_point_data.begin();
102 iter++) { 84 iter++) {
103 key->append(STRING16(L"|") + iter->mac_address + STRING16(L"|")); 85 *key += separator;
86 *key += iter->mac_address;
87 *key += separator;
104 } 88 }
105 // If the key is the empty string, return false, as we don't want to cache a 89 // If the key is the empty string, return false, as we don't want to cache a
106 // position for such a set of device data. 90 // position for such a set of device data.
107 return !key->empty(); 91 return !key->empty();
108 } 92 }
109 93
110 private: 94 private:
111 // The cache of positions. This is stored using two maps. One map is keyed on 95 // The cache of positions. This is stored using two maps. One map is keyed on
112 // a string that represents a set of device data, the other is keyed on the 96 // a string that represents a set of device data, the other is keyed on the
113 // timestamp of the position. 97 // timestamp of the position.
114 typedef std::map<std::string16, Position> CacheMap; 98 typedef std::map<string16, Position> CacheMap;
115 CacheMap cache_; 99 CacheMap cache_;
116 typedef std::map<int64, CacheMap::iterator> CacheTimesMap; 100 typedef std::map<int64, CacheMap::iterator> CacheTimesMap;
117 CacheTimesMap cache_times_; 101 CacheTimesMap cache_times_;
118 }; 102 };
119 103
120
121 // NetworkLocationProvider factory function 104 // NetworkLocationProvider factory function
122 LocationProviderBase *NewNetworkLocationProvider( 105 LocationProviderBase* NewNetworkLocationProvider(
123 BrowsingContext *browsing_context, 106 LocationProviderBase::AccessTokenStore* access_token_store,
124 const std::string16 &url, 107 URLRequestContextGetter* context,
125 const std::string16 &host_name, 108 const GURL& url,
126 const std::string16 &language) { 109 const string16& host_name) {
127 return new NetworkLocationProvider(browsing_context, url, host_name, 110 return new NetworkLocationProvider(access_token_store, context,
128 language); 111 url, host_name);
129 } 112 }
130
131 113
132 // NetworkLocationProvider 114 // NetworkLocationProvider
133 NetworkLocationProvider::NetworkLocationProvider( 115 NetworkLocationProvider::NetworkLocationProvider(
134 BrowsingContext *browsing_context, 116 AccessTokenStore* access_token_store,
135 const std::string16 &url, 117 URLRequestContextGetter* url_context_getter,
136 const std::string16 &host_name, 118 const GURL& url,
137 const std::string16 &language) 119 const string16& host_name)
138 : request_(NULL), 120 : access_token_store_(access_token_store),
139 url_(url), 121 radio_data_provider_(NULL),
140 host_name_(host_name), 122 wifi_data_provider_(NULL),
141 request_address_(false), 123 is_radio_data_complete_(false),
142 request_address_from_last_request_(false), 124 is_wifi_data_complete_(false),
143 address_language_(language), 125 device_data_updated_timestamp_(kint64min),
144 is_shutting_down_(false),
145 is_new_data_available_(false), 126 is_new_data_available_(false),
146 is_new_listener_waiting_(false), 127 ALLOW_THIS_IN_INITIALIZER_LIST(delayed_start_task_(this)) {
147 browsing_context_(browsing_context) { 128 // Create the position cache.
148 // TODO(steveblock): Consider allowing multiple values for "address_language" 129 position_cache_.reset(new PositionCache());
149 // in the network protocol to allow better sharing of network location 130
150 // providers. 131 request_.reset(new NetworkLocationRequest(url_context_getter, url,
132 host_name, this));
133 }
134
135 NetworkLocationProvider::~NetworkLocationProvider() {
136 if (radio_data_provider_)
137 radio_data_provider_->Unregister(this);
138 if (wifi_data_provider_)
139 wifi_data_provider_->Unregister(this);
140 }
141
142 // LocationProviderBase implementation
143 void NetworkLocationProvider::GetPosition(Position *position) {
144 DCHECK(position);
145 AutoLock lock(position_mutex_);
146 *position = position_;
147 }
148
149 void NetworkLocationProvider::UpdatePosition() {
150 if (is_new_data_available_) {
151 RequestPosition();
152 }
153 }
154
155 // DeviceDataProviderInterface::ListenerInterface implementation.
156 void NetworkLocationProvider::DeviceDataUpdateAvailable(
157 RadioDataProvider* provider) {
158 {
159 AutoLock lock(data_mutex_);
160 DCHECK(provider == radio_data_provider_);
161 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
162 }
163 OnDeviceDataUpdated();
164 }
165
166 void NetworkLocationProvider::DeviceDataUpdateAvailable(
167 WifiDataProvider* provider) {
168 {
169 AutoLock lock(data_mutex_);
170 DCHECK(provider == wifi_data_provider_);
171 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
172 }
173 OnDeviceDataUpdated();
174 }
175
176 // NetworkLocationRequest::ListenerInterface implementation.
177 void NetworkLocationProvider::LocationResponseAvailable(
178 const Position& position,
179 bool server_error,
180 const string16& access_token) {
181 CheckRunningInClientLoop();
182 // Record the position and update our cache.
183 {
184 AutoLock position_lock(position_mutex_);
185 position_ = position;
186 }
187 if (position.IsValidFix()) {
188 AutoLock lock(data_mutex_);
189 position_cache_->CachePosition(radio_data_, wifi_data_, position);
190 }
191
192 // Record access_token if it's set.
193 if (!access_token.empty() && access_token_ != access_token) {
194 access_token_ = access_token;
195 access_token_store_->SetAccessToken(request_->url(), access_token);
196 }
197
198 // If new data arrived whilst request was pending reissue the request.
199 UpdatePosition();
200 // Let listeners know that we now have a position available.
201 UpdateListeners();
202 }
203
204 bool NetworkLocationProvider::StartProvider() {
205 CheckRunningInClientLoop();
206 DCHECK(radio_data_provider_ == NULL);
207 DCHECK(wifi_data_provider_ == NULL);
208 if (!request_->url().is_valid()) {
209 LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
210 << request_->url().possibly_invalid_spec();
211 return false;
212 }
151 213
152 // Get the device data providers. The first call to Register will create the 214 // Get the device data providers. The first call to Register will create the
153 // provider and it will be deleted by ref counting. 215 // provider and it will be deleted by ref counting.
154 radio_data_provider_ = RadioDataProvider::Register(this); 216 radio_data_provider_ = RadioDataProvider::Register(this);
155 wifi_data_provider_ = WifiDataProvider::Register(this); 217 wifi_data_provider_ = WifiDataProvider::Register(this);
156 218
157 AccessTokenManager::GetInstance()->Register(url_); 219 MessageLoop::current()->PostDelayedTask(
158 220 FROM_HERE,
159 // Create the position cache. 221 delayed_start_task_.NewRunnableMethod(
160 position_cache_.reset(new PositionCache()); 222 &NetworkLocationProvider::RequestPosition),
161 223 kDataCompleteWaitPeriod);
162 // Start the worker thread 224 {
163 if (!Start()) {
164 // This should never happen.
165 LOG(("Could not start the NLR"));
166 assert(false);
167 }
168 }
169
170 NetworkLocationProvider::~NetworkLocationProvider() {
171 // Shut down the worker thread
172 is_shutting_down_ = true;
173 thread_notification_event_.Signal();
174 Join();
175
176 // Must keep the request around until our worker thread has stopped.
177 if (request_) {
178 request_->StopThreadAndDelete();
179 request_ = NULL;
180 }
181
182 radio_data_provider_->Unregister(this);
183 wifi_data_provider_->Unregister(this);
184
185 AccessTokenManager::GetInstance()->Unregister();
186 }
187
188 void NetworkLocationProvider::RegisterListener(
189 LocationProviderBase::ListenerInterface *listener,
190 bool request_address) {
191 // Determine whether this listener requires an address when the last request
192 // does not.
193 bool new_listener_requires_address =
194 !request_address_from_last_request_ && request_address;
195
196 // Update whether or not we need to request an address.
197 request_address_ |= request_address;
198
199 // If we now need to request an address when we did not before, we don't add
200 // the listener. This is because if a request is currently in progress, we
201 // don't want the new listener to be called back with a position without an
202 // address. We add the listener when we make the next request.
203 if (new_listener_requires_address) {
204 MutexLock lock(&new_listeners_requiring_address_mutex_);
205 new_listeners_requiring_address_.insert(listener);
206 } else {
207 LocationProviderBase::RegisterListener(listener, request_address);
208 }
209
210 // Signal to the worker thread that there is a new listener.
211 is_new_listener_waiting_ = true;
212 thread_notification_event_.Signal();
213 }
214
215 void NetworkLocationProvider::UnregisterListener(
216 LocationProviderBase::ListenerInterface *listener) {
217 assert(listener);
218
219 // First try removing the listener from the set of new listeners waiting for
220 // an address. Otherwise, try the regular listeners.
221 MutexLock new_listeners_lock(&new_listeners_requiring_address_mutex_);
222 ListenerSet::iterator iter = new_listeners_requiring_address_.find(listener);
223 if (iter != new_listeners_requiring_address_.end()) {
224 new_listeners_requiring_address_.erase(iter);
225 } else {
226 LocationProviderBase::UnregisterListener(listener);
227 }
228
229 // Update whether or not we need to request an address.
230 if (request_address_) {
231 if (!new_listeners_requiring_address_.empty()) {
232 return;
233 }
234 MutexLock listeners_lock(GetListenersMutex());
235 ListenerMap *listeners = GetListeners();
236 for (ListenerMap::const_iterator iter = listeners->begin();
237 iter != listeners->end();
238 iter++) {
239 if (iter->second.first == true) {
240 return;
241 }
242 }
243 request_address_ = false;
244 }
245 }
246
247 // LocationProviderBase implementation
248 void NetworkLocationProvider::GetPosition(Position *position) {
249 assert(position);
250 MutexLock lock(&position_mutex_);
251 *position = position_;
252 }
253
254 // DeviceDataProviderInterface::ListenerInterface implementation.
255 void NetworkLocationProvider::DeviceDataUpdateAvailable(
256 RadioDataProvider *provider) {
257 MutexLock lock(&data_mutex_);
258 assert(provider == radio_data_provider_);
259 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
260
261 DeviceDataUpdateAvailableImpl();
262 }
263
264 void NetworkLocationProvider::DeviceDataUpdateAvailable(
265 WifiDataProvider *provider) {
266 assert(provider == wifi_data_provider_);
267 MutexLock lock(&data_mutex_);
268 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
269
270 DeviceDataUpdateAvailableImpl();
271 }
272
273 // NetworkLocationRequest::ListenerInterface implementation.
274 void NetworkLocationProvider::LocationResponseAvailable(
275 const Position &position,
276 bool server_error,
277 const std::string16 &access_token) {
278 // Record the position and update our cache.
279 position_mutex_.Lock();
280 position_ = position;
281 if (position_.IsGoodFix()) {
282 MutexLock lock(&data_mutex_);
283 position_cache_->CachePosition(radio_data_, wifi_data_, position_);
284 }
285 position_mutex_.Unlock();
286
287 // Record access_token if it's set.
288 if (!access_token.empty()) {
289 AccessTokenManager::GetInstance()->SetToken(url_, access_token);
290 }
291
292 // Get earliest time for next request.
293 earliest_next_request_time_ = BackoffManager::ReportResponse(url_,
294 server_error);
295
296 // Signal to the worker thread that this request has completed.
297 is_last_request_complete_ = true;
298 thread_notification_event_.Signal();
299
300 // Let listeners know that we now have a position available.
301 UpdateListeners();
302 }
303
304 // Thread implementation
305 void NetworkLocationProvider::Run() {
306 // Create the network request object. We must do this on the same thread from
307 // which we'll call Start().
308 request_ = NetworkLocationRequest::Create(browsing_context_, url_,
309 host_name_, this);
310 if (!request_) {
311 LOG(("Failed to create NetworkLocationRequest object.\n"));
312 assert(false);
313 return;
314 }
315
316 // Get the device data. 225 // Get the device data.
317 data_mutex_.Lock(); 226 AutoLock lock(data_mutex_);
318 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); 227 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
319 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); 228 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
320 timestamp_ = GetCurrentTimeMillis(); 229 }
321 230 if (is_radio_data_complete_ || is_wifi_data_complete_)
322 // For the first request, wait for a certain maximum time period to get as 231 OnDeviceDataUpdated();
323 // much device data as possible. 232 return true;
324 int64 start_time = timestamp_; 233 }
325 while (true) { 234
326 if (is_radio_data_complete_ && is_wifi_data_complete_) { 235 // Other methods
327 data_mutex_.Unlock(); 236 void NetworkLocationProvider::RequestPosition() {
328 break; 237 CheckRunningInClientLoop();
238
239 delayed_start_task_.RevokeAll();
240 const Position* cached_position;
241 {
242 AutoLock lock(data_mutex_);
243 cached_position = position_cache_->FindPosition(radio_data_, wifi_data_);
244 }
245 DCHECK_NE(device_data_updated_timestamp_, kint64min) <<
246 "Timestamp must be set before looking up position";
247 if (cached_position) {
248 DCHECK(cached_position->IsValidFix());
249 // Record the position and update its timestamp.
250 {
251 AutoLock lock(position_mutex_);
252 position_ = *cached_position;
253 // The timestamp of a position fix is determined by the timestamp
254 // of the source data update. (The value of position_.timestamp from
255 // the cache could be from weeks ago!)
256 position_.timestamp = device_data_updated_timestamp_;
329 } 257 }
330 data_mutex_.Unlock(); 258 is_new_data_available_ = false;
331
332 int64 elapsed_time = GetCurrentTimeMillis() - start_time;
333 int timeout = kDataCompleteWaitPeriod - static_cast<int>(elapsed_time);
334 if (timeout <= 0) {
335 break;
336 }
337 if (!thread_notification_event_.WaitWithTimeout(timeout)) {
338 // Quit waiting if we time out.
339 break;
340 }
341 // Terminate the thread if requested.
342 if (is_shutting_down_) {
343 return;
344 }
345 // The event should be due to new device data or a new listener.
346 assert(is_new_data_available_ || is_new_listener_waiting_);
347 // If we have new data available, inform listeners of movement.
348 if (is_new_data_available_) {
349 InformListenersOfMovement();
350 }
351 // Lock the data mutex to test is_radio_data_complete_ and
352 // is_wifi_data_complete_ on the next loop.
353 data_mutex_.Lock();
354 }
355
356 earliest_next_request_time_ = 0;
357 MakeRequest();
358
359 // Loop continually, making requests whenever new data becomes available,
360 // subject to the minimum interval.
361 //
362 // This loop is structured such that we don't require mutex locks to
363 // synchronise changes to is_new_data_available_ etc with signals on
364 // thread_notification_event_. Note that if we get a signal before we wait,
365 // the wait will proceed immediately, so we don't miss signals.
366 int64 remaining_time = 1;
367 while (!is_shutting_down_) {
368 if (remaining_time > 0) {
369 remaining_time = earliest_next_request_time_ - GetCurrentTimeMillis();
370 }
371
372 // If the minimum time period has not yet elapsed, set the timeout such
373 // that the wait expires when the period has elapsed.
374 if (remaining_time > 0) {
375 thread_notification_event_.WaitWithTimeout(
376 static_cast<int>(remaining_time));
377 } else {
378 thread_notification_event_.Wait();
379 }
380
381 // Update remaining time now we've woken up. Note that it can never
382 // transition from <= 0 to > 0.
383 if (remaining_time > 0) {
384 remaining_time = earliest_next_request_time_ - GetCurrentTimeMillis();
385 }
386
387 bool make_request = false;
388 if (is_new_listener_waiting_) {
389 // A new listener has just registered with this provider. If new data is
390 // available, force a new request now, unless a request is already in
391 // progress. If not, update listeners with the last known position,
392 // provided we have one.
393 if (is_new_data_available_) {
394 if (is_last_request_complete_) {
395 make_request = true;
396 }
397 } else {
398 // Before the first network request completes, position_ may not be
399 // valid, so we do not update the listeners. They will be updated once
400 // the network request completes.
401 if (position_.IsInitialized()) {
402 // Update listeners with the last known position.
403 UpdateListeners();
404 }
405 }
406 is_new_listener_waiting_ = false;
407 }
408
409 // If a new listener has now registered such that we now require an address,
410 // we make a new request once the current request completes.
411 new_listeners_requiring_address_mutex_.Lock();
412 if (!new_listeners_requiring_address_.empty()) {
413 if (is_last_request_complete_) {
414 make_request = true;
415 }
416 }
417 new_listeners_requiring_address_mutex_.Unlock();
418
419 // If the thread is not shutting down, we have new data, the last request
420 // has completed, and the minimum time has elapsed, make the next request.
421 if (!is_shutting_down_ &&
422 is_new_data_available_ &&
423 is_last_request_complete_ &&
424 remaining_time <= 0) {
425 make_request = true;
426 }
427
428 // If we have new data available, inform listeners of movement.
429 if (is_new_data_available_) {
430 InformListenersOfMovement();
431 }
432
433 // TODO(steveblock): If the request does not complete within some maximum
434 // time period, we should kill it and start a new request.
435 if (make_request) {
436 MakeRequest();
437 remaining_time = 1;
438 }
439 }
440 }
441
442 // Other methods
443
444 bool NetworkLocationProvider::MakeRequest() {
445 // If we have new listeners waiting for an address, request_address_
446 // must be true.
447 assert(new_listeners_requiring_address_.empty() || request_address_);
448
449 // Move the new listeners waiting for an address to the list of listeners.
450 MutexLock lock(&new_listeners_requiring_address_mutex_);
451 for (ListenerSet::const_iterator iter =
452 new_listeners_requiring_address_.begin();
453 iter != new_listeners_requiring_address_.end();
454 iter++) {
455 LocationProviderBase::RegisterListener(*iter, true);
456 }
457 new_listeners_requiring_address_.clear();
458
459 request_address_from_last_request_ = request_address_;
460
461 BackoffManager::ReportRequest(url_);
462
463 std::string16 access_token;
464 AccessTokenManager::GetInstance()->GetToken(url_, &access_token);
465
466 // Reset flags
467 is_new_data_available_ = false;
468 is_new_listener_waiting_ = false;
469
470 data_mutex_.Lock();
471 const Position *cached_position =
472 position_cache_->FindPosition(radio_data_, wifi_data_);
473 data_mutex_.Unlock();
474 if (cached_position) {
475 assert(cached_position->IsGoodFix());
476 // Record the position and update its timestamp.
477 position_mutex_.Lock();
478 position_ = *cached_position;
479 position_.timestamp = timestamp_;
480 position_mutex_.Unlock();
481
482 // Let listeners know that we now have a position available. 259 // Let listeners know that we now have a position available.
483 UpdateListeners(); 260 UpdateListeners();
484 return true; 261 return;
485 } 262 }
486 263
487 assert(request_); 264 DCHECK(request_ != NULL);
488 is_last_request_complete_ = false; 265
489 MutexLock data_lock(&data_mutex_); 266 // TODO(joth): Consider timing out any pending request.
490 return request_->MakeRequest(access_token, 267 if (request_->is_request_pending())
491 radio_data_, 268 return;
492 wifi_data_, 269
493 request_address_, 270 is_new_data_available_ = false;
494 address_language_, 271
495 kBadLatLng, // We don't have a position to pass 272 if (access_token_.empty())
496 kBadLatLng, // to the server. 273 access_token_store_->GetAccessToken(request_->url(), &access_token_);
497 timestamp_); 274
498 } 275 AutoLock data_lock(data_mutex_);
499 276 request_->MakeRequest(access_token_, radio_data_, wifi_data_,
500 void NetworkLocationProvider::DeviceDataUpdateAvailableImpl() { 277 device_data_updated_timestamp_);
501 timestamp_ = GetCurrentTimeMillis(); 278 }
502 279
503 // Signal to the worker thread that new data is available. 280 void NetworkLocationProvider::OnDeviceDataUpdated() {
504 is_new_data_available_ = true; 281 if (MessageLoop::current() != client_loop()) {
505 thread_notification_event_.Signal(); 282 client_loop()->PostTask(FROM_HERE,
506 } 283 NewRunnableMethod(this, &NetworkLocationProvider::OnDeviceDataUpdated));
507 284 return;
508 #endif // if 0 285 }
286 device_data_updated_timestamp_ = GetCurrentTimeMillis();
287
288 is_new_data_available_ = is_radio_data_complete_ || is_radio_data_complete_;
289 if (delayed_start_task_.empty() ||
290 (is_radio_data_complete_ && is_radio_data_complete_)) {
291 UpdatePosition();
292 }
293 }
OLDNEW
« no previous file with comments | « chrome/browser/geolocation/network_location_provider.h ('k') | chrome/browser/geolocation/network_location_request.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698