一,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源码分析(一)
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设备。
至此,连接流程结束。