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

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

Issue 3153031: Gateway Location Provider (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: Land patch Created 10 years, 4 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
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/geolocation/network_location_provider.h" 5 #include "chrome/browser/geolocation/network_location_provider.h"
6 6
7 #include "base/time.h" 7 #include "base/time.h"
8 #include "base/utf_string_conversions.h" 8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/geolocation/access_token_store.h" 9 #include "chrome/browser/geolocation/access_token_store.h"
10 10
11 namespace { 11 namespace {
12 // The maximum period of time we'll wait for a complete set of device data 12 // The maximum period of time we'll wait for a complete set of device data
13 // before sending the request. 13 // before sending the request.
14 const int kDataCompleteWaitPeriod = 1000 * 2; // 2 seconds 14 const int kDataCompleteWaitPeriod = 1000 * 2; // 2 seconds
15 15
16 // The maximum size of the cache of positions for previously requested device 16 // The maximum size of the cache of positions for previously requested device
17 // data. 17 // data.
18 const size_t kMaximumCacheSize = 10; 18 const size_t kMaximumCacheSize = 10;
19 } // namespace 19 } // namespace
20 20
21 // The PositionCache handles caching and retrieving a position returned by a 21 // The PositionCache handles caching and retrieving a position returned by a
22 // network location provider. It is not thread safe. It's methods are called on 22 // network location provider. It is not thread safe. It's methods are called on
23 // multiple threads by NetworkLocationProvider, but the timing is such that 23 // multiple threads by NetworkLocationProvider, but the timing is such that
24 // thread safety is not required. 24 // thread safety is not required.
25 class NetworkLocationProvider::PositionCache { 25 class NetworkLocationProvider::PositionCache {
26 public: 26 public:
27 // Caches the current position response for the current set of cell ID and 27 // Caches the current position response for the current set of cell ID and
28 // WiFi data. Returns true on success, false otherwise. 28 // WiFi data. Returns true on success, false otherwise.
29 bool CachePosition(const RadioData& radio_data, 29 bool CachePosition(const GatewayData& gateway_data,
30 const RadioData& radio_data,
30 const WifiData& wifi_data, 31 const WifiData& wifi_data,
31 const Geoposition& position) { 32 const Geoposition& position) {
32 // Check that we can generate a valid key for the device data. 33 // Check that we can generate a valid key for the device data.
33 string16 key; 34 string16 key;
34 if (!MakeKey(radio_data, wifi_data, &key)) { 35 if (!MakeKey(gateway_data, radio_data, wifi_data, &key)) {
35 return false; 36 return false;
36 } 37 }
37 // If the cache is full, remove the oldest entry. 38 // If the cache is full, remove the oldest entry.
38 if (cache_.size() == kMaximumCacheSize) { 39 if (cache_.size() == kMaximumCacheSize) {
39 DCHECK(cache_times_.size() == kMaximumCacheSize); 40 DCHECK(cache_times_.size() == kMaximumCacheSize);
40 CacheTimesMap::iterator oldest_entry = cache_times_.begin(); 41 CacheTimesMap::iterator oldest_entry = cache_times_.begin();
41 DCHECK(oldest_entry != cache_times_.end()); 42 DCHECK(oldest_entry != cache_times_.end());
42 cache_.erase(oldest_entry->second); 43 cache_.erase(oldest_entry->second);
43 cache_times_.erase(oldest_entry); 44 cache_times_.erase(oldest_entry);
44 } 45 }
45 // Insert the position into the cache. 46 // Insert the position into the cache.
46 std::pair<CacheMap::iterator, bool> result = 47 std::pair<CacheMap::iterator, bool> result =
47 cache_.insert(std::make_pair(key, position)); 48 cache_.insert(std::make_pair(key, position));
48 DCHECK(result.second); 49 DCHECK(result.second);
49 cache_times_[position.timestamp] = result.first; 50 cache_times_[position.timestamp] = result.first;
50 DCHECK(cache_.size() == cache_times_.size()); 51 DCHECK(cache_.size() == cache_times_.size());
51 return true; 52 return true;
52 } 53 }
53 54
54 // Searches for a cached position response for the current set of cell ID and 55 // Searches for a cached position response for the current set of cell ID and
55 // WiFi data. Returns the cached position if available, NULL otherwise. 56 // WiFi data. Returns the cached position if available, NULL otherwise.
56 const Geoposition *FindPosition(const RadioData &radio_data, 57 const Geoposition *FindPosition(const GatewayData &gateway_data,
58 const RadioData &radio_data,
57 const WifiData &wifi_data) { 59 const WifiData &wifi_data) {
58 string16 key; 60 string16 key;
59 if (!MakeKey(radio_data, wifi_data, &key)) { 61 if (!MakeKey(gateway_data, radio_data, wifi_data, &key)) {
60 return NULL; 62 return NULL;
61 } 63 }
62 CacheMap::const_iterator iter = cache_.find(key); 64 CacheMap::const_iterator iter = cache_.find(key);
63 return iter == cache_.end() ? NULL : &iter->second; 65 return iter == cache_.end() ? NULL : &iter->second;
64 } 66 }
65 67
66 // Makes the key for the map of cached positions, using a set of 68 // Makes the key for the map of cached positions, using a set of
67 // device data. Returns true if a good key was generated, false otherwise. 69 // device data. Returns true if a good key was generated, false otherwise.
68 static bool MakeKey(const RadioData& /*radio_data*/, 70 static bool MakeKey(const GatewayData& gateway_data,
71 const RadioData& /*radio_data*/,
69 const WifiData& wifi_data, 72 const WifiData& wifi_data,
70 string16* key) { 73 string16* key) {
71 // Currently we use only the WiFi data, and base the key only on the MAC 74 // Currently we use only the WiFi data and gateway data, and base the
72 // addresses. 75 // key only on the MAC addresses.
73 // TODO(steveblock): Make use of radio_data. 76 // TODO(steveblock): Make use of radio_data.
74 DCHECK(key); 77 DCHECK(key);
75 key->clear(); 78 key->clear();
76 key->reserve(wifi_data.access_point_data.size() * 19); 79 key->reserve(wifi_data.access_point_data.size() * 19 +
80 gateway_data.router_data.size() * 19);
77 const string16 separator(ASCIIToUTF16("|")); 81 const string16 separator(ASCIIToUTF16("|"));
82 for (GatewayData::RouterDataSet::const_iterator iter =
83 gateway_data.router_data.begin();
84 iter != gateway_data.router_data.end();
85 iter++) {
86 *key += separator;
87 *key += iter->mac_address;
88 *key += separator;
89 }
78 for (WifiData::AccessPointDataSet::const_iterator iter = 90 for (WifiData::AccessPointDataSet::const_iterator iter =
79 wifi_data.access_point_data.begin(); 91 wifi_data.access_point_data.begin();
80 iter != wifi_data.access_point_data.end(); 92 iter != wifi_data.access_point_data.end();
81 iter++) { 93 iter++) {
82 *key += separator; 94 *key += separator;
83 *key += iter->mac_address; 95 *key += iter->mac_address;
84 *key += separator; 96 *key += separator;
85 } 97 }
86 // If the key is the empty string, return false, as we don't want to cache a 98 // If the key is the empty string, return false, as we don't want to cache a
87 // position for such a set of device data. 99 // position for such a set of device data.
(...skipping 20 matching lines...) Expand all
108 access_token_store, context, url, access_token); 120 access_token_store, context, url, access_token);
109 } 121 }
110 122
111 // NetworkLocationProvider 123 // NetworkLocationProvider
112 NetworkLocationProvider::NetworkLocationProvider( 124 NetworkLocationProvider::NetworkLocationProvider(
113 AccessTokenStore* access_token_store, 125 AccessTokenStore* access_token_store,
114 URLRequestContextGetter* url_context_getter, 126 URLRequestContextGetter* url_context_getter,
115 const GURL& url, 127 const GURL& url,
116 const string16& access_token) 128 const string16& access_token)
117 : access_token_store_(access_token_store), 129 : access_token_store_(access_token_store),
130 gateway_data_provider_(NULL),
118 radio_data_provider_(NULL), 131 radio_data_provider_(NULL),
119 wifi_data_provider_(NULL), 132 wifi_data_provider_(NULL),
133 is_gateway_data_complete_(false),
120 is_radio_data_complete_(false), 134 is_radio_data_complete_(false),
121 is_wifi_data_complete_(false), 135 is_wifi_data_complete_(false),
122 access_token_(access_token), 136 access_token_(access_token),
123 is_new_data_available_(false), 137 is_new_data_available_(false),
124 ALLOW_THIS_IN_INITIALIZER_LIST(delayed_start_task_(this)) { 138 ALLOW_THIS_IN_INITIALIZER_LIST(delayed_start_task_(this)) {
125 // Create the position cache. 139 // Create the position cache.
126 position_cache_.reset(new PositionCache()); 140 position_cache_.reset(new PositionCache());
127 141
128 request_.reset(new NetworkLocationRequest(url_context_getter, url, this)); 142 request_.reset(new NetworkLocationRequest(url_context_getter, url, this));
129 } 143 }
130 144
131 NetworkLocationProvider::~NetworkLocationProvider() { 145 NetworkLocationProvider::~NetworkLocationProvider() {
132 StopProvider(); 146 StopProvider();
133 } 147 }
134 148
135 // LocationProviderBase implementation 149 // LocationProviderBase implementation
136 void NetworkLocationProvider::GetPosition(Geoposition *position) { 150 void NetworkLocationProvider::GetPosition(Geoposition *position) {
137 DCHECK(position); 151 DCHECK(position);
138 *position = position_; 152 *position = position_;
139 } 153 }
140 154
141 void NetworkLocationProvider::UpdatePosition() { 155 void NetworkLocationProvider::UpdatePosition() {
142 // TODO(joth): When called via the public (base class) interface, this should 156 // TODO(joth): When called via the public (base class) interface, this should
143 // poke each data provider to get them to expedite their next scan. 157 // poke each data provider to get them to expedite their next scan.
144 // Whilst in the delayed start, only send request if all data is ready. 158 // Whilst in the delayed start, only send request if all data is ready.
145 if (delayed_start_task_.empty() || 159 if (delayed_start_task_.empty() ||
146 (is_radio_data_complete_ && is_wifi_data_complete_)) { 160 (is_gateway_data_complete_ && is_radio_data_complete_ &&
161 is_wifi_data_complete_)) {
147 RequestPosition(); 162 RequestPosition();
148 } 163 }
149 } 164 }
150 165
151 void NetworkLocationProvider::OnPermissionGranted( 166 void NetworkLocationProvider::OnPermissionGranted(
152 const GURL& requesting_frame) { 167 const GURL& requesting_frame) {
153 const bool host_was_empty = most_recent_authorized_host_.empty(); 168 const bool host_was_empty = most_recent_authorized_host_.empty();
154 most_recent_authorized_host_ = requesting_frame.host(); 169 most_recent_authorized_host_ = requesting_frame.host();
155 if (host_was_empty && !most_recent_authorized_host_.empty() 170 if (host_was_empty && !most_recent_authorized_host_.empty()
156 && IsStarted()) { 171 && IsStarted()) {
157 UpdatePosition(); 172 UpdatePosition();
158 } 173 }
159 } 174 }
160 175
161 // DeviceDataProviderInterface::ListenerInterface implementation. 176 // DeviceDataProviderInterface::ListenerInterface implementation.
162 void NetworkLocationProvider::DeviceDataUpdateAvailable( 177 void NetworkLocationProvider::DeviceDataUpdateAvailable(
178 GatewayDataProvider* provider) {
179 DCHECK(provider == gateway_data_provider_);
180 is_gateway_data_complete_ = gateway_data_provider_->GetData(&gateway_data_);
181 OnDeviceDataUpdated();
182 }
183
184 void NetworkLocationProvider::DeviceDataUpdateAvailable(
163 RadioDataProvider* provider) { 185 RadioDataProvider* provider) {
164 DCHECK(provider == radio_data_provider_); 186 DCHECK(provider == radio_data_provider_);
165 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); 187 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
166 OnDeviceDataUpdated(); 188 OnDeviceDataUpdated();
167 } 189 }
168 190
169 void NetworkLocationProvider::DeviceDataUpdateAvailable( 191 void NetworkLocationProvider::DeviceDataUpdateAvailable(
170 WifiDataProvider* provider) { 192 WifiDataProvider* provider) {
171 DCHECK(provider == wifi_data_provider_); 193 DCHECK(provider == wifi_data_provider_);
172 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); 194 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
173 OnDeviceDataUpdated(); 195 OnDeviceDataUpdated();
174 } 196 }
175 197
176 // NetworkLocationRequest::ListenerInterface implementation. 198 // NetworkLocationRequest::ListenerInterface implementation.
177 void NetworkLocationProvider::LocationResponseAvailable( 199 void NetworkLocationProvider::LocationResponseAvailable(
178 const Geoposition& position, 200 const Geoposition& position,
179 bool server_error, 201 bool server_error,
180 const string16& access_token, 202 const string16& access_token,
203 const GatewayData& gateway_data,
181 const RadioData& radio_data, 204 const RadioData& radio_data,
182 const WifiData& wifi_data) { 205 const WifiData& wifi_data) {
183 DCHECK(CalledOnValidThread()); 206 DCHECK(CalledOnValidThread());
184 // Record the position and update our cache. 207 // Record the position and update our cache.
185 position_ = position; 208 position_ = position;
186 if (position.IsValidFix()) { 209 if (position.IsValidFix()) {
187 position_cache_->CachePosition(radio_data, wifi_data, position); 210 position_cache_->CachePosition(gateway_data, radio_data,
211 wifi_data, position);
188 } 212 }
189 213
190 // Record access_token if it's set. 214 // Record access_token if it's set.
191 if (!access_token.empty() && access_token_ != access_token) { 215 if (!access_token.empty() && access_token_ != access_token) {
192 access_token_ = access_token; 216 access_token_ = access_token;
193 access_token_store_->SaveAccessToken(request_->url(), access_token); 217 access_token_store_->SaveAccessToken(request_->url(), access_token);
194 } 218 }
195 219
196 // Let listeners know that we now have a position available. 220 // Let listeners know that we now have a position available.
197 UpdateListeners(); 221 UpdateListeners();
198 } 222 }
199 223
200 bool NetworkLocationProvider::StartProvider(bool high_accuracy) { 224 bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
201 DCHECK(CalledOnValidThread()); 225 DCHECK(CalledOnValidThread());
202 if (IsStarted()) 226 if (IsStarted())
203 return true; 227 return true;
204 DCHECK(wifi_data_provider_ == NULL); 228 DCHECK(wifi_data_provider_ == NULL);
205 if (!request_->url().is_valid()) { 229 if (!request_->url().is_valid()) {
206 LOG(WARNING) << "StartProvider() : Failed, Bad URL: " 230 LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
207 << request_->url().possibly_invalid_spec(); 231 << request_->url().possibly_invalid_spec();
208 return false; 232 return false;
209 } 233 }
210 234
211 // Get the device data providers. The first call to Register will create the 235 // Get the device data providers. The first call to Register will create the
212 // provider and it will be deleted by ref counting. 236 // provider and it will be deleted by ref counting.
237 gateway_data_provider_ = GatewayDataProvider::Register(this);
213 radio_data_provider_ = RadioDataProvider::Register(this); 238 radio_data_provider_ = RadioDataProvider::Register(this);
214 wifi_data_provider_ = WifiDataProvider::Register(this); 239 wifi_data_provider_ = WifiDataProvider::Register(this);
215 240
216 MessageLoop::current()->PostDelayedTask( 241 MessageLoop::current()->PostDelayedTask(
217 FROM_HERE, 242 FROM_HERE,
218 delayed_start_task_.NewRunnableMethod( 243 delayed_start_task_.NewRunnableMethod(
219 &NetworkLocationProvider::RequestPosition), 244 &NetworkLocationProvider::RequestPosition),
220 kDataCompleteWaitPeriod); 245 kDataCompleteWaitPeriod);
221 // Get the device data. 246 // Get the device data.
247 is_gateway_data_complete_ = gateway_data_provider_->GetData(&gateway_data_);
222 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_); 248 is_radio_data_complete_ = radio_data_provider_->GetData(&radio_data_);
223 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_); 249 is_wifi_data_complete_ = wifi_data_provider_->GetData(&wifi_data_);
224 if (is_radio_data_complete_ || is_wifi_data_complete_) 250 if (is_gateway_data_complete_ || is_radio_data_complete_ ||
251 is_wifi_data_complete_)
225 OnDeviceDataUpdated(); 252 OnDeviceDataUpdated();
226 return true; 253 return true;
227 } 254 }
228 255
229 void NetworkLocationProvider::StopProvider() { 256 void NetworkLocationProvider::StopProvider() {
230 DCHECK(CalledOnValidThread()); 257 DCHECK(CalledOnValidThread());
231 if (IsStarted()) { 258 if (IsStarted()) {
259 gateway_data_provider_->Unregister(this);
232 radio_data_provider_->Unregister(this); 260 radio_data_provider_->Unregister(this);
233 wifi_data_provider_->Unregister(this); 261 wifi_data_provider_->Unregister(this);
234 } 262 }
263 gateway_data_provider_ = NULL;
235 radio_data_provider_ = NULL; 264 radio_data_provider_ = NULL;
236 wifi_data_provider_ = NULL; 265 wifi_data_provider_ = NULL;
237 delayed_start_task_.RevokeAll(); 266 delayed_start_task_.RevokeAll();
238 } 267 }
239 268
240 // Other methods 269 // Other methods
241 void NetworkLocationProvider::RequestPosition() { 270 void NetworkLocationProvider::RequestPosition() {
242 DCHECK(CalledOnValidThread()); 271 DCHECK(CalledOnValidThread());
243 if (!is_new_data_available_) 272 if (!is_new_data_available_)
244 return; 273 return;
245 274
246 const Geoposition* cached_position = 275 const Geoposition* cached_position =
247 position_cache_->FindPosition(radio_data_, wifi_data_); 276 position_cache_->FindPosition(gateway_data_, radio_data_, wifi_data_);
248 DCHECK(!device_data_updated_timestamp_.is_null()) << 277 DCHECK(!device_data_updated_timestamp_.is_null()) <<
249 "Timestamp must be set before looking up position"; 278 "Timestamp must be set before looking up position";
250 if (cached_position) { 279 if (cached_position) {
251 DCHECK(cached_position->IsValidFix()); 280 DCHECK(cached_position->IsValidFix());
252 // Record the position and update its timestamp. 281 // Record the position and update its timestamp.
253 position_ = *cached_position; 282 position_ = *cached_position;
254 // The timestamp of a position fix is determined by the timestamp 283 // The timestamp of a position fix is determined by the timestamp
255 // of the source data update. (The value of position_.timestamp from 284 // of the source data update. (The value of position_.timestamp from
256 // the cache could be from weeks ago!) 285 // the cache could be from weeks ago!)
257 position_.timestamp = device_data_updated_timestamp_; 286 position_.timestamp = device_data_updated_timestamp_;
(...skipping 13 matching lines...) Expand all
271 // NetworkLocationRequest for each and hold a set of pending requests. 300 // NetworkLocationRequest for each and hold a set of pending requests.
272 if (request_->is_request_pending()) { 301 if (request_->is_request_pending()) {
273 LOG(INFO) << "NetworkLocationProvider - pre-empting pending network request" 302 LOG(INFO) << "NetworkLocationProvider - pre-empting pending network request"
274 << "with new data. Wifi APs: " 303 << "with new data. Wifi APs: "
275 << wifi_data_.access_point_data.size(); 304 << wifi_data_.access_point_data.size();
276 } 305 }
277 // The hostname sent in the request is just to give a first-order 306 // The hostname sent in the request is just to give a first-order
278 // approximation of usage. We do not need to guarantee that this network 307 // approximation of usage. We do not need to guarantee that this network
279 // request was triggered by an API call from this specific host. 308 // request was triggered by an API call from this specific host.
280 request_->MakeRequest(most_recent_authorized_host_, access_token_, 309 request_->MakeRequest(most_recent_authorized_host_, access_token_,
281 radio_data_, wifi_data_, 310 gateway_data_, radio_data_, wifi_data_,
282 device_data_updated_timestamp_); 311 device_data_updated_timestamp_);
283 } 312 }
284 313
285 void NetworkLocationProvider::OnDeviceDataUpdated() { 314 void NetworkLocationProvider::OnDeviceDataUpdated() {
286 DCHECK(CalledOnValidThread()); 315 DCHECK(CalledOnValidThread());
287 device_data_updated_timestamp_ = base::Time::Now(); 316 device_data_updated_timestamp_ = base::Time::Now();
288 317
289 is_new_data_available_ = is_radio_data_complete_ || is_wifi_data_complete_; 318 is_new_data_available_ = is_gateway_data_complete_ ||
319 is_radio_data_complete_ || is_wifi_data_complete_;
290 UpdatePosition(); 320 UpdatePosition();
291 } 321 }
292 322
293 bool NetworkLocationProvider::IsStarted() const { 323 bool NetworkLocationProvider::IsStarted() const {
324 DCHECK_EQ(!!gateway_data_provider_, !!radio_data_provider_);
294 DCHECK_EQ(!!radio_data_provider_, !!wifi_data_provider_); 325 DCHECK_EQ(!!radio_data_provider_, !!wifi_data_provider_);
295 return wifi_data_provider_ != NULL; 326 return wifi_data_provider_ != NULL;
296 } 327 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698