diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 6d43740aa507..c994a7ff1cab 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "e4f586d6a2c7a8ff3a676d2ddfecc5b2de94f429", + "revision": "5de9f5b9b2f843825f13bd3667dc0fbf2e04e5f3", "repo_path": "/integration/gaia-central" } diff --git a/dom/wifi/WifiWorker.js b/dom/wifi/WifiWorker.js index 2dacfa3fb0ab..62f573b9ee2b 100644 --- a/dom/wifi/WifiWorker.js +++ b/dom/wifi/WifiWorker.js @@ -10,6 +10,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/systemlibs.js"); var DEBUG = false; // set to true to show debug messages. @@ -67,6 +68,15 @@ const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk"; const NETWORK_INTERFACE_UP = "up"; const NETWORK_INTERFACE_DOWN = "down"; +const DEFAULT_WLAN_INTERFACE = "wlan0"; + +const DRIVER_READY_WAIT = 2000; + +const SUPP_PROP = "init.svc.wpa_supplicant"; +const WPA_SUPPLICANT = "wpa_supplicant"; +const DHCP_PROP = "init.svc.dhcpcd"; +const DHCP = "dhcpcd"; + XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", "@mozilla.org/network/manager;1", "nsINetworkManager"); @@ -84,21 +94,29 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", // expected results). var WifiManager = (function() { function getStartupPrefs() { - Cu.import("resource://gre/modules/systemlibs.js"); return { sdkVersion: parseInt(libcutils.property_get("ro.build.version.sdk"), 10), unloadDriverEnabled: libcutils.property_get("ro.moz.wifi.unloaddriver") === "1", - schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true + schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true, + driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"), + ifname: libcutils.property_get("wifi.interface") }; } - let {sdkVersion, unloadDriverEnabled, schedScanRecovery} = getStartupPrefs(); + let {sdkVersion, unloadDriverEnabled, schedScanRecovery, driverDelay, ifname} = getStartupPrefs(); var controlWorker = new ChromeWorker(WIFIWORKER_WORKER); var eventWorker = new ChromeWorker(WIFIWORKER_WORKER); var manager = {}; + manager.ifname = ifname; + // Emulator build runs to here. + // The debug() should only be used after WifiManager. + if (!ifname) { + manager.ifname = DEFAULT_WLAN_INTERFACE; + } manager.schedScanRecovery = schedScanRecovery; + manager.driverDelay = driverDelay ? parseInt(driverDelay, 10) : DRIVER_READY_WAIT; // Callbacks to invoke when a reply arrives from the controlWorker. var controlCallbacks = Object.create(null); @@ -711,12 +729,38 @@ var WifiManager = (function() { }); } + function stopProcess(service, process, callback) { + var count = 0; + var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + function tick() { + let result = libcutils.property_get(service); + if (result === null) { + callback(); + return; + } + if (result === "stopped" || ++count >= 5) { + // Either we succeeded or ran out of time. + timer = null; + callback(); + return; + } + + // Else it's still running, continue waiting. + timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT); + } + + setProperty("ctl.stop", process, tick); + } + function stopDhcp(ifname, callback) { - controlMessage({ cmd: "dhcp_stop", ifname: ifname }, function(data) { - dhcpInfo = null; - notify("dhcplost"); - callback(!data.status); - }); + // This function does exactly what dhcp_stop does. Unforunately, if we call + // this function twice before the previous callback is returned. We may block + // our self waiting for the callback. It slows down the wifi startup procedure. + // Therefore, we have to roll our own version here. + let dhcpService = DHCP_PROP + "_" + ifname; + let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname; + let processName = DHCP + "_" + suffix; + stopProcess(dhcpService, processName, callback); } function releaseDhcpLease(ifname, callback) { @@ -1114,34 +1158,13 @@ var WifiManager = (function() { return true; } - const SUPP_PROP = "init.svc.wpa_supplicant"; function killSupplicant(callback) { // It is interesting to note that this function does exactly what // wifi_stop_supplicant does. Unforunately, on the Galaxy S2, Samsung // changed that function in a way that means that it doesn't recognize // wpa_supplicant as already running. Therefore, we have to roll our own // version here. - var count = 0; - var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - function tick() { - getProperty(SUPP_PROP, "stopped", function (result) { - if (result === null) { - callback(); - return; - } - if (result === "stopped" || ++count >= 5) { - // Either we succeeded or ran out of time. - timer = null; - callback(); - return; - } - - // Else it's still running, continue waiting. - timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT); - }); - } - - setProperty("ctl.stop", "wpa_supplicant", tick); + stopProcess(SUPP_PROP, WPA_SUPPLICANT, callback); } function didConnectSupplicant(callback) { @@ -1159,10 +1182,24 @@ var WifiManager = (function() { } function prepareForStartup(callback) { + let status = libcutils.property_get(DHCP_PROP + "_" + manager.ifname); + if (status !== "running") { + tryStopSupplicant(); + return; + } manager.connectionDropped(function() { - // Ignore any errors and kill any currently-running supplicants. On some - // phones, stopSupplicant won't work for a supplicant that we didn't - // start, so we hand-roll it here. + tryStopSupplicant(); + }); + + // Ignore any errors and kill any currently-running supplicants. On some + // phones, stopSupplicant won't work for a supplicant that we didn't + // start, so we hand-roll it here. + function tryStopSupplicant () { + let status = libcutils.property_get(SUPP_PROP); + if (status !== "running") { + callback(); + return; + } suppressEvents = true; killSupplicant(function() { disableInterface(manager.ifname, function (ok) { @@ -1170,7 +1207,7 @@ var WifiManager = (function() { callback(); }); }); - }); + } } // Initial state. @@ -1182,7 +1219,6 @@ var WifiManager = (function() { manager.authenticationFailuresCount = 0; manager.loopDetectionCount = 0; - const DRIVER_READY_WAIT = 2000; var waitForDriverReadyTimer = null; function cancelWaitForDriverReadyTimer() { if (waitForDriverReadyTimer) { @@ -1193,7 +1229,7 @@ var WifiManager = (function() { function createWaitForDriverReadyTimer(onTimeout) { waitForDriverReadyTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); waitForDriverReadyTimer.initWithCallback(onTimeout, - DRIVER_READY_WAIT, + manager.driverDelay, Ci.nsITimer.TYPE_ONE_SHOT); }; @@ -1206,71 +1242,64 @@ var WifiManager = (function() { if (enable) { manager.state = "INITIALIZING"; - // Kill any existing connections if necessary. - getProperty("wifi.interface", "tiwlan0", function (ifname) { - if (!ifname) { - callback(-1); - manager.state = "UNINITIALIZED"; - return; - } - manager.ifname = ifname; - - // Register as network interface. - WifiNetworkInterface.name = ifname; - if (!WifiNetworkInterface.registered) { - gNetworkManager.registerNetworkInterface(WifiNetworkInterface); - WifiNetworkInterface.registered = true; - } - WifiNetworkInterface.state = Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED; - WifiNetworkInterface.ip = null; - WifiNetworkInterface.netmask = null; - WifiNetworkInterface.broadcast = null; - WifiNetworkInterface.gateway = null; - WifiNetworkInterface.dns1 = null; - WifiNetworkInterface.dns2 = null; - Services.obs.notifyObservers(WifiNetworkInterface, - kNetworkInterfaceStateChangedTopic, - null); - - prepareForStartup(function() { - loadDriver(function (status) { + // Register as network interface. + WifiNetworkInterface.name = manager.ifname; + if (!WifiNetworkInterface.registered) { + gNetworkManager.registerNetworkInterface(WifiNetworkInterface); + WifiNetworkInterface.registered = true; + } + WifiNetworkInterface.state = Ci.nsINetworkInterface.NETWORK_STATE_DISCONNECTED; + WifiNetworkInterface.ip = null; + WifiNetworkInterface.netmask = null; + WifiNetworkInterface.broadcast = null; + WifiNetworkInterface.gateway = null; + WifiNetworkInterface.dns1 = null; + WifiNetworkInterface.dns2 = null; + Services.obs.notifyObservers(WifiNetworkInterface, + kNetworkInterfaceStateChangedTopic, + null); + prepareForStartup(function() { + loadDriver(function (status) { + if (status < 0) { + callback(status); + manager.state = "UNINITIALIZED"; + return; + } + gNetworkManager.setWifiOperationMode(manager.ifname, + WIFI_FIRMWARE_STATION, + function (status) { if (status) { callback(status); manager.state = "UNINITIALIZED"; return; } - gNetworkManager.setWifiOperationMode(ifname, - WIFI_FIRMWARE_STATION, - function (status) { - if (status < 0) { - callback(status); - manager.state = "UNINITIALIZED"; - return; - } - function doStartSupplicant() { - cancelWaitForDriverReadyTimer(); - startSupplicant(function (status) { - if (status < 0) { - unloadDriver(function() { - callback(status); - }); - manager.state = "UNINITIALIZED"; - return; - } + function doStartSupplicant() { + cancelWaitForDriverReadyTimer(); + startSupplicant(function (status) { + if (status < 0) { + unloadDriver(function() { + callback(status); - manager.supplicantStarted = true; - enableInterface(ifname, function (ok) { - callback(ok ? 0 : -1); }); - }); - } + manager.state = "UNINITIALIZED"; + return; + } - // Driver startup on certain platforms takes longer than it takes for us - // to return from loadDriver, so wait 2 seconds before starting - // the supplicant to give it a chance to start. + manager.supplicantStarted = true; + enableInterface(manager.ifname, function (ok) { + callback(ok ? 0 : -1); + }); + }); + } + // Driver startup on certain platforms takes longer than it takes for us + // to return from loadDriver, so wait 2 seconds before starting + // the supplicant to give it a chance to start. + if (manager.driverDelay > 0) { createWaitForDriverReadyTimer(doStartSupplicant); - }); + } else { + doStartSupplicant(); + } }); }); }); @@ -1297,42 +1326,34 @@ var WifiManager = (function() { manager.setWifiApEnabled = function(enabled, configuration, callback) { if (enabled) { manager.tetheringState = "INITIALIZING"; - getProperty("wifi.interface", "tiwlan0", function (ifname) { - if (!ifname) { + loadDriver(function (status) { + if (status < 0) { callback(); manager.tetheringState = "UNINITIALIZED"; return; } - manager.ifname = ifname; - loadDriver(function (status) { - if (status < 0) { + + function doStartWifiTethering() { + cancelWaitForDriverReadyTimer(); + WifiNetworkInterface.name = manager.ifname; + gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, + configuration, function(result) { + if (result) { + manager.tetheringState = "UNINITIALIZED"; + } else { + manager.tetheringState = "COMPLETED"; + } + // Pop out current request. callback(); - manager.tetheringState = "UNINITIALIZED"; - return; - } + // Should we fire a dom event if we fail to set wifi tethering ? + debug("Enable Wifi tethering result: " + (result ? result : "successfully")); + }); + } - function doStartWifiTethering() { - cancelWaitForDriverReadyTimer(); - WifiNetworkInterface.name = manager.ifname; - gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, - configuration, function(result) { - if (result) { - manager.tetheringState = "UNINITIALIZED"; - } else { - manager.tetheringState = "COMPLETED"; - } - // Pop out current request. - callback(); - // Should we fire a dom event if we fail to set wifi tethering ? - debug("Enable Wifi tethering result: " + (result ? result : "successfully")); - }); - } - - // Driver startup on certain platforms takes longer than it takes - // for us to return from loadDriver, so wait 2 seconds before - // turning on Wifi tethering. - createWaitForDriverReadyTimer(doStartWifiTethering); - }); + // Driver startup on certain platforms takes longer than it takes + // for us to return from loadDriver, so wait 2 seconds before + // turning on Wifi tethering. + createWaitForDriverReadyTimer(doStartWifiTethering); }); } else { gNetworkManager.setWifiTethering(enabled, WifiNetworkInterface, @@ -2160,6 +2181,16 @@ function WifiWorker() { self.currentNetwork.bssid = WifiManager.connectionInfo.bssid; break; case "DISCONNECTED": + // wpa_supplicant may give us a "DISCONNECTED" event even if + // we are already in "DISCONNECTED" state. + if (this.prevState === "INITIALIZING" || + this.prevState === "DISCONNECTED" || + this.prevState === "INTERFACE_DISABLED" || + this.prevState === "INACTIVE" || + this.prevState === "UNINITIALIZED") { + return; + } + self._fireEvent("ondisconnect", {}); self.currentNetwork = null; self.ipAddress = "";