1. 程式人生 > >Android Wi-Fi P2P原理與原始碼學習

Android Wi-Fi P2P原理與原始碼學習

一,Wi-Fi P2P相關知識

(一)P2P及其依賴的技術項


(二)P2P工作流程

包括1.裝置的發現、2.組協調、3.認證關聯、4.WPS以及4次握手。總體流程如下圖:

 

1.  Device Discovery工作流程介紹

P2P Device Discovery的工作流程包含兩個狀態和兩個階段。先來看兩個狀態,它們分別是:

  • Search State:在該狀態中,P2P Device將在2.4GHz的1,6,11頻段上分別傳送Probe Request幀。這幾個頻段被稱為Social Channels。為了區別非P2P的Probe Request幀,P2P Device Discovery要求必須在Probe Request幀中包含P2P IE。
  • Listen State:在該狀態下,P2P Device將隨機選擇在1,6,11頻段中的一個頻段(被選中的頻段被稱為Listen Channel)監聽Probe Request幀並回復Probe Response幀。值得指出的是,Listen Channel一旦選擇好後,在整個P2P Discovery階段就不能更改。另外,在這個階段中,P2P Device只處理那些包含了P2P IE資訊的Probe Request幀。

再來看兩個階段,它們分別是:

  • Scan Phase:掃描階段。這一階段和前面章節介紹的無線網路掃描一樣,P2P Device會在各個頻段上傳送Probe Request幀(主動掃描)。P2P Device在這一階段中不會處理來自其他裝置的Probe Request幀。這一階段過後,P2P Device將進入下一個階段,即Find Phase。
  • Find Phase:雖然從中文翻譯來看,Scan和Find意思比較接近,但P2P的Find Phase卻和Scan Phase大不相同。在這一階段中,P2P Device將在Search State和Listen State之間來回切換。Search State中,P2P Device將傳送Probe Request幀,而Listen State中,它將接收其他裝置的Probe Request幀並回復Probe Response幀。

Discovery流程如下圖:

 

  • Discovery啟動後,Device首先進入Scan Phase。在這一階段,P2P裝置在其支援的所有頻段上都會發送Probe Request幀。
  • Scan Phase完成後,Device進入Find Phase。在這一階段中,Device將在Listen和Search State中切換。根據前面的介紹,每一個裝置的Listen Channel在Discovery開始前就已確定。例如,圖中Device 1的Listen Channel是1,而Device 2的Listen Channel是6。
  • 在Find Phase中,P2P規範對Device處於Listen State的時間也有所規定,其時間是100TU的整數倍,倍數值是一個隨機數,位於minDiscoverableInterval和maxDiscoverableInterval之間。這兩個值預設為1和3,而廠商可以修改。選擇隨機倍數的原因是為了防止兩個Device進入所謂的Lock-Step怪圈,即兩個Device同時進入Listen State,等待相同的時間後又同時進入Search State。如此,雙方都無法處理對方的Probe Request資訊(Search State中,Device只發送Probe Request)。圖7-3中,Device 1第一次在Listen State中待了2個100TU,而第二次在Listen State中待了1個100TU。
  • 當Device處於Find Phase中的Search State時,它將在1,6,11頻段上傳送Probe Request幀。注意,只有當兩個裝置處於同一頻段時,一方傳送的幀才能被對方接收到。

2.組協調

GO Negotiation涉及三次幀交換,包括GO NegotiationRequest、GO Negotiation Response、GO Negotiation Confirmation,GO NegotiationRequest幀中的GO Intent屬性代表傳送裝置扮演GO的渴望程度,通過一下游戲規則來決定誰扮演GO:

 

二,Android Wi-Fi P2P原始碼分析()

AndroidWi-Fi P2P的操作主要有WifiP2pSettings類實現,其位置在:

packages/apps/Settings/src/com/android/settings/wifi/p2p/WifiP2pSettings.java

這裡先分析該類如何呼叫實現P2P的搜尋與連線,先不考慮底層如何實現。

1.註冊廣播監聽,監聽的內容有:

mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);  mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);  mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);


2. 獲取WifiP2pManagerChannel

