一,Wi-Fi P2P相关知识

(一)P2P及其依赖的技术项

android p2p 与热点共存_ide

(二)P2P工作流程

包括1.设备的发现、2.组协调、3.认证关联、4.WPS以及4次握手。总体流程如下图:

 

android p2p 与热点共存_android p2p 与热点共存_02

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流程如下图:

 

android p2p 与热点共存_android_03

  • 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 p2p 与热点共存_ide_04


二,Android Wi-Fi P2P源码分析(一)

Android中Wi-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. 获取WifiP2pManager和Channel


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设备。

至此,连接流程结束。