Bug 1049460 - Change wpa_supplicant mux/demux method on KK to enable wifi direct. r=vchang
authorHenry Chang <hchang@mozilla.com>
Wed, 08 Oct 2014 15:18:35 +0800
changeset 210996 fa591de5d4ddfadfbb69a41666f3b335091a0caa
parent 210995 745dff11e9ecee82e9017b81c5d20c2a0bd0747d
child 210997 ad7a09962cc4da1d12ac75dd5a2840ec25e77640
push id11493
push usercbook@mozilla.com
push dateMon, 20 Oct 2014 09:07:43 +0000
treeherderb2g-inbound@ad7a09962cc4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvchang
bugs1049460
milestone36.0a1
Bug 1049460 - Change wpa_supplicant mux/demux method on KK to enable wifi direct. r=vchang
dom/wifi/DOMWifiP2pManager.js
dom/wifi/WifiCommand.jsm
dom/wifi/WifiP2pManager.jsm
dom/wifi/WifiProxyService.cpp
dom/wifi/WifiWorker.js
--- a/dom/wifi/DOMWifiP2pManager.js
+++ b/dom/wifi/DOMWifiP2pManager.js
@@ -144,17 +144,17 @@ MozWifiP2pManager.prototype = {
 
       case "WifiP2pManager:setScanEnabled:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to enable/disable Wifi P2P peer discovery.");
         break;
 
      case "WifiP2pManager:getPeerList:Return:OK":
         request = this.takeRequest(msg.rid);
-        Services.DOMRequest.fireSuccess(request, msg.data);
+        Services.DOMRequest.fireSuccess(request, Cu.cloneInto(msg.data, this._window));
         break;
 
       case "WifiP2pManager:getPeerList:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to disable Wifi P2P peer discovery.");
         break;
 
       case "WifiP2pManager:connect:Return:OK":
--- a/dom/wifi/WifiCommand.jsm
+++ b/dom/wifi/WifiCommand.jsm
@@ -21,16 +21,23 @@ this.WifiCommand = function(aControlMess
     if (DEBUG) {
       dump('-------------- WifiCommand: ' + msg);
     }
   }
 
   var command = {};
 
   //-------------------------------------------------
+  // Utilities.
+  //-------------------------------------------------
+  command.getSdkVersion = function() {
+    return aSdkVersion;
+  };
+
+  //-------------------------------------------------
   // General commands.
   //-------------------------------------------------
 
   command.loadDriver = function (callback) {
     voidControlMessage("load_driver", function(status) {
       callback(status);
     });
   };
--- a/dom/wifi/WifiP2pManager.jsm
+++ b/dom/wifi/WifiP2pManager.jsm
@@ -603,28 +603,38 @@ function P2pStateMachine(aP2pCommand, aN
       function onSuccess()
       {
         _onEnabled(true);
         _sm.gotoState(stateInactive);
       }
 
       _sm.pause();
 
-      // Step 1: Connect to p2p0.
-      aP2pCommand.connectToSupplicant(function (status) {
-        let detail;
-
-        if (0 !== status) {
-          debug('Failed to connect to p2p0');
-          onFailure();
+      // This function will only call back on success.
+      function connectToSupplicantIfNeeded(callback) {
+        if (aP2pCommand.getSdkVersion() >= 19) {
+          // No need to connect to supplicant on KK. Call back directly.
+          callback();
           return;
         }
+        aP2pCommand.connectToSupplicant(function (status) {
+          if (0 !== status) {
+            debug('Failed to connect to p2p0');
+            onFailure();
+            return;
+          }
+          debug('wpa_supplicant p2p0 connected!');
+          _onSupplicantConnected();
+          callback();
+        });
+      }
 
-        debug('wpa_supplicant p2p0 connected!');
-        _onSupplicantConnected();
+      // Step 1: Connect to p2p0 if needed.
+      connectToSupplicantIfNeeded(function callback () {
+        let detail;
 
         // Step 2: Get MAC address.
         if (!_localDevice.address) {
           aP2pCommand.getMacAddress(function (address) {
             if (!address) {
               debug('Failed to get MAC address....');
               onFailure();
               return;
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -169,16 +169,24 @@ WifiProxyService::FactoryCreate()
 NS_IMETHODIMP
 WifiProxyService::Start(nsIWifiEventListener* aListener,
                         const char ** aInterfaces,
                         uint32_t aNumOfInterfaces)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
+#if ANDROID_VERSION >= 19
+  // KK changes the way mux'ing/demux'ing different supplicant interfaces
+  // (e.g. wlan0/p2p0) from multi-sockets to single socket embedded with
+  // prefixed interface name (e.g. IFNAME=wlan0 xxxxxx). Therefore, we use
+  // the first given interface as the global interface for KK.
+  aNumOfInterfaces = 1;
+#endif
+
   nsresult rv;
 
   // Since EventRunnable runs in the manner of blocking, we have to
   // spin a thread for each interface.
   // (See the WpaSupplicant::WaitForEvent)
   mEventThreadList.SetLength(aNumOfInterfaces);
   for (uint32_t i = 0; i < aNumOfInterfaces; i++) {
     mEventThreadList[i].mInterface = aInterfaces[i];
@@ -245,24 +253,33 @@ WifiProxyService::SendCommand(JS::Handle
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WifiProxyService::WaitForEvent(const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+#if ANDROID_VERSION >= 19
+  // We will only have one global interface for KK.
+  if (!mEventThreadList.IsEmpty()) {
+    nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
+    mEventThreadList[0].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
+    return NS_OK;
+  }
+#else
   // Dispatch to the event thread which has the given interface name
   for (size_t i = 0; i < mEventThreadList.Length(); i++) {
     if (mEventThreadList[i].mInterface.Equals(aInterface)) {
       nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
       mEventThreadList[i].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
       return NS_OK;
     }
   }
+#endif
 
   return NS_ERROR_FAILURE;
 }
 
 void
 WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -277,26 +294,37 @@ WifiProxyService::DispatchWifiResult(con
   // Call the listener with a JS value.
   mListener->OnCommand(val, aInterface);
 }
 
 void
 WifiProxyService::DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
+
+#if ANDROID_VERSION < 19
+  mListener->OnWaitEvent(aEvent, aInterface);
+#else
+  // The interface might be embedded in the event string such as
+  // "IFNAME=wlan0 CTRL-EVENT-BSS-ADDED 65 3c:94:d5:7c:11:8b".
+  // Parse the interface name from the event string and use p2p0
+  // as the default interface if "IFNAME" is not found.
   nsAutoString event;
+  nsAutoString embeddedInterface(NS_LITERAL_STRING("p2p0"));
   if (StringBeginsWith(aEvent, NS_LITERAL_STRING("IFNAME"))) {
-    // Jump over IFNAME for gonk-kk.
+    int32_t ifnameFrom = aEvent.FindChar('=') + 1;
+    int32_t ifnameTo = aEvent.FindChar(' ') - 1;
+    embeddedInterface = Substring(aEvent, ifnameFrom, ifnameTo - ifnameFrom + 1);
     event = Substring(aEvent, aEvent.FindChar(' ') + 1);
   }
   else {
     event = aEvent;
   }
-  // Call the listener.
-  mListener->OnWaitEvent(event, aInterface);
+  mListener->OnWaitEvent(event, NS_ConvertUTF16toUTF8(embeddedInterface));
+#endif
 }
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
                                          WifiProxyService::FactoryCreate)
 
 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
 
 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -129,17 +129,21 @@ var WifiManager = (function() {
     capabilities.eapMethod.unshift("SIM");
   }
 
   let wifiListener = {
     onWaitEvent: function(event, iface) {
       if (manager.ifname === iface && handleEvent(event)) {
         waitForEvent(iface);
       } else if (p2pSupported) {
-        if (WifiP2pManager.INTERFACE_NAME === iface) {
+        // Please refer to
+        // http://androidxref.com/4.4.2_r1/xref/frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java#519
+        // for interface event mux/demux rules. In short words, both
+        // 'p2p0' and 'p2p-' should go to Wifi P2P state machine.
+        if (WifiP2pManager.INTERFACE_NAME === iface || -1 !== iface.indexOf('p2p-')) {
           // 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;
           }