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 "content/browser/geolocation/wifi_data_provider_common.h" 6 7 #include "base/bind.h" 8 #include "base/strings/stringprintf.h" 9 #include "base/strings/utf_string_conversions.h" 10 11 namespace content { 12 13 string16 MacAddressAsString16(const uint8 mac_as_int[6]) { 14 // mac_as_int is big-endian. Write in byte chunks. 15 // Format is XX-XX-XX-XX-XX-XX. 16 static const char* const kMacFormatString = 17 "%02x-%02x-%02x-%02x-%02x-%02x"; 18 return ASCIIToUTF16(base::StringPrintf(kMacFormatString, 19 mac_as_int[0], 20 mac_as_int[1], 21 mac_as_int[2], 22 mac_as_int[3], 23 mac_as_int[4], 24 mac_as_int[5])); 25 } 26 27 WifiDataProviderCommon::WifiDataProviderCommon() 28 : Thread("Geolocation_wifi_provider"), 29 is_first_scan_complete_(false), 30 weak_factory_(this) { 31 } 32 33 WifiDataProviderCommon::~WifiDataProviderCommon() { 34 // Thread must be stopped before entering destructor chain to avoid race 35 // conditions; see comment in DeviceDataProvider::Unregister. 36 DCHECK(!IsRunning()); // Must call StopDataProvider before destroying me. 37 } 38 39 bool WifiDataProviderCommon::StartDataProvider() { 40 DCHECK(CalledOnClientThread()); 41 DCHECK(!IsRunning()); // StartDataProvider must only be called once. 42 return Start(); 43 } 44 45 void WifiDataProviderCommon::StopDataProvider() { 46 DCHECK(CalledOnClientThread()); 47 Stop(); 48 } 49 50 bool WifiDataProviderCommon::GetData(WifiData* data) { 51 DCHECK(CalledOnClientThread()); 52 DCHECK(data); 53 base::AutoLock lock(data_mutex_); 54 *data = wifi_data_; 55 // If we've successfully completed a scan, indicate that we have all of the 56 // data we can get. 57 return is_first_scan_complete_; 58 } 59 60 // Thread implementation 61 void WifiDataProviderCommon::Init() { 62 DCHECK(wlan_api_ == NULL); 63 wlan_api_.reset(NewWlanApi()); 64 if (wlan_api_ == NULL) { 65 // Error! Can't do scans, so don't try and schedule one. 66 is_first_scan_complete_ = true; 67 return; 68 } 69 70 DCHECK(polling_policy_ == NULL); 71 polling_policy_.reset(NewPollingPolicy()); 72 DCHECK(polling_policy_ != NULL); 73 74 // Perform first scan ASAP regardless of the polling policy. If this scan 75 // fails we'll retry at a rate in line with the polling policy. 76 ScheduleNextScan(0); 77 } 78 79 void WifiDataProviderCommon::CleanUp() { 80 // Destroy these instances in the thread on which they were created. 81 wlan_api_.reset(); 82 polling_policy_.reset(); 83 } 84 85 void WifiDataProviderCommon::DoWifiScanTask() { 86 bool update_available = false; 87 WifiData new_data; 88 if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) { 89 ScheduleNextScan(polling_policy_->NoWifiInterval()); 90 } else { 91 { 92 base::AutoLock lock(data_mutex_); 93 update_available = wifi_data_.DiffersSignificantly(new_data); 94 wifi_data_ = new_data; 95 } 96 polling_policy_->UpdatePollingInterval(update_available); 97 ScheduleNextScan(polling_policy_->PollingInterval()); 98 } 99 if (update_available || !is_first_scan_complete_) { 100 is_first_scan_complete_ = true; 101 NotifyListeners(); 102 } 103 } 104 105 void WifiDataProviderCommon::ScheduleNextScan(int interval) { 106 message_loop()->PostDelayedTask( 107 FROM_HERE, 108 base::Bind(&WifiDataProviderCommon::DoWifiScanTask, 109 weak_factory_.GetWeakPtr()), 110 base::TimeDelta::FromMilliseconds(interval)); 111 } 112 113 } // namespace content 114