Bug 1018379 - Use wifi scanner as the sole the heartbeat that drives location updates, shorten the wifi scanner wait to 5s to ensure this (also stop and restart the scanner on WifiGeoPositionProvider.startup() to ensure this). r=jdm, a=1.4+
authorGarvan Keeley <gkeeley@mozilla.com>
Sun, 08 Jun 2014 22:52:53 -0700
changeset 208034 4674e62192c43dc389b5efe0323e59f47b6a7fe8
parent 208033 6e0f4138959eb70c06742de392562e68ce1bdea6
child 208035 8d93866031c14ed0dceb113c6c152c3696d66224
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm, 1
bugs1018379
milestone32.0a2
Bug 1018379 - Use wifi scanner as the sole the heartbeat that drives location updates, shorten the wifi scanner wait to 5s to ensure this (also stop and restart the scanner on WifiGeoPositionProvider.startup() to ensure this). r=jdm, a=1.4+
dom/system/NetworkGeolocationProvider.js
netwerk/wifi/nsWifiAccessPoint.cpp
netwerk/wifi/nsWifiMonitor.h
netwerk/wifi/nsWifiScannerDBus.cpp
netwerk/wifi/nsWifiScannerFreeBSD.cpp
netwerk/wifi/nsWifiScannerMac.cpp
netwerk/wifi/nsWifiScannerSolaris.cpp
netwerk/wifi/nsWifiScannerWin.cpp
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -9,24 +9,20 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 
 const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE;
 const SETTING_DEBUG_ENABLED = "geolocation.debugging.enabled";
 const SETTING_CHANGED_TOPIC = "mozsettings-changed";
 
 let gLoggingEnabled = false;
 
-// if we don't see any wifi responses in 5 seconds, send the request.
-let gTimeToWaitBeforeSending = 5000; //ms
+let gLocationRequestTimeout = 5000;
 
 let gWifiScanningEnabled = true;
-let gWifiResults;
-
 let gCellScanningEnabled = false;
-let gCellResults;
 
 function LOG(aMsg) {
   if (gLoggingEnabled) {
     aMsg = "*** WIFI GEO: " + aMsg + "\n";
     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
     dump(aMsg);
   }
 }
@@ -54,17 +50,17 @@ WifiGeoPositionObject.prototype = {
 };
 
 function WifiGeoPositionProvider() {
   try {
     gLoggingEnabled = Services.prefs.getBoolPref("geo.wifi.logging.enabled");
   } catch (e) {}
 
   try {
-    gTimeToWaitBeforeSending = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
+    gLocationRequestTimeout = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
   } catch (e) {}
 
   try {
     gWifiScanningEnabled = Services.prefs.getBoolPref("geo.wifi.scan");
   } catch (e) {}
 
   try {
     gCellScanningEnabled = Services.prefs.getBoolPref("geo.cell.scan");
@@ -118,22 +114,26 @@ WifiGeoPositionProvider.prototype = {
       Services.obs.addObserver(this, SETTING_CHANGED_TOPIC, false);
       let settings = Cc["@mozilla.org/settingsService;1"].getService(Ci.nsISettingsService);
       settings.createLock().get(SETTING_DEBUG_ENABLED, settingsCallback);
     } catch(ex) {
       // This platform doesn't have the settings interface, and that is just peachy
     }
 
     if (gWifiScanningEnabled && Cc["@mozilla.org/wifi/monitor;1"]) {
-      this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
+      if (this.wifiService) {
+        this.wifiService.stopWatching(this);
+      }
+      this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Ci.nsIWifiMonitor);
       this.wifiService.startWatching(this);
     }
+    // wifi thread triggers WifiGeoPositionProvider to proceed, with no wifi, do manual timeout
     this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     this.timeoutTimer.initWithCallback(this,
-                                       gTimeToWaitBeforeSending,
+                                       gLocationRequestTimeout,
                                        this.timeoutTimer.TYPE_REPEATING_SLACK);
     LOG("startup called.");
   },
 
   watch: function(c) {
     this.listener = c;
   },
 
@@ -158,17 +158,16 @@ WifiGeoPositionProvider.prototype = {
     this.listener = null;
     this.started = false;
   },
 
   setHighAccuracy: function(enable) {
   },
 
   onChange: function(accessPoints) {
-
     function isPublic(ap) {
       let mask = "_nomap"
       let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
       if (result != -1) {
         LOG("Filtering out " + ap.ssid + " " + result);
       }
       return result;
     };
@@ -176,28 +175,29 @@ WifiGeoPositionProvider.prototype = {
     function sort(a, b) {
       return b.signal - a.signal;
     };
 
     function encode(ap) {
       return { 'macAddress': ap.mac, 'signalStrength': ap.signal };
     };
 
+    let wifiData = null;
     if (accessPoints) {
-      gWifiResults = accessPoints.filter(isPublic).sort(sort).map(encode);
-    } else {
-      gWifiResults = null;
+      wifiData = accessPoints.filter(isPublic).sort(sort).map(encode);
     }
+    this.sendLocationRequest(wifiData);
   },
 
   onError: function (code) {
     LOG("wifi error: " + code);
+    this.sendLocationRequest(null);
   },
 
-  updateMobileInfo: function() {
+  getMobileInfo: function() {
     LOG("updateMobileInfo called");
     try {
       let radioService = Cc["@mozilla.org/ril;1"]
                     .getService(Ci.nsIRadioInterfaceLayer);
       let numInterfaces = radioService.numRadioInterfaces;
       let result = [];
       for (let i = 0; i < numInterfaces; i++) {
         LOG("Looking for SIM in slot:" + i + " of " + numInterfaces);
@@ -211,21 +211,30 @@ WifiGeoPositionProvider.prototype = {
                       mobileCountryCode: iccInfo.mcc,
                       mobileNetworkCode: iccInfo.mnc,
                       locationAreaCode: cell.gsmLocationAreaCode,
                       cellId: cell.gsmCellId });
         }
       }
       return result;
     } catch (e) {
-      gCellResults = null;
+      return null;
     }
   },
 
   notify: function (timeoutTimer) {
+    // If Wifi scanning is disabled, then we can not depend on that for the
+    // heartbeat that drives location updates.  Instead, just use a timer which
+    // will drive the update.
+    if (gWifiScanningEnabled == false) {
+        this.sendLocationRequest(null);
+    }
+  },
+
+  sendLocationRequest: function (wifiData) {
     let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
     let listener = this.listener;
     LOG("Sending request: " + url + "\n");
 
     let xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
                         .createInstance(Ci.nsIXMLHttpRequest);
 
     listener.locationUpdatePending();
@@ -253,27 +262,27 @@ WifiGeoPositionProvider.prototype = {
 
       let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
                                                   xhr.response.location.lng,
                                                   xhr.response.accuracy);
 
       listener.update(newLocation);
     };
 
-    if (gCellScanningEnabled) {
-      this.updateMobileInfo();
+    let data = {};
+    if (wifiData) {
+      data.wifiAccessPoints = wifiData;
     }
 
-    let data = {};
-    if (gWifiResults) {
-      data.wifiAccessPoints = gWifiResults;
+    if (gCellScanningEnabled) {
+      let cellData = this.getMobileInfo();
+      if (cellData) {
+        data.cellTowers = cellData;
+      }
     }
-    if (gCellResults) {
-      data.cellTowers = gCellResults;
-    }
+
     data = JSON.stringify(data);
-    gWifiResults = gCellResults = null;
     LOG("sending " + data);
     xhr.send(data);
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiGeoPositionProvider]);
--- a/netwerk/wifi/nsWifiAccessPoint.cpp
+++ b/netwerk/wifi/nsWifiAccessPoint.cpp
@@ -16,16 +16,17 @@ extern PRLogModuleInfo *gWifiMonitorLog;
 NS_IMPL_ISUPPORTS(nsWifiAccessPoint, nsIWifiAccessPoint)
 
 nsWifiAccessPoint::nsWifiAccessPoint()
 {
   // make sure these are null terminated (because we are paranoid)
   mMac[0] = '\0';
   mSsid[0] = '\0';
   mSsidLen = 0;
+  mSignal = -1000;
 }
 
 nsWifiAccessPoint::~nsWifiAccessPoint()
 {
 }
 
 NS_IMETHODIMP nsWifiAccessPoint::GetMac(nsACString& aMac)
 {
@@ -65,17 +66,18 @@ bool AccessPointsEqual(nsCOMArray<nsWifi
   }
 
   for (int32_t i = 0; i < a.Count(); i++) {
     LOG(("++ Looking for %s\n", a[i]->mSsid));
     bool found = false;
     for (int32_t j = 0; j < b.Count(); j++) {
       LOG(("   %s->%s | %s->%s\n", a[i]->mSsid, b[j]->mSsid, a[i]->mMac, b[j]->mMac));
       if (!strcmp(a[i]->mSsid, b[j]->mSsid) &&
-          !strcmp(a[i]->mMac, b[j]->mMac)) {
+          !strcmp(a[i]->mMac, b[j]->mMac) &&
+          a[i]->mSignal == b[j]->mSignal) {
         found = true;
       }
     }
     if (!found)
       return false;
   }
   LOG(("   match!\n"));
   return true;
--- a/netwerk/wifi/nsWifiMonitor.h
+++ b/netwerk/wifi/nsWifiMonitor.h
@@ -23,16 +23,18 @@
 
 #if defined(PR_LOGGING)
 extern PRLogModuleInfo *gWifiMonitorLog;
 #endif
 #define LOG(args)     PR_LOG(gWifiMonitorLog, PR_LOG_DEBUG, args)
 
 class nsWifiAccessPoint;
 
+#define kDefaultWifiScanInterval 5 /* seconds */
+
 class nsWifiListener
 {
  public:
 
   nsWifiListener(nsMainThreadPtrHolder<nsIWifiListener>* aListener)
   {
     mListener = aListener;
     mHasSentData = false;
--- a/netwerk/wifi/nsWifiScannerDBus.cpp
+++ b/netwerk/wifi/nsWifiScannerDBus.cpp
@@ -327,13 +327,13 @@ nsWifiMonitor::DoScan()
                                                   lastAccessPoints);
     ReplaceArray(lastAccessPoints, accessPoints);
 
     rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
     NS_ENSURE_SUCCESS(rv, rv);
 
     LOG(("waiting on monitor\n"));
     mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mon.Wait(PR_SecondsToInterval(60));
+    mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
   }
 
   return NS_OK;
 }
--- a/netwerk/wifi/nsWifiScannerFreeBSD.cpp
+++ b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
@@ -154,14 +154,14 @@ nsWifiMonitor::DoScan()
 
     rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // wait for some reasonable amount of time. pref?
     LOG(("waiting on monitor\n"));
 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mon.Wait(PR_SecondsToInterval(60));
+    mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
   }
   while (mKeepGoing);
 
   return NS_OK;
 }
--- a/netwerk/wifi/nsWifiScannerMac.cpp
+++ b/netwerk/wifi/nsWifiScannerMac.cpp
@@ -42,14 +42,14 @@ nsWifiMonitor::DoScan()
 
     rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // wait for some reasonable amount of time.  pref?
     LOG(("waiting on monitor\n"));
 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mon.Wait(PR_SecondsToInterval(60));
+    mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
   }
   while (mKeepGoing);
 
   return NS_OK;
 }
--- a/netwerk/wifi/nsWifiScannerSolaris.cpp
+++ b/netwerk/wifi/nsWifiScannerSolaris.cpp
@@ -137,13 +137,13 @@ nsWifiMonitor::DoScan()
     ReplaceArray(lastAccessPoints, accessPoints);
 
     nsresult rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
     NS_ENSURE_SUCCESS(rv, rv);
 
     LOG(("waiting on monitor\n"));
 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    mon.Wait(PR_SecondsToInterval(60));
+    mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
   }
 
   return NS_OK;
 }
--- a/netwerk/wifi/nsWifiScannerWin.cpp
+++ b/netwerk/wifi/nsWifiScannerWin.cpp
@@ -118,14 +118,14 @@ nsWifiMonitor::DoScan()
 
       nsresult rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // wait for some reasonable amount of time.  pref?
       LOG(("waiting on monitor\n"));
 
       ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-      mon.Wait(PR_SecondsToInterval(60));
+      mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
     }
     while (mKeepGoing);
 
     return NS_OK;
 }