Wi-Fi Alliance(Wi-Fi联盟)推出的一项重要技术规范Wi-Fi P2P。该规范的商品名为Wi-Fi Direct,它支持多个Wi-Fi设备在没有AP的情况下相互连接。 借助P2P技术,Wi-Fi设备之间的直接相连将极大拓展Wi-Fi技术的使用场景。如智能终端设备之间的多屏共享和互动功能。
p2p架构中定义了两种角色,分别是:
Device Discovery使用Probe Request和Probe Response帧来交换设备信息。
P2P为Device Discovery定义了两个状态和两个阶段。
两个状态:
两个阶段:
注:Operating Channel属性表示组建的P2P Group将在哪个频段上工作。并且其频段不限于Social Channels中指定的那三个频段。
GO Formation 包含两个阶段:
GO协商包含一个三路握手过程,用于协商谁是GO以及P2P组的一些特征。 这三路握手过程主要主要交换如下一些信息:
当一个P2P设备发送GO Negotiation Request后,100ms内没有接收到确认帧,则认为此次协商失败。GO Negotiation的一个主要目的就是交换GO Intent属性,以决定谁当GO。如果一个P2P设备只能当GO,则其GO Intent值必须设置为15。
第一个GO Negotiation Request帧的Tie Breaker位会被随机设置为0或1。在接下来的GO Negotiation Request帧中(该位会被置反,重传除外)。GO Negotiation Response帧的Tie breaker位将会根据相应的GO Negotiation Request帧的相应位置反。
wifi p2p工作流程
HSM(对应的类是StateMachine)和AsyncChannel是Android Java Framework中两个重要的类。目前还仅由Framework内部使用,SDK中并没有包含它们。
HSM在传统状态机对所有状态都一视同仁的基础上做了一些改变,使得状态和状态之间有了层级关系。在父状态中实现generic的功能,而在子状态中实现一些特定的处理。
State中重要函数:
HSM中一些重要的API:
HSM中状态和状态之间的层级关系体现:
AsyncChannel用于两个Handler之间的通信。具体的通信方式为源Handler通过sendMessage向目标Handler发送消息,而目标Handler通过replyToMessage回复源Handler处理结果。这两个Handler可位于同一个进程,也可分属两个不同的进程.
用法包含两种不同的应用模式(usage model)。
WifiService相关模块中,第二种应用模式使用得较多。
WifiP2pSettings是Settings应用中负责处理P2P相关UI/UE逻辑的主要类,与之交互的则是位于SystemServer进程中的WifiP2pService。
WifiP2pManager /frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
WifiP2pSettings packages/apps/Settings/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
WifiP2pServiceImpl /frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
WifiNative /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java
WifiMonitor /frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java
加载界面元素
通过监听广播的方式来了解系统中Wi-Fi P2P相关的信息及变化情况,进行相应的处理:
WifiP2pSettings将借助WifiP2pManager和系统中的WifiP2pService交互。WifiP2pSettings主要使用WifiP2pManager的几个重要函数:
WifiP2pService是Android系统中P2P功能的Java层核心模块。其家族类图如下。
P2pStateMachine是WifiP2pService定义的内部类,P2pStateMachine是WifiP2pService的核心。P2pStateMachine中定义的各个状态及层级关系如图:
P2pStateMachine初始状态为P2pDisabledState,然后:
1)P2pStateMachine收到来自WifiStateMachine的CMD_ENABLE_P2P消息,在该消息的处理逻辑中,P2pStateMachine将创建一个WifiMonitor对象以和wpa_supplicant进程交互。P2pStateMachine转入P2pEnablingState。
2)在P2pEnablingState中,处理SUP_CONNECT_EVENT消息,它代表WifiMonitor成功连接上了wpa_supplicant。P2pStateMachine将转入InactiveState。
3)InactiveState的父状态是P2pEnabledState,P2pEnabledState的EA将初始化P2P设置,这部分代码逻辑在initializeP2pSettings函数中。另外,WifiP2pSettings将收到一些P2P广播,此时P2P功能正常启动。
4)搜索设备时,P2pStateMachine将收到DISCVOER_PEERS消息。它在P2pEnabledState中被处理,wpas_supplicant将发起P2P DeviceDiscovery流程以搜索周围的P2P设备。
5)若有P2P设备被发现,P2pStateMachine将收到P2P_DEVICE_FOUND_EVENT消息。该消息由其父状态P2pEnabledState来处理。同时,WifiP2pSettings也会相应收到信息以更新UI。
6)连接时,WifiP2pSettings将发送CONNECT消息给P2pStateMachine。该消息由InactiveState来处理。大部分情况下(除了Persistent Group或者对端设备是GO的情况下),P2pStateMachine将转入ProvisionDiscoveryState。
7)ProvisionDiscoveryState中,P2pStateMachine将通知WPAS以开展ProvisioningDiscovery流程。之后,P2pStateMachine将收到P2P_PROV_DISC_PBC_RSP_EVENT消息。在该消息的处理过程中,P2pStateMachine将通过p2pConnectWithPinDisplay函数通知WPAS和对端设备启动Group Formation流程。此后,P2pStateMachine转入GroupNegotiationState。
8)Group Formation完成,一个Group也就创建成功,P2pStateMachine将收到P2P_GROUP_STARTED_EVENT消息。该消息由GroupNegotiationState处理。如果本机扮演GO的话,它将启动一个Dhcp服务器
9)当对端P2P Client(Group建立后,角色也就确定了)关联上本机的GO后, AP_STA_CONNECTED_EVENT消息将被发送给P2pStateMachine处理。
相关文件简介:
1、WifiP2pSettings 属于应用程序层,是对相关操作结果的一个视觉呈现。主要负责界面初始化、接收底层事件消息进行界面更新、发出相应命令等。
2、WifiP2pManager:是Wi-Fi P2P部分对外的接口,通过它来访问Wi-Fi P2p的核心功能。
3、WifiP2pService:是Wi-Fi P2p部分的核心,负责Wi-Fi整个流程的控制。
4、P2pStateMachine:继承了StateMachine。下发了加载驱动和启动supplicant命令,启动了WifiMonitor。
5、WifiMonitor:开启一个MonitorThread来实现事件的轮询,而轮询的关键函数是WifiNative.waitForEvent()。WifiMonitor将接收到的底层事件转换成WifiStateMachine所能识别的消息,然后将消息发送给WifiStateMachine。
6、WifiNative:封装了一系列本地调用的接口函数,通过JNI调用C++代码。
APP
WifiP2pManager manager;
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel
channel; channel = manager.initialize(this, getMainLooper(), null);
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {;}
@Override
public void onFailure(int reasonCode) {;}
}
WifiP2pManager:
public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {return initalizeChannel(srcContext, srcLooper, listener, getMessenger());}
private Channel initalizeChannel(Context srcContext, Looper srcLooper, ChannelListener listener,Messenger messenger) {
if (messenger == null) return null;
Channel c = new Channel(srcContext, srcLooper, listener);
if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
== AsyncChannel.STATUS_SUCCESSFUL) {
return c;
} else {return null;}
}
public void discoverPeers(Channel c, ActionListener listener) {
checkChannel(c);//void,c是否为空,若空,抛出IllegalArgumentException异常
c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
}
WifiP2pService:
P2pStateMachine当前处于InactiveState,不过DISCOVER_PEERS消息却是由其父状态
P2pEnabledState来处理的.
case WifiP2pManager.DISCOVER_PEERS:
if (mDiscoveryBlocked) {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.BUSY);
break;
}
// do not send service discovery request while normal find operation.
clearSupplicantServiceRequest();
if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {//向WPAS发送P2P_FIND命令
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
sendP2pDiscoveryChangedBroadcast(true);
} else {
replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
WifiP2pManager.ERROR);
}
break;
WifiP2pService:
上述处理流程主要调用WifiNative的p2pFind函数,它会向wpa_supplicant发送P2P_FIND命令。若成功发送这个命令,就会通过WifiManager中discoverPeers的第二个参数ActionListener来告知Application执行成功;若执行失败,也会通知Application,只是回调不同的方法,一个是onSuccess(),一个是onFailure()。
wpa_supplicant收到P2P_FIND后,开始搜索周边的P2P设备,若找到,给WifiMonitor发送P2P-DEVICE-FOUND这样的event,WifiMonitor收到后,会将P2P-DEVICE-FOUND后面的data数据封装成为WifiP2pDevice对象,然后发送P2P_DEVICE_FOUND_EVENT消息给WIfiStateMachine处理。
P2P_DEVICE_FOUND_EVENT也由InactiveState的父状态P2pEnabledState来处理:
case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
WifiP2pDevice device = (WifiP2pDevice) message.obj;
if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
mPeers.updateSupplicantDetails(device);
sendPeersChangedBroadcast();
break;
APP:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
if (manager != null) {
manager.requestPeers(channel, (WifiP2pManager.PeerListListener) activity.getFragmentManager().findFragmentById(R.id.frag_list));
}
}
WifiP2pManager:
public void requestPeers(Channel c, PeerListListener listener) {
checkChannel(c);
c.mAsyncChannel.sendMessage(REQUEST_PEERS, 0, c.putListener(listener));
}
P2P设备连接有四种情况:主动连接、被动连接、主动invite和被动invite 这里以主动连接介绍P2P连接流程。
APP:
mContentView.findViewById(R.id.btn_connect).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
// 设置对端P2P Device的WSC配置方法为PBC
config.wps.setup = WpsInfo.PBC;
((DeviceListFragment.DeviceActionListener) getActivity()).connect(config);
}
});
public void connect(WifiP2pConfig config) {
manager.connect(channel, config, new WifiP2pManager.ActionListener() {
public void onSuccess() {}
public void onFailure(int reason) {}
});
}
WifiP2pManager:
public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {
checkChannel(c);
checkP2pConfig(config);
c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);
}
private static void checkP2pConfig(WifiP2pConfig c) {
if (c == null) throw new IllegalArgumentException("config cannot be null");
if (TextUtils.isEmpty(c.deviceAddress)) {
throw new IllegalArgumentException("deviceAddress cannot be empty");
}
}
WifiP2pManager的connect函数将发送CONNECT消息给P2pStateMachine,该消息由
InactiveState状态自己来处理
WifiP2pService:
case WifiP2pManager.CONNECT:
if (DBG) logd(getName() + " sending connect");
WifiP2pConfig config = (WifiP2pConfig) message.obj;
if (isConfigInvalid(config)) {
loge("Dropping connect requeset " + config);
replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
break;
}
mAutonomousGroup = false;
mWifiNative.p2pStopFind();
if (reinvokePersistentGroup(config)) {//判断是否采用persisten连接
transitionTo(mGroupNegotiationState);
} else { transitionTo(mProvisionDiscoveryState);}
mSavedPeerConfig = config;
mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
sendPeersChangedBroadcast();
replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
break;
WifiP2pService:
Group分为persistent和Temporary两种,对于persistent的连接,一次连接成功后,连接信息不在变化,包含credential、GO MAC地址、Ssid等信息。若采用persisten连接,就是去wpa_supplicant拿这些信息,并进行匹配。对于temporary,采用negotiate方式,则跳转到ProvisionDiscoveryState,其父状态是GroupCreatingState。
class GroupCreatingState extends State {
public void enter() {
if (DBG) logd(getName());
sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
}
class ProvisionDiscoveryState extends State {
public void enter() {
if (DBG) logd(getName());
mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
}
WifiNative的p2pProvisionDiscovery向对方发送Provision discovery封包。当对方收到Provision discovery封包后,会回复provision response,wpa_supplicant处理后,会给WifiMonitor发送P2P-PROV-DISC-PBC-RESP(当WPS方式为PBC时),WifiMonitor就会给P2pStateMachine发送P2P_PROV_DISC_PBC_RSP_EVNET。
WifiP2pService:
case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
provDisc = (WifiP2pProvDiscEvent) message.obj;
device = provDisc.device;
if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
if (DBG) logd("Found a match " + mSavedPeerConfig);
p2pConnectWithPinDisplay(mSavedPeerConfig);
transitionTo(mGroupNegotiationState);
}
break;
private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());//向wpa_supplicant发送P2P_CONNECT命令
try {
Integer.parseInt(pin);
notifyInvitationSent(pin, config.deviceAddress);
} catch (NumberFormatException ignore) {}
}
WifiP2pService:
开始Group negotiate后,wpa_supplicant会发送多个event给WifiMonitor,包括P2P-GO-NEG-SUCCESS、WPS-SUCCESS、P2P-GROUP-FORMATION-SUCCESS、P2P-GROUP-STARTED等.
其中比较重要的是P2P-GROUP-STARTED这个event,WifiMonitor收到这个event后会给P2pStateMachine发送P2P_GROUP_STARTED_EVENT,收到这个消息后,GroupNegotiationState主要调用DHCP相关的StateMachine开始会两端分配IP,然后更新group owner的相关信息,最后跳转至GroupCreatedState就表示连接完成了。
在DhcpStateMachine获取到IP地址以后,就会发送DhcpStateMachine.CMD_POST_DHCP_ACTION消息给P2pStateMachine
case DhcpStateMachine.CMD_POST_DHCP_ACTION:
DhcpResults dhcpResults = (DhcpResults) message.obj;
if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS && dhcpResults != null) {
if (DBG) logd("DhcpResults: " + dhcpResults);
setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);
sendP2pConnectionChangedBroadcast();
//Turn on power save on client
mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
try { String iface = mGroup.getInterface();
mNwService.addInterfaceToLocalNetwork(iface, dhcpResults.getRoutes(iface));
} catch (RemoteException e) { }
} else { loge("DHCP failed"); mWifiNative.p2pGroupRemove(mGroup.getInterface()); }
break;
其他三种连接
PS:
最近在测试wifi p2p相关. 发现一些流程已经不是很清楚了, 翻出来两年前自己整理的资料, 发现远超现在的水平.
逆水行舟, 不进则退.