зеркало из https://github.com/mozilla/gecko-dev.git
Bug 811635 - Part 4: Wifi Direct core implementation. r=vchang
This commit is contained in:
Родитель
3884fca148
Коммит
918822095e
|
@ -403,6 +403,8 @@
|
|||
#ifdef MOZ_WIDGET_GONK
|
||||
@BINPATH@/components/DOMWifiManager.js
|
||||
@BINPATH@/components/DOMWifiManager.manifest
|
||||
@BINPATH@/components/DOMWifiP2pManager.js
|
||||
@BINPATH@/components/DOMWifiP2pManager.manifest
|
||||
@BINPATH@/components/NetworkInterfaceListService.js
|
||||
@BINPATH@/components/NetworkInterfaceListService.manifest
|
||||
@BINPATH@/components/NetworkManager.js
|
||||
|
|
|
@ -9,7 +9,7 @@ interface nsIWifiTetheringCallback;
|
|||
/**
|
||||
* Information about networks that is exposed to network manager API consumers.
|
||||
*/
|
||||
[scriptable, uuid(f4cf9d88-f962-4d29-9baa-fb295dad387b)]
|
||||
[scriptable, uuid(e2f5c6e0-4203-11e3-aa6e-0800200c9a66)]
|
||||
interface nsINetworkInterface : nsISupports
|
||||
{
|
||||
const long NETWORK_STATE_UNKNOWN = -1;
|
||||
|
@ -31,6 +31,7 @@ interface nsINetworkInterface : nsISupports
|
|||
const long NETWORK_TYPE_MOBILE = 1;
|
||||
const long NETWORK_TYPE_MOBILE_MMS = 2;
|
||||
const long NETWORK_TYPE_MOBILE_SUPL = 3;
|
||||
const long NETWORK_TYPE_WIFI_P2P = 4;
|
||||
|
||||
/**
|
||||
* Network type. One of the NETWORK_TYPE_* constants.
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["StateMachine"];
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
this.StateMachine = function(aDebugTag) {
|
||||
function debug(aMsg) {
|
||||
dump('-------------- StateMachine:' + aDebugTag + ': ' + aMsg);
|
||||
}
|
||||
|
||||
var sm = {};
|
||||
|
||||
var _initialState;
|
||||
var _curState;
|
||||
var _prevState;
|
||||
var _paused;
|
||||
var _eventQueue = [];
|
||||
var _deferredEventQueue = [];
|
||||
var _defaultEventHandler;
|
||||
|
||||
// Public interfaces.
|
||||
|
||||
sm.setDefaultEventHandler = function(aDefaultEventHandler) {
|
||||
_defaultEventHandler = aDefaultEventHandler;
|
||||
};
|
||||
|
||||
sm.start = function(aInitialState) {
|
||||
_initialState = aInitialState;
|
||||
sm.gotoState(_initialState);
|
||||
};
|
||||
|
||||
sm.sendEvent = function (aEvent) {
|
||||
if (!_initialState) {
|
||||
if (DEBUG) {
|
||||
debug('StateMachine is not running. Call StateMachine.start() first.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
_eventQueue.push(aEvent);
|
||||
asyncCall(handleFirstEvent);
|
||||
};
|
||||
|
||||
sm.getPreviousState = function() {
|
||||
return _prevState;
|
||||
};
|
||||
|
||||
sm.getCurrentState = function() {
|
||||
return _curState;
|
||||
};
|
||||
|
||||
// State object maker.
|
||||
// @param aName string for this state's name.
|
||||
// @param aDelegate object:
|
||||
// .handleEvent: required.
|
||||
// .enter: called before entering this state (optional).
|
||||
// .exit: called before exiting this state (optional).
|
||||
sm.makeState = function (aName, aDelegate) {
|
||||
if (!aDelegate.handleEvent) {
|
||||
throw "handleEvent is a required delegate function.";
|
||||
}
|
||||
var nop = function() {};
|
||||
return {
|
||||
name: aName,
|
||||
enter: (aDelegate.enter || nop),
|
||||
exit: (aDelegate.exit || nop),
|
||||
handleEvent: aDelegate.handleEvent
|
||||
};
|
||||
};
|
||||
|
||||
sm.deferEvent = function (aEvent) {
|
||||
// The definition of a 'deferred event' is:
|
||||
// We are not able to handle this event now but after receiving
|
||||
// certain event or entering a new state, we might be able to handle
|
||||
// it. For example, we couldn't handle CONNECT_EVENT in the
|
||||
// diconnecting state. But once we finish doing "disconnecting", we
|
||||
// could then handle CONNECT_EVENT!
|
||||
//
|
||||
// So, the deferred event may be handled in the following cases:
|
||||
// 1. Once we entered a new state.
|
||||
// 2. Once we handled a regular event.
|
||||
if (DEBUG) {
|
||||
debug('Deferring event: ' + JSON.stringify(aEvent));
|
||||
}
|
||||
_deferredEventQueue.push(aEvent);
|
||||
};
|
||||
|
||||
// Goto the new state. If the current state is null, the exit
|
||||
// function won't be called.
|
||||
sm.gotoState = function (aNewState) {
|
||||
if (_curState) {
|
||||
if (DEBUG) {
|
||||
debug("exiting state: " + _curState.name);
|
||||
}
|
||||
_curState.exit();
|
||||
}
|
||||
|
||||
_prevState = _curState;
|
||||
_curState = aNewState;
|
||||
|
||||
if (DEBUG) {
|
||||
debug("entering state: " + _curState.name);
|
||||
}
|
||||
_curState.enter();
|
||||
|
||||
// We are in the new state now. We got a chance to handle the
|
||||
// deferred events.
|
||||
handleDeferredEvents();
|
||||
|
||||
sm.resume();
|
||||
};
|
||||
|
||||
// No incoming event will be handled after you call pause().
|
||||
// (But they will be queued.)
|
||||
sm.pause = function() {
|
||||
_paused = true;
|
||||
};
|
||||
|
||||
// Continue to handle incoming events.
|
||||
sm.resume = function() {
|
||||
_paused = false;
|
||||
asyncCall(handleFirstEvent);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Private stuff
|
||||
//----------------------------------------------------------
|
||||
|
||||
function asyncCall(f) {
|
||||
Services.tm.currentThread.dispatch(f, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
function handleFirstEvent() {
|
||||
var hadDeferredEvents;
|
||||
|
||||
if (0 === _eventQueue.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_paused) {
|
||||
return; // The state machine is paused now.
|
||||
}
|
||||
|
||||
hadDeferredEvents = _deferredEventQueue.length > 0;
|
||||
|
||||
handleOneEvent(_eventQueue.shift()); // The handler may defer this event.
|
||||
|
||||
// We've handled one event. If we had deferred events before, now is
|
||||
// a good chance to handle them.
|
||||
if (hadDeferredEvents) {
|
||||
handleDeferredEvents();
|
||||
}
|
||||
|
||||
// Continue to handle the next regular event.
|
||||
handleFirstEvent();
|
||||
}
|
||||
|
||||
function handleDeferredEvents() {
|
||||
if (_deferredEventQueue.length && DEBUG) {
|
||||
debug('Handle deferred events: ' + _deferredEventQueue.length);
|
||||
}
|
||||
for (let i = 0; i < _deferredEventQueue.length; i++) {
|
||||
handleOneEvent(_deferredEventQueue.shift());
|
||||
}
|
||||
}
|
||||
|
||||
function handleOneEvent(aEvent)
|
||||
{
|
||||
if (DEBUG) {
|
||||
debug('Handling event: ' + JSON.stringify(aEvent));
|
||||
}
|
||||
|
||||
var handled = _curState.handleEvent(aEvent);
|
||||
|
||||
if (undefined === handled) {
|
||||
throw "handleEvent returns undefined: " + _curState.name;
|
||||
}
|
||||
if (!handled) {
|
||||
// Event is not handled in the current state. Try handleEventCommon().
|
||||
handled = (_defaultEventHandler ? _defaultEventHandler(aEvent) : handled);
|
||||
}
|
||||
if (undefined === handled) {
|
||||
throw "handleEventCommon returns undefined: " + _curState.name;
|
||||
}
|
||||
if (!handled) {
|
||||
if (DEBUG) {
|
||||
debug('!!!!!!!!! FIXME !!!!!!!!! Event not handled: ' + JSON.stringify(aEvent));
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
return sm;
|
||||
};
|
|
@ -14,8 +14,15 @@ Cu.import("resource://gre/modules/systemlibs.js");
|
|||
|
||||
const SUPP_PROP = "init.svc.wpa_supplicant";
|
||||
const WPA_SUPPLICANT = "wpa_supplicant";
|
||||
const DEBUG = false;
|
||||
|
||||
this.WifiCommand = function(aControlMessage, aInterface) {
|
||||
function debug(msg) {
|
||||
if (DEBUG) {
|
||||
dump('-------------- WifiCommand: ' + msg);
|
||||
}
|
||||
}
|
||||
|
||||
var command = {};
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -135,14 +142,16 @@ this.WifiCommand = function(aControlMessage, aInterface) {
|
|||
doStringCommand("LOG_LEVEL", callback);
|
||||
};
|
||||
|
||||
command.wpsPbc = function (callback) {
|
||||
doBooleanCommand("WPS_PBC", "OK", callback);
|
||||
command.wpsPbc = function (iface, callback) {
|
||||
doBooleanCommand("WPS_PBC" + (iface ? (" interface=" + iface) : ""),
|
||||
"OK", callback);
|
||||
};
|
||||
|
||||
command.wpsPin = function (detail, callback) {
|
||||
doStringCommand("WPS_PIN " +
|
||||
(detail.bssid === undefined ? "any" : detail.bssid) +
|
||||
(detail.pin === undefined ? "" : (" " + detail.pin)),
|
||||
(detail.pin === undefined ? "" : (" " + detail.pin)) +
|
||||
(detail.iface ? (" interface=" + detail.iface) : ""),
|
||||
callback);
|
||||
};
|
||||
|
||||
|
@ -337,9 +346,89 @@ this.WifiCommand = function(aControlMessage, aInterface) {
|
|||
});
|
||||
};
|
||||
|
||||
//--------------------------------------------------
|
||||
// Helper functions.
|
||||
//--------------------------------------------------
|
||||
command.setDeviceName = function(deviceName, callback) {
|
||||
doBooleanCommand("SET device_name " + deviceName, "OK", callback);
|
||||
};
|
||||
|
||||
//-------------------------------------------------
|
||||
// P2P commands.
|
||||
//-------------------------------------------------
|
||||
|
||||
command.p2pProvDiscovery = function(address, wpsMethod, callback) {
|
||||
var command = "P2P_PROV_DISC " + address + " " + wpsMethod;
|
||||
doBooleanCommand(command, "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pConnect = function(config, callback) {
|
||||
var command = "P2P_CONNECT " + config.address + " " + config.wpsMethodWithPin + " ";
|
||||
if (config.joinExistingGroup) {
|
||||
command += "join";
|
||||
} else {
|
||||
command += "go_intent=" + config.goIntent;
|
||||
}
|
||||
|
||||
debug('P2P connect command: ' + command);
|
||||
doBooleanCommand(command, "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pGroupRemove = function(iface, callback) {
|
||||
debug("groupRemove()");
|
||||
doBooleanCommand("P2P_GROUP_REMOVE " + iface, "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pEnable = function(detail, callback) {
|
||||
var commandChain = ["SET device_name " + detail.deviceName,
|
||||
"SET device_type " + detail.deviceType,
|
||||
"SET config_methods " + detail.wpsMethods,
|
||||
"P2P_SET conc_pref sta",
|
||||
"P2P_FLUSH"];
|
||||
|
||||
doBooleanCommandChain(commandChain, callback);
|
||||
};
|
||||
|
||||
command.p2pDisable = function(callback) {
|
||||
doBooleanCommand("P2P_SET disabled 1", "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pEnableScan = function(timeout, callback) {
|
||||
doBooleanCommand("P2P_FIND " + timeout, "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pDisableScan = function(callback) {
|
||||
doBooleanCommand("P2P_STOP_FIND", "OK", callback);
|
||||
};
|
||||
|
||||
command.p2pGetGroupCapab = function(address, callback) {
|
||||
command.p2pPeer(address, function(reply) {
|
||||
debug('p2p_peer reply: ' + reply);
|
||||
if (!reply) {
|
||||
callback(0);
|
||||
return;
|
||||
}
|
||||
var capab = /group_capab=0x([0-9a-fA-F]+)/.exec(reply)[1];
|
||||
if (!capab) {
|
||||
callback(0);
|
||||
} else {
|
||||
callback(parseInt(capab, 16));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
command.p2pPeer = function(address, callback) {
|
||||
doStringCommand("P2P_PEER " + address, callback);
|
||||
};
|
||||
|
||||
command.p2pGroupAdd = function(netId, callback) {
|
||||
doBooleanCommand("P2P_GROUP_ADD persistent=" + netId, callback);
|
||||
};
|
||||
|
||||
command.p2pReinvoke = function(netId, address, callback) {
|
||||
doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + address, "OK", callback);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Private stuff.
|
||||
//----------------------------------------------------------
|
||||
|
||||
function voidControlMessage(cmd, callback) {
|
||||
aControlMessage({ cmd: cmd, iface: aInterface }, function (data) {
|
||||
|
@ -391,6 +480,10 @@ this.WifiCommand = function(aControlMessage, aInterface) {
|
|||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// Helper functions.
|
||||
//--------------------------------------------------
|
||||
|
||||
function stopProcess(service, process, callback) {
|
||||
var count = 0;
|
||||
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
|
|
@ -11,16 +11,23 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
|
||||
"@mozilla.org/network/service;1",
|
||||
"nsINetworkService");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WifiNetUtil"];
|
||||
|
||||
const DHCP_PROP = "init.svc.dhcpcd";
|
||||
const DHCP = "dhcpcd";
|
||||
const DEBUG = false;
|
||||
|
||||
this.WifiNetUtil = function(controlMessage) {
|
||||
function debug(msg) {
|
||||
if (DEBUG) {
|
||||
dump('-------------- NetUtil: ' + msg);
|
||||
}
|
||||
}
|
||||
|
||||
var util = {};
|
||||
|
||||
util.configureInterface = function(cfg, callback) {
|
||||
|
@ -67,14 +74,14 @@ this.WifiNetUtil = function(controlMessage) {
|
|||
});
|
||||
};
|
||||
|
||||
util.startDhcpServer = function (range, callback) {
|
||||
gNetworkManager.setDhcpServer(true, range, function (error) {
|
||||
util.startDhcpServer = function (config, callback) {
|
||||
gNetworkService.setDhcpServer(true, config, function (error) {
|
||||
callback(!error);
|
||||
});
|
||||
};
|
||||
|
||||
util.stopDhcpServer = function (callback) {
|
||||
gNetworkManager.setDhcpServer(false, null, function (error) {
|
||||
gNetworkService.setDhcpServer(false, null, function (error) {
|
||||
callback(!error);
|
||||
});
|
||||
};
|
||||
|
@ -135,6 +142,7 @@ this.WifiNetUtil = function(controlMessage) {
|
|||
|
||||
util.runIpConfig = function (name, data, callback) {
|
||||
if (!data) {
|
||||
debug("IP config failed to run");
|
||||
callback({ info: data });
|
||||
return;
|
||||
}
|
||||
|
@ -142,16 +150,19 @@ this.WifiNetUtil = function(controlMessage) {
|
|||
setProperty("net." + name + ".dns1", ipToString(data.dns1),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.dns1");
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".dns2", ipToString(data.dns2),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.dns2");
|
||||
return;
|
||||
}
|
||||
setProperty("net." + name + ".gw", ipToString(data.gateway),
|
||||
function(ok) {
|
||||
if (!ok) {
|
||||
debug("Unable to set net.<ifname>.gw");
|
||||
return;
|
||||
}
|
||||
callback({ info: data });
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,303 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const CONNECTION_STATUS_DISCONNECTED = "disconnected";
|
||||
const CONNECTION_STATUS_CONNECTING = "connecting";
|
||||
const CONNECTION_STATUS_CONNECTED = "connected";
|
||||
const CONNECTION_STATUS_DISCONNECTING = "disconnecting";
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["WifiP2pWorkerObserver"];
|
||||
|
||||
// WifiP2pWorkerObserver resides in WifiWorker to handle DOM message
|
||||
// by either 1) returning internally maintained information or
|
||||
// 2) delegating to aDomMsgResponder. It is also responsible
|
||||
// for observing events from WifiP2pManager and dispatch to DOM.
|
||||
//
|
||||
// @param aDomMsgResponder handles DOM messages, including
|
||||
// - setScanEnabled
|
||||
// - connect
|
||||
// - disconnect
|
||||
// - setPairingConfirmation
|
||||
// The instance is actually WifiP2pManager.
|
||||
this.WifiP2pWorkerObserver = function(aDomMsgResponder) {
|
||||
function debug(aMsg) {
|
||||
if (DEBUG) {
|
||||
dump('-------------- WifiP2pWorkerObserver: ' + aMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Private member variables.
|
||||
let _localDevice;
|
||||
let _peerList = {}; // List of P2pDevice.
|
||||
let _domManagers = [];
|
||||
|
||||
// Constructor of P2pDevice. It will be exposed to DOM.
|
||||
//
|
||||
// @param aPeer object representing a P2P device:
|
||||
// .name: string for the device name.
|
||||
// .address: Mac address.
|
||||
// .isGroupOwner: boolean to indicate if this device is the group owner.
|
||||
// .wpsCapabilities: array of string of {"pbc", "display", "keypad"}.
|
||||
function P2pDevice(aPeer) {
|
||||
this.address = aPeer.address;
|
||||
this.name = (aPeer.name ? aPeer.name : aPeer.address);
|
||||
this.isGroupOwner = aPeer.isGroupOwner;
|
||||
this.wpsCapabilities = aPeer.wpsCapabilities;
|
||||
this.connectionStatus = CONNECTION_STATUS_DISCONNECTED;
|
||||
|
||||
// Since this object will be exposed to web, defined the exposed
|
||||
// properties here.
|
||||
this.__exposedProps__ = {
|
||||
address: "r",
|
||||
name: "r",
|
||||
isGroupOwner: "r",
|
||||
wpsCapabilities: "r",
|
||||
connectionStatus: "r"
|
||||
};
|
||||
}
|
||||
|
||||
// Constructor of P2pGroupOwner.
|
||||
//
|
||||
// @param aGroupOwner:
|
||||
// .macAddress
|
||||
// .ipAddress
|
||||
// .passphrase
|
||||
// .ssid
|
||||
// .freq
|
||||
// .isLocal
|
||||
function P2pGroupOwner(aGroupOwner) {
|
||||
this.macAddress = aGroupOwner.macAddress; // The identifier to get further information.
|
||||
this.ipAddress = aGroupOwner.ipAddress;
|
||||
this.passphrase = aGroupOwner.passphrase;
|
||||
this.ssid = aGroupOwner.ssid; // e.g. DIRECT-xy.
|
||||
this.freq = aGroupOwner.freq;
|
||||
this.isLocal = aGroupOwner.isLocal;
|
||||
|
||||
let detail = _peerList[aGroupOwner.macAddress];
|
||||
if (detail) {
|
||||
this.name = detail.name;
|
||||
this.wpsCapabilities = detail.wpsCapabilities;
|
||||
} else if (_localDevice.address === this.macAddress) {
|
||||
this.name = _localDevice.name;
|
||||
this.wpsCapabilities = _localDevice.wpsCapabilities;
|
||||
} else {
|
||||
debug("We don't know this group owner: " + aGroupOwner.macAddress);
|
||||
this.name = aGroupOwner.macAddress;
|
||||
this.wpsCapabilities = [];
|
||||
}
|
||||
}
|
||||
|
||||
function fireEvent(aMessage, aData) {
|
||||
debug('domManager: ' + JSON.stringify(_domManagers));
|
||||
_domManagers.forEach(function(manager) {
|
||||
// Note: We should never have a dead message manager here because we
|
||||
// observe our child message managers shutting down below.
|
||||
manager.sendAsyncMessage("WifiP2pManager:" + aMessage, aData);
|
||||
});
|
||||
}
|
||||
|
||||
function addDomManager(aMsg) {
|
||||
if (-1 === _domManagers.indexOf(aMsg.manager)) {
|
||||
_domManagers.push(aMsg.manager);
|
||||
}
|
||||
}
|
||||
|
||||
function returnMessage(aMessage, aSuccess, aData, aMsg) {
|
||||
let rMsg = aMessage + ":Return:" + (aSuccess ? "OK" : "NO");
|
||||
aMsg.manager.sendAsyncMessage(rMsg,
|
||||
{ data: aData, rid: aMsg.rid, mid: aMsg.mid });
|
||||
}
|
||||
|
||||
function handlePeerListUpdated() {
|
||||
fireEvent("onpeerinfoupdate", {});
|
||||
}
|
||||
|
||||
// Return a literal object as the constructed object.
|
||||
return {
|
||||
onLocalDeviceChanged: function(aDevice) {
|
||||
_localDevice = aDevice;
|
||||
debug('Local device updated to: ' + JSON.stringify(_localDevice));
|
||||
},
|
||||
|
||||
onEnabled: function() {
|
||||
_peerList = [];
|
||||
fireEvent("p2pUp", {});
|
||||
},
|
||||
|
||||
onDisbaled: function() {
|
||||
fireEvent("p2pDown", {});
|
||||
},
|
||||
|
||||
onPeerFound: function(aPeer) {
|
||||
let newFoundPeer = new P2pDevice(aPeer);
|
||||
let origianlPeer = _peerList[aPeer.address];
|
||||
_peerList[aPeer.address] = newFoundPeer;
|
||||
if (origianlPeer) {
|
||||
newFoundPeer.connectionStatus = origianlPeer.connectionStatus;
|
||||
}
|
||||
handlePeerListUpdated();
|
||||
},
|
||||
|
||||
onPeerLost: function(aPeer) {
|
||||
let lostPeer = _peerList[aPeer.address];
|
||||
if (!lostPeer) {
|
||||
debug('Unknown peer lost: ' + aPeer.address);
|
||||
return;
|
||||
}
|
||||
delete _peerList[aPeer.address];
|
||||
handlePeerListUpdated();
|
||||
},
|
||||
|
||||
onConnecting: function(aPeer) {
|
||||
let peer = _peerList[aPeer.address];
|
||||
if (!peer) {
|
||||
debug('Unknown peer connecting: ' + aPeer.address);
|
||||
peer = new P2pDevice(aPeer);
|
||||
_peerList[aPeer.address] = peer;
|
||||
handlePeerListUpdated();
|
||||
}
|
||||
peer.connectionStatus = CONNECTION_STATUS_CONNECTING;
|
||||
|
||||
fireEvent('onconnecting', { peer: peer });
|
||||
},
|
||||
|
||||
onConnected: function(aGroupOwner, aPeer) {
|
||||
let go = new P2pGroupOwner(aGroupOwner);
|
||||
let peer = _peerList[aPeer.address];
|
||||
if (!peer) {
|
||||
debug('Unknown peer connected: ' + aPeer.address);
|
||||
peer = new P2pDevice(aPeer);
|
||||
_peerList[aPeer.address] = peer;
|
||||
handlePeerListUpdated();
|
||||
}
|
||||
peer.connectionStatus = CONNECTION_STATUS_CONNECTED;
|
||||
peer.isGroupOwner = (aPeer.address === aGroupOwner.address);
|
||||
|
||||
fireEvent('onconnected', { groupOwner: go, peer: peer });
|
||||
},
|
||||
|
||||
onDisconnected: function(aPeer) {
|
||||
let peer = _peerList[aPeer.address];
|
||||
if (!peer) {
|
||||
debug('Unknown peer disconnected: ' + aPeer.address);
|
||||
return;
|
||||
}
|
||||
|
||||
peer.connectionStatus = CONNECTION_STATUS_DISCONNECTED;
|
||||
fireEvent('ondisconnected', { peer: peer });
|
||||
},
|
||||
|
||||
getObservedDOMMessages: function() {
|
||||
return [
|
||||
"WifiP2pManager:getState",
|
||||
"WifiP2pManager:getPeerList",
|
||||
"WifiP2pManager:setScanEnabled",
|
||||
"WifiP2pManager:connect",
|
||||
"WifiP2pManager:disconnect",
|
||||
"WifiP2pManager:setPairingConfirmation",
|
||||
"WifiP2pManager:setDeviceName"
|
||||
];
|
||||
},
|
||||
|
||||
onDOMMessage: function(aMessage) {
|
||||
let msg = aMessage.data || {};
|
||||
msg.manager = aMessage.target;
|
||||
|
||||
if ("child-process-shutdown" === aMessage.name) {
|
||||
let i;
|
||||
if (-1 !== (i = _domManagers.indexOf(msg.manager))) {
|
||||
_domManagers.splice(i, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aMessage.target.assertPermission("wifi-manage")) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "WifiP2pManager:getState": // A new DOM manager is created.
|
||||
addDomManager(msg);
|
||||
return { peerList: _peerList, }; // Synchronous call. Simply return it.
|
||||
|
||||
case "WifiP2pManager:setScanEnabled":
|
||||
{
|
||||
let enabled = msg.data;
|
||||
|
||||
aDomMsgResponder.setScanEnabled(enabled, function(success) {
|
||||
returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "WifiP2pManager:getPeerList":
|
||||
{
|
||||
// Convert the object to an array.
|
||||
let peerArray = [];
|
||||
for (let key in _peerList) {
|
||||
if (_peerList.hasOwnProperty(key)) {
|
||||
peerArray.push(_peerList[key]);
|
||||
}
|
||||
}
|
||||
|
||||
returnMessage(aMessage.name, true, peerArray, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case "WifiP2pManager:connect":
|
||||
{
|
||||
let peer = msg.data;
|
||||
|
||||
let onDoConnect = function(success) {
|
||||
returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
|
||||
};
|
||||
|
||||
aDomMsgResponder.connect(peer.address, peer.wpsMethod,
|
||||
peer.goIntent, onDoConnect);
|
||||
}
|
||||
break;
|
||||
|
||||
case "WifiP2pManager:disconnect":
|
||||
{
|
||||
let address = msg.data;
|
||||
|
||||
aDomMsgResponder.disconnect(address, function(success) {
|
||||
returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "WifiP2pManager:setPairingConfirmation":
|
||||
{
|
||||
let result = msg.data;
|
||||
aDomMsgResponder.setPairingConfirmation(result);
|
||||
returnMessage(aMessage.name, true, true, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case "WifiP2pManager:setDeviceName":
|
||||
{
|
||||
let newDeviceName = msg.data;
|
||||
aDomMsgResponder.setDeviceName(newDeviceName, function(success) {
|
||||
returnMessage(aMessage.name, success, (success ? true : "ERROR"), msg);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (0 === aMessage.name.indexOf("WifiP2pManager:")) {
|
||||
debug("DOM WifiP2pManager message not handled: " + aMessage.name);
|
||||
}
|
||||
} // End of switch.
|
||||
}
|
||||
};
|
||||
};
|
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
Cu.import("resource://gre/modules/systemlibs.js");
|
||||
Cu.import("resource://gre/modules/WifiCommand.jsm");
|
||||
Cu.import("resource://gre/modules/WifiNetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/WifiP2pManager.jsm");
|
||||
Cu.import("resource://gre/modules/WifiP2pWorkerObserver.jsm");
|
||||
|
||||
var DEBUG = false; // set to true to show debug messages.
|
||||
|
||||
|
@ -108,16 +110,30 @@ var WifiManager = (function() {
|
|||
unloadDriverEnabled: libcutils.property_get("ro.moz.wifi.unloaddriver") === "1",
|
||||
schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true,
|
||||
driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"),
|
||||
p2pSupported: libcutils.property_get("ro.moz.wifi.p2p_supported") === "1",
|
||||
ifname: libcutils.property_get("wifi.interface")
|
||||
};
|
||||
}
|
||||
|
||||
let {sdkVersion, unloadDriverEnabled, schedScanRecovery, driverDelay, ifname} = getStartupPrefs();
|
||||
let {sdkVersion, unloadDriverEnabled, schedScanRecovery, driverDelay, p2pSupported, ifname} = getStartupPrefs();
|
||||
|
||||
let wifiListener = {
|
||||
onWaitEvent: function(event, iface) {
|
||||
if (manager.ifname === iface && handleEvent(event)) {
|
||||
waitForEvent(iface);
|
||||
} else if (p2pSupported) {
|
||||
if (WifiP2pManager.INTERFACE_NAME === iface) {
|
||||
// If the connection is closed, wifi.c::wifi_wait_for_event()
|
||||
// will still return 'CTRL-EVENT-TERMINATING - connection closed'
|
||||
// rather than blocking. So when we see this special event string,
|
||||
// just return immediately.
|
||||
const TERMINATED_EVENT = 'CTRL-EVENT-TERMINATING - connection closed';
|
||||
if (-1 !== event.indexOf(TERMINATED_EVENT)) {
|
||||
return;
|
||||
}
|
||||
p2pManager.handleEvent(event);
|
||||
waitForEvent(iface);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -135,18 +151,29 @@ var WifiManager = (function() {
|
|||
manager.schedScanRecovery = schedScanRecovery;
|
||||
manager.driverDelay = driverDelay ? parseInt(driverDelay, 10) : DRIVER_READY_WAIT;
|
||||
|
||||
// Regular Wifi stuff.
|
||||
var netUtil = WifiNetUtil(controlMessage);
|
||||
var wifiCommand = WifiCommand(controlMessage, manager.ifname);
|
||||
|
||||
// Wifi P2P stuff
|
||||
var p2pManager;
|
||||
if (p2pSupported) {
|
||||
let p2pCommand = WifiCommand(controlMessage, WifiP2pManager.INTERFACE_NAME);
|
||||
p2pManager = WifiP2pManager(p2pCommand, netUtil);
|
||||
}
|
||||
|
||||
let wifiService = Cc["@mozilla.org/wifi/service;1"];
|
||||
if (wifiService) {
|
||||
wifiService = wifiService.getService(Ci.nsIWifiProxyService);
|
||||
let interfaces = [manager.ifname];
|
||||
if (p2pSupported) {
|
||||
interfaces.push(WifiP2pManager.INTERFACE_NAME);
|
||||
}
|
||||
wifiService.start(wifiListener, interfaces, interfaces.length);
|
||||
} else {
|
||||
debug("No wifi service component available!");
|
||||
}
|
||||
|
||||
var wifiCommand = WifiCommand(controlMessage, manager.ifname);
|
||||
var netUtil = WifiNetUtil(controlMessage);
|
||||
|
||||
// Callbacks to invoke when a reply arrives from the wifi service.
|
||||
var controlCallbacks = Object.create(null);
|
||||
var idgen = 0;
|
||||
|
@ -244,6 +271,7 @@ var WifiManager = (function() {
|
|||
wifiCommand.doSetScanMode(true, function(ignore) {
|
||||
setBackgroundScan("OFF", function(turned, ignore) {
|
||||
reEnableBackgroundScan = turned;
|
||||
manager.handlePreWifiScan();
|
||||
wifiCommand.scan(function(ok) {
|
||||
wifiCommand.doSetScanMode(false, function(ignore) {
|
||||
// The result of scanCommand is the result of the actual SCAN
|
||||
|
@ -255,6 +283,7 @@ var WifiManager = (function() {
|
|||
});
|
||||
return;
|
||||
}
|
||||
manager.handlePreWifiScan();
|
||||
wifiCommand.scan(callback);
|
||||
}
|
||||
|
||||
|
@ -267,6 +296,7 @@ var WifiManager = (function() {
|
|||
if (ok)
|
||||
debugEnabled = wanted;
|
||||
});
|
||||
p2pManager.setDebug(DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,6 +785,7 @@ var WifiManager = (function() {
|
|||
reEnableBackgroundScan = false;
|
||||
setBackgroundScan("ON", function() {});
|
||||
}
|
||||
manager.handlePostWifiScan();
|
||||
notify("scanresultsavailable");
|
||||
return true;
|
||||
}
|
||||
|
@ -786,6 +817,10 @@ var WifiManager = (function() {
|
|||
notify("supplicantconnection");
|
||||
callback();
|
||||
});
|
||||
|
||||
if (p2pSupported) {
|
||||
manager.enableP2p(function(success) {});
|
||||
}
|
||||
}
|
||||
|
||||
function prepareForStartup(callback) {
|
||||
|
@ -911,19 +946,27 @@ var WifiManager = (function() {
|
|||
// Note these following calls ignore errors. If we fail to kill the
|
||||
// supplicant gracefully, then we need to continue telling it to die
|
||||
// until it does.
|
||||
manager.state = "DISABLING";
|
||||
wifiCommand.terminateSupplicant(function (ok) {
|
||||
manager.connectionDropped(function () {
|
||||
wifiCommand.stopSupplicant(function (status) {
|
||||
wifiCommand.closeSupplicantConnection(function () {
|
||||
manager.state = "UNINITIALIZED";
|
||||
netUtil.disableInterface(manager.ifname, function (ok) {
|
||||
unloadDriver(WIFI_FIRMWARE_STATION, callback);
|
||||
let doDisableWifi = function() {
|
||||
manager.state = "DISABLING";
|
||||
wifiCommand.terminateSupplicant(function (ok) {
|
||||
manager.connectionDropped(function () {
|
||||
wifiCommand.stopSupplicant(function (status) {
|
||||
wifiCommand.closeSupplicantConnection(function () {
|
||||
manager.state = "UNINITIALIZED";
|
||||
netUtil.disableInterface(manager.ifname, function (ok) {
|
||||
unloadDriver(WIFI_FIRMWARE_STATION, callback);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (p2pSupported) {
|
||||
p2pManager.setEnabled(false, { onDisabled: doDisableWifi });
|
||||
} else {
|
||||
doDisableWifi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1135,6 +1178,11 @@ var WifiManager = (function() {
|
|||
wifiCommand.saveConfig(callback);
|
||||
}
|
||||
manager.enableNetwork = function(netId, disableOthers, callback) {
|
||||
if (p2pSupported) {
|
||||
// We have to stop wifi direct scan before associating to an AP.
|
||||
// Otherwise we will get a "REJECT" wpa supplicant event.
|
||||
p2pManager.setScanEnabled(false, function(success) {});
|
||||
}
|
||||
wifiCommand.enableNetwork(netId, disableOthers, callback);
|
||||
}
|
||||
manager.disableNetwork = function(netId, callback) {
|
||||
|
@ -1215,6 +1263,46 @@ var WifiManager = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
manager.handlePreWifiScan = function() {
|
||||
if (p2pSupported) {
|
||||
// Before doing regular wifi scan, we have to disable wifi direct
|
||||
// scan first. Otherwise we will never get the scan result.
|
||||
p2pManager.blockScan();
|
||||
}
|
||||
};
|
||||
|
||||
manager.handlePostWifiScan = function() {
|
||||
if (p2pSupported) {
|
||||
// After regular wifi scanning, we should restore the restricted
|
||||
// wifi direct scan.
|
||||
p2pManager.unblockScan();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Public APIs for P2P.
|
||||
//
|
||||
|
||||
manager.p2pSupported = function() {
|
||||
return p2pSupported;
|
||||
};
|
||||
|
||||
manager.getP2pManager = function() {
|
||||
return p2pManager;
|
||||
};
|
||||
|
||||
manager.enableP2p = function(callback) {
|
||||
p2pManager.setEnabled(true, {
|
||||
onSupplicantConnected: function() {
|
||||
wifiService.waitForEvent(WifiP2pManager.INTERFACE_NAME);
|
||||
},
|
||||
|
||||
onEnabled: function(success) {
|
||||
callback(success);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return manager;
|
||||
})();
|
||||
|
||||
|
@ -1497,6 +1585,17 @@ function WifiWorker() {
|
|||
this._connectionInfoTimer = null;
|
||||
this._reconnectOnDisconnect = false;
|
||||
|
||||
// Create p2pObserver and assign to p2pManager.
|
||||
if (WifiManager.p2pSupported()) {
|
||||
this._p2pObserver = WifiP2pWorkerObserver(WifiManager.getP2pManager());
|
||||
WifiManager.getP2pManager().setObserver(this._p2pObserver);
|
||||
|
||||
// Add DOM message observerd by p2pObserver to the message listener as well.
|
||||
this._p2pObserver.getObservedDOMMessages().forEach((function(msgName) {
|
||||
this._mm.addMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
// Users of instances of nsITimer should keep a reference to the timer until
|
||||
// it is no longer needed in order to assure the timer is fired.
|
||||
this._callbackTimer = null;
|
||||
|
@ -1529,6 +1628,7 @@ function WifiWorker() {
|
|||
// wait for our next command) ensure that background scanning is on and
|
||||
// then try again.
|
||||
debug("Determined that scanning is stuck, turning on background scanning!");
|
||||
WifiManager.handlePostWifiScan();
|
||||
WifiManager.disconnect(function(ok) {});
|
||||
self._turnOnBackgroundScan = true;
|
||||
}
|
||||
|
@ -2304,6 +2404,15 @@ WifiWorker.prototype = {
|
|||
let msg = aMessage.data || {};
|
||||
msg.manager = aMessage.target;
|
||||
|
||||
if (WifiManager.p2pSupported()) {
|
||||
// If p2pObserver returns something truthy, return it!
|
||||
// Otherwise, continue to do the rest of tasks.
|
||||
var p2pRet = this._p2pObserver.onDOMMessage(aMessage);
|
||||
if (p2pRet) {
|
||||
return p2pRet;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: By the time we receive child-process-shutdown, the child process
|
||||
// has already forgotten its permissions so we do this before the
|
||||
// permissions check.
|
||||
|
@ -2393,79 +2502,6 @@ WifiWorker.prototype = {
|
|||
}).bind(this));
|
||||
},
|
||||
|
||||
getWifiScanResults: function(callback) {
|
||||
var count = 0;
|
||||
var timer = null;
|
||||
var self = this;
|
||||
|
||||
self.waitForScan(waitForScanCallback);
|
||||
doScan();
|
||||
function doScan() {
|
||||
WifiManager.scan(true, function (ok) {
|
||||
if (!ok) {
|
||||
if (!timer) {
|
||||
count = 0;
|
||||
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
}
|
||||
|
||||
if (count++ >= 3) {
|
||||
timer = null;
|
||||
this.wantScanResults.splice(this.wantScanResults.indexOf(waitForScanCallback), 1);
|
||||
callback.onfailure();
|
||||
return;
|
||||
}
|
||||
|
||||
// Else it's still running, continue waiting.
|
||||
timer.initWithCallback(doScan, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function waitForScanCallback(networks) {
|
||||
if (networks === null) {
|
||||
callback.onfailure();
|
||||
return;
|
||||
}
|
||||
|
||||
var wifiScanResults = new Array();
|
||||
var net;
|
||||
for (let net in networks) {
|
||||
let value = networks[net];
|
||||
wifiScanResults.push(transformResult(value));
|
||||
}
|
||||
callback.onready(wifiScanResults.length, wifiScanResults);
|
||||
}
|
||||
|
||||
function transformResult(element) {
|
||||
var result = new WifiScanResult();
|
||||
result.connected = false;
|
||||
for (let id in element) {
|
||||
if (id === "__exposedProps__") {
|
||||
continue;
|
||||
}
|
||||
if (id === "security") {
|
||||
result[id] = 0;
|
||||
var security = element[id];
|
||||
for (let j = 0; j < security.length; j++) {
|
||||
if (security[j] === "WPA-PSK") {
|
||||
result[id] |= Ci.nsIWifiScanResult.WPA_PSK;
|
||||
} else if (security[j] === "WPA-EAP") {
|
||||
result[id] |= Ci.nsIWifiScanResult.WPA_EAP;
|
||||
} else if (security[j] === "WEP") {
|
||||
result[id] |= Ci.nsIWifiScanResult.WEP;
|
||||
} else {
|
||||
result[id] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result[id] = element[id];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
getKnownNetworks: function(msg) {
|
||||
const message = "WifiManager:getKnownNetworks:Return";
|
||||
if (!WifiManager.enabled) {
|
||||
|
@ -2722,7 +2758,7 @@ WifiWorker.prototype = {
|
|||
let self = this;
|
||||
let detail = msg.data;
|
||||
if (detail.method === "pbc") {
|
||||
WifiManager.wpsPbc(function(ok) {
|
||||
WifiManager.wpsPbc(WifiManager.ifname, function(ok) {
|
||||
if (ok)
|
||||
self._sendMessage(message, true, true, msg);
|
||||
else
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMMozWifiConnectionInfoEvent.idl',
|
||||
'nsIDOMMozWifiP2pStatusChangeEvent.idl',
|
||||
'nsIDOMMozWifiStatusChangeEvent.idl',
|
||||
'nsIWifi.idl',
|
||||
'nsIWifiService.idl',
|
||||
|
@ -16,13 +17,18 @@ XPIDL_MODULE = 'dom_wifi'
|
|||
EXTRA_COMPONENTS += [
|
||||
'DOMWifiManager.js',
|
||||
'DOMWifiManager.manifest',
|
||||
'DOMWifiP2pManager.js',
|
||||
'DOMWifiP2pManager.manifest',
|
||||
'WifiWorker.js',
|
||||
'WifiWorker.manifest',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'StateMachine.jsm',
|
||||
'WifiCommand.jsm',
|
||||
'WifiNetUtil.jsm',
|
||||
'WifiP2pManager.jsm',
|
||||
'WifiP2pWorkerObserver.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
|
|
Загрузка…
Ссылка в новой задаче