manager =(WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel =manager.initialize(MainActivity.this, getMainLooper(), null)

3.搜尋周圍可用裝置

1.  

manager.discoverPeers(channel,new WifiP2pManager.ActionListener() {  
 @Override  
public void onSuccess() {  }  
@Override  
 public void onFailure(int reasonCode) {
} 
 });  

4.監聽裝置變化並獲取裝置列表

 mWifiP2pManager.requestPeers(mChannel,WifiP2pSettings.this);
WifiP2pSettings實現PeerListListener介面,重寫onPeersAvailable方法

@Override  

 public void onPeersAvailable(WifiP2pDeviceList peers) {  
    mPeers= peers;
    handlePeersChanged(); 

}  


5.連線裝置

	WifiP2pConfig config = new WifiP2pConfig();  
	config.deviceAddress = device.deviceAddress;  
	config.wps.setup = WpsInfo.PBC;  
	manager.connect(channel,config, new ActionListener() {  
	    @Override  
	    public void onSuccess() {}  
	    @Override  
	    public void onFailure(int reason) {}  
	});

相關許可權:

 <uses-permission android:name=”android.permission.ACCESS_WIFI_STATE” />  
<uses-permission android:name=”android.permission.CHANGE_WIFI_STATE” />  
 <uses-permission android:name=”android.permission.INTERNET” /> 

三,Android Wi-Fi P2P原始碼分析()

通過上述分析,瞭解到WifiP2pSettings主要通過呼叫WifiP2pManager的方法實現P2P的掃描與連線,下面分析WifiP2pManager及以下層次的實現。

WifiP2pService是處理WiFi P2P相關工作的核心模組,它有一個內部類P2pStateMachine,其互動方式與WiFiService和WifiStateMachine類似。P2pStateMachine有16種狀態,初始狀態為P2pDisabledState(若支援P2P)。

1.初始化

使用者開啟WiFi功能,WifiStateMachine會向P2pStateMachine傳送CMD_ENABLE_P2P的訊息,由P2pDisabledState處理,主要通過啟動WifiMonitor連線spa_supplicant,之後將轉入InactiveState狀態。

除了初始化階段是由WifiStateMachine發起之外,其餘的操作基本是通過WifiP2pSettings發起的。WifiP2pSettings呼叫WifiP2pManager的方法,WifiP2pManager通過AsyncChannel與WiFiService通訊,而WiFiService則將從WifiP2pManager傳送來的訊息轉發給P2pStateMachine處理。

2.掃描流程

WifiP2pSettings呼叫WifiP2pManager的discoverPeers方法,將傳送DISCOVER_PEERS訊息給P2pStateMachine,該訊息由當前狀態的父狀態P2pEnabledState處理。

@Override
      public boolean processMessage(Message message) {
          switch (message.what) {
              //程式碼省略
              case WifiP2pManager.DISCOVER_PEERS:
                 //程式碼省略
                  boolean retP2pFind = false;
                  if (isWfdSinkEnabled()) {
                      //copy from HE dongle
                      p2pConfigWfdSink();
                      retP2pFind = mWifiNative.p2pFind();
                  } else if (timeout == WifiP2pManager.BEAM_DISCOVERY_TIMEOUT) {
       					retP2pFind = mWifiNative.p2pFind(
WifiP2pManager.BEAM_DISCOVERY_TIMEOUT);
                  } else {
                    retP2pFind = mWifiNative.p2pFind(DISCOVER_TIMEOUT_S);
                  }
                  //程式碼省略
                  break;
                //程式碼省略
            }
        }
通過呼叫WifiNative的p2pFind()通知WPAS掃描周圍的P2P裝置,搜尋到裝置後將裝置資訊傳送給WifiMonitor,WifiMonitor然後傳送P2P_DEVICE_FOUND_EVENT給P2pStateMachine,同樣由P2pEnabledState處理。
@Override
      public boolean processMessage(Message message) {
          switch (message.what) {
              //程式碼省略
              case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
                    WifiP2pDevice device = (WifiP2pDevice) message.obj;
                    if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
                    mPeers.updateSupplicantDetails(device);
                    sendPeersChangedBroadcast();
                     ///M: force update peer information for invitation  @{
                    if (mUpdatePeerForInvited) {
                        if (mSavedPeerConfig.deviceAddress
.equals(device.deviceAddress)) {
                            mUpdatePeerForInvited = false;
                            sendMessage(M_P2P_DEVICE_FOUND_INVITATION);
                        }
                    }
                    break;
                  //程式碼省略
                  break;
                //程式碼省略
            }
        }

上述程式碼主要將搜尋到的裝置儲存到mPeers中,再發送WIFI_P2P_PEERS_CHANGED_ACTION的廣播,WifiP2pSettings收到該廣播後將通過WifiP2pManager的requestPeers獲取mPeers的內容。

3.連線流程

當用戶選擇某個裝置進行連線時,WifiP2pSettings呼叫WifiP2pManager的connect方法發起連線,WifiP2pManager將傳送CONNECT訊息給P2pStateMachine,該訊息有當前狀態InactiveState自己處理:

@Override
      public boolean processMessage(Message message) {
          switch (message.what) {
              case WifiP2pManager.CONNECT:
                    //程式碼省略
                    mAutonomousGroup = false;
                    mConnectToPeer = true;
                    if (mMiracastMode == WifiP2pManager.MIRACAST_SOURCE
                        && !WFD_DONGLE_USE_P2P_INVITE) {
                        // To support WFD dongle that doesn't support p2p_invite
                        transitionTo(mProvisionDiscoveryState);
                    } else {
                        // Normal connection case
                        if (reinvokePersistentGroup(config)) {
                            transitionTo(mGroupNegotiationState);
                        } else {
                            transitionTo(mProvisionDiscoveryState);
                        }
                    }
                    mSavedPeerConfig = config;
                    mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
  					sendPeersChangedBroadcast();
                    replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
                  break;
                //程式碼省略
            }
        } 

進入reinvokePersistentGroup(config)函式,若為發起端,則返回false,之後進入ProvisionDiscoveryState狀態,若為接受端則啟動Group Formation流程,然後進入GroupNegotiationState狀態。ProvisionDiscoveryState的enter()方法將向對端裝置傳送Provision Discovery Request幀:

mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig)

當對端裝置同意連線之後,將收到一個P2P_PROV_DISC_PBC_RSP_EVENT訊息,由ProvisionDiscoveryState處理:

@Override
      public boolean processMessage(Message message) {
          switch (message.what) {
              case WifiP2pManager.CONNECT:
                    case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
                    provDisc = (WifiP2pProvDiscEvent) message.obj;
                    device = provDisc.device;
                    if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) 
break;
                    ///M: for crossmount  @{
                    updateCrossMountInfo(provDisc.device.deviceAddress);
                    ///@}
                    if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
                        if (DBG) logd("Found a match " + mSavedPeerConfig);
                        p2pConnectWithPinDisplay(mSavedPeerConfig);
                        transitionTo(mGroupNegotiationState);
                    }
                    break; 
//程式碼省略
            }
        } 

p2pConnectWithPinDisplay(mSavedPeerConfig)函式將呼叫WifiNative的p2pConnect函式觸發WPAS傳送GON Request幀,接收端收到該幀,將彈出對話方塊詢問使用者是否接受請求。之後進入GroupNegotiationState。

當WPAS進行GroupFormation結束之後,P2pStateMachine將收到P2P_GROUP_STARTED_EVENT訊息,該訊息由GroupNegotiationState處理。

@Override
      public boolean processMessage(Message message) {
          switch (message.what) {
               case WifiMonitor.P2P_GROUP_STARTED_EVENT:
                    mGroup = (WifiP2pGroup) message.obj;
                    //程式碼省略
                    if (mGroup.isGroupOwner()) {
                        if (!mAutonomousGroup) {
                            mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 
GROUP_IDLE_TIME_S);
                        }
                        startDhcpServer(mGroup.getInterface());
                    } else {
                        ///M: No DHCP, use static IP @{
                        if (mGcIgnoresDhcpReq) {
                            //程式碼省略
                        } else {
                            mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 
GROUP_IDLE_TIME_S);
                            startIpManager(mGroup.getInterface());
                        }
                        //程式碼省略
                    }
                    transitionTo(mGroupCreatedState);
                    break;//程式碼省略
            }
        } 

若本機扮演GO,則通過startDhcpServer(mGroup.getInterface())啟動DhcpServer,若本機為GC,則通過startIpManager(mGroup.getInterface())去獲取IP地址,之後轉入GroupCreatedState。

當連線成功後,WifiMonitor還會發送一個AP_STA_CONNECTED_EVENT訊息,該訊息由GroupCreatedState處理:

其將呼叫mGroup.addClient(mPeers.get(deviceAddress))新增一個P2P裝置。

至此,連線流程結束。