WifiP2pService的启动以及P2P的连接

来源:互联网 发布:wpf软件 编辑:程序博客网 时间:2024/05/16 01:13

这一章主要总结从WifiP2pService的启动到用户通过四种连接方式连接P2P的过程,四种方式包括:主动连接、被动连接、主动invite和被动invite。首先来看WifiP2pService的启动。


WifiP2pService的启动

WifiP2pService的创建以及启动是在SystemServer中,主要代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. wifiP2p = new WifiP2pService(context);  
  2. ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);  
  3.   
  4. wifiP2p.connectivityServiceReady();  

进入到WifiP2pService的构造函数分析:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public WifiP2pService(Context context) {  
  2.     mContext = context;  
  3.   
  4.     //STOPSHIP: get this from native side  
  5.     mInterface = "p2p0";  
  6.     mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");  
  7.   
  8.     mP2pSupported = mContext.getPackageManager().hasSystemFeature(  
  9.             PackageManager.FEATURE_WIFI_DIRECT);  
  10.   
  11.     mThisDevice.primaryDeviceType = mContext.getResources().getString(  
  12.             com.android.internal.R.string.config_wifi_p2p_device_type);  
  13.   
  14.     mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported);  
  15.     mP2pStateMachine.start();  
  16. }  

WifiP2pService的构造函数很简单,主要是创建一个NetworkInfo的对象,然后通过PackageManagerService获取到系统是否支持P2P,然后创建一个P2pStateMachine并启动这个StateMachine,进入到P2pStateMachine中分析:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. P2pStateMachine(String name, boolean p2pSupported) {  
  2.     super(name);  
  3.   
  4.     addState(mDefaultState);  
  5.         addState(mP2pNotSupportedState, mDefaultState);  
  6.         addState(mP2pDisablingState, mDefaultState);  
  7.         addState(mP2pDisabledState, mDefaultState);  
  8.         addState(mP2pEnablingState, mDefaultState);  
  9.         addState(mP2pEnabledState, mDefaultState);  
  10.             addState(mInactiveState, mP2pEnabledState);  
  11.             addState(mGroupCreatingState, mP2pEnabledState);  
  12.                 addState(mUserAuthorizingInviteRequestState, mGroupCreatingState);  
  13.                 addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState);  
  14.                 addState(mProvisionDiscoveryState, mGroupCreatingState);  
  15.                 addState(mGroupNegotiationState, mGroupCreatingState);  
  16.                 addState(mFrequencyConflictState, mGroupCreatingState);  
  17.             addState(mGroupCreatedState, mP2pEnabledState);  
  18.                 addState(mUserAuthorizingJoinState, mGroupCreatedState);  
  19.                 addState(mOngoingGroupRemovalState, mGroupCreatedState);  
  20.   
  21.     if (p2pSupported) {  
  22.         setInitialState(mP2pDisabledState);  
  23.     } else {  
  24.         setInitialState(mP2pNotSupportedState);  
  25.     }  
  26.     setLogRecSize(50);  
  27.     setLogOnlyTransitions(true);  
  28. }  

通过上面的构造函数,我们可以看出P2pStateMachine的各个State关系如下。并且若在支持P2P的情况下,InitialState是P2pDisabledState;若在不支持P2P的情况下,InitialState是P2pNotSupportedState。


接着回到SystemServer中,会调用到WifiP2pService的connectivityServiceReady函数,这个函数比较简单,首先通过ServiceManager获取NETWORKMANAGEMENT_SERVICE,然后记录到mNwService中。这样WifiP2pService的启动流程就介绍完毕了,下面再来看当Enable Wifi时,如何Enable P2p。

Enable P2p


还记得我们在Wifi toggle on这个章节有说过,在WifiStateMachine的DriverStartedState中,如平台支持P2P,还将会给WifiP2pService发送CMD_ENABLE_P2P的消息,在Android 4.4的平台上面,当打开Wifi时,会同时把P2p也enable,我们从这里开始分析。首先由前面的知识,我们进入P2pDisabledState看如何处理CMD_ENABLE_P2P消息:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class P2pDisabledState extends State {  
  2.    @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.     }  
  6.   
  7.     @Override  
  8.     public boolean processMessage(Message message) {  
  9.         if (DBG) logd(getName() + message.toString());  
  10.         switch (message.what) {  
  11.             case WifiStateMachine.CMD_ENABLE_P2P:  
  12.                 try {  
  13.                     mNwService.setInterfaceUp(mInterface);  
  14.                 } catch (RemoteException re) {  
  15.                     loge("Unable to change interface settings: " + re);  
  16.                 } catch (IllegalStateException ie) {  
  17.                     loge("Unable to change interface settings: " + ie);  
  18.                 }  
  19.                 mWifiMonitor.startMonitoring();  
  20.                 transitionTo(mP2pEnablingState);  
  21.                 break;  

首先通过NetworkManagementService将P2P0设置为up状态,然后通过WifiMonitor去和wpa_supplicant建立socket连接,因为在WifiStateMachine的DriverStartedState中,wpa_supplicant已经启动成功了,所以我们这里可以直接去和wpa_supplicant通信,最后转到P2pEnablingState处理和wpa_supplicant连接成功与否的消息。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class P2pEnablingState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.     }  
  6.   
  7.     @Override  
  8.     public boolean processMessage(Message message) {  
  9.         if (DBG) logd(getName() + message.toString());  
  10.         switch (message.what) {  
  11.             case WifiMonitor.SUP_CONNECTION_EVENT:  
  12.                 if (DBG) logd("P2p socket connection successful");  
  13.                 transitionTo(mInactiveState);  
  14.                 break;  
  15.             case WifiMonitor.SUP_DISCONNECTION_EVENT:  
  16.                 loge("P2p socket connection failed");  
  17.                 transitionTo(mP2pDisabledState);  
  18.                 break;  
  19.             case WifiStateMachine.CMD_ENABLE_P2P:  
  20.             case WifiStateMachine.CMD_DISABLE_P2P_REQ:  
  21.                 deferMessage(message);  
  22.                 break;  
  23.             default:  
  24.                 return NOT_HANDLED;  
  25.         }  
  26.         return HANDLED;  
  27.     }  
  28. }  

由Wifi toggle on的知识我们可以知道,当WifiMonitor与wpa_suppliant建立socket成功后,会给P2pStateMachine发送SUP_CONNECT_EVENT消息,P2pEnablingState这时会跳转到InactiveState中,由前面P2pStateMachine的State关系图我们可以知道,P2pEnabledState是InactiveState父State,我们先到P2pEnabledState的enter函数去分析:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class P2pEnabledState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         sendP2pStateChangedBroadcast(true);  
  6.         mNetworkInfo.setIsAvailable(true);  
  7.         sendP2pConnectionChangedBroadcast();  
  8.         initializeP2pSettings();  
  9.     }  

这里主要发送两个broadcast,然后初始化一些P2p的设置,包括deviceName、DeviceType、ConfigMethods,并且获取以前persistent的相关device信息。


P2p设备扫描

当用户到Settings-->P2p中点击扫描后,就开始启动discoverPeers的流程了,首先来看一下WifiP2pManager提供给我们的文档说明:
The API is asynchronous and responses to requests from an application are on listener callbacks provided by the application. The application needs to do an initialization with initialize(Context, Looper, WifiP2pManager.ChannelListener) before doing any p2p operation.

这段话告诉我们WifiP2pManager提供给application的函数都是异步的,并且在调用其它p2p的方法之前,需要先调用initialize方法,那我们首先来看一下initialize的实现:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {  
  2.     Messenger messenger = getMessenger();  
  3.     if (messenger == nullreturn null;  
  4.   
  5.     Channel c = new Channel(srcContext, srcLooper, listener);  
  6.     if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)  
  7.             == AsyncChannel.STATUS_SUCCESSFUL) {  
  8.         return c;  
  9.     } else {  
  10.         return null;  
  11.     }  
  12. }  

这段代码主要的功能是创建一个Channel对象,Channel是将application和wifi p2p framework连接的对象,当然我们知道wifi p2p framework中最核心的还是WifiP2pService,所以Channel需要将application的消息发送给WifiP2pService,所以我们就看到函数开头的getMessenger函数,通过这个函数会利用WifiP2pService中的P2pStateMachine的handler创建一个Messenger对象并返回;然后Channel对象中又会创建一个AsyncChannel对象,通过AsyncChanne将Channel自身的handler与P2pStateMachine联系起来。我们可以简单的理解Channel是对AsyncChannel的封装,用于实现applicantion与WifiP2pService之间的异步通信。流程图文章最底下图中的左上方。

接着我们就可以调用discoverPeers来进行P2P设备的扫描了,代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void discoverPeers(Channel c, ActionListener listener) {  
  2.     checkChannel(c);  
  3.     c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));  
  4. }  

由前面Enable P2p的知识,我们知道P2pEnabledState会处理DISCOVER_PEERS消息,代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiP2pManager.DISCOVER_PEERS:  
  2.     if (mDiscoveryBlocked) {  
  3.         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,  
  4.                 WifiP2pManager.BUSY);  
  5.         break;  
  6.     }  
  7.     // do not send service discovery request while normal find operation.  
  8.     clearSupplicantServiceRequest();  
  9.     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {  
  10.         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);  
  11.         sendP2pDiscoveryChangedBroadcast(true);  
  12.     } else {  
  13.         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,  
  14.                 WifiP2pManager.ERROR);  
  15.     }  
  16.     break;  

P2pEnabledState处理DISCOVER_PEERS流程中主要调用WifiNative的p2pFind函数,它会向wpa_supplicant发送P2P_FIND命令。若成功发送这个命令,就会通过WifiManager中discoverPeers的第二个参数ActionListener来告知Application执行成功;若执行失败,也会通知Application,只是回调不同的方法,一个是onSuccess(),一个是onFailure()。

wpa_supplicant收到P2P_FIND后,就会开始搜索周边的P2P设备,如果有找到,则会给WifiMonitor发送P2P-DEVICE-FOUND这样的event,这个event会带有对方设备的信息,包括MAC地址、device type、设备名字以及config methods等,例如P2P-DEVICE-FOUND 02:08:22:22:ec:fb p2p_dev_addr=02:08:22:22:ec:fb pri_dev_type=10-0050F204-5 name='Android_7a5f' config_methods=0x188 dev_capab=0x25 group_capab=0x0 wfd_dev_info=0x00000600101c440032。WifiMonitor收到这样的event后,会将P2P-DEVICE-FOUND后面的data数据封装成为一个WifiP2pDevice对象,然后发送P2P_DEVICE_FOUND_EVENT消息给WIfiStateMachine处理。接着我们到P2pEnabledState看如何处理P2P_DEVICE_FOUND_EVENT:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_DEVICE_FOUND_EVENT:  
  2.     WifiP2pDevice device = (WifiP2pDevice) message.obj;  
  3.     if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;  
  4.     mPeers.updateSupplicantDetails(device);  
  5.     sendPeersChangedBroadcast();  
  6.     break;  

mPeers是一个WifiP2pDeviceList对象,它内部维护一个全局的HashMap来维护所有找到的P2P 设备信息,HashMpa的key是P2P设备的MAC地址,值即为上面的WifiP2pDevice对象。然后通过sendPeersChangedBroadcast发送一个 WIFI_P2P_PEERS_CHANGED_ACTION的broadcast,这样WifiP2pSettings收到这个broadcast后,就可以直接通过WifiP2pDeviceList对象来访问里面的HasmMap来显示所有的P2P设备了。

连接P2P设备

这里开始介绍四种连接方式:主动连接、被动连接、主动invite和被动invite

主动连接

先来看一下这部分的总体流程图:


当用户选择扫描到的设备列表中的一个设备后,就会开始连接流程,通过调用WifiManager.connect(Channel c, WifiP2pConfig config, ActionListener listener),其中第一个参数Channel即从initialize中返回的,第二个参数WifiP2pConfig包含对方设备的MAC地址、WPS等信息。进入到connect函数看这个方法的实现:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void connect(Channel c, WifiP2pConfig config, ActionListener listener) {  
  2.     checkChannel(c);  
  3.     checkP2pConfig(config);  
  4.     c.mAsyncChannel.sendMessage(CONNECT, 0, c.putListener(listener), config);  
  5. }  

通过Channel中的AsyncChannel给P2pStateMachine发送一个CONNECT消息,由前面的扫描阶段的知识,InactiveState会处理CONNECT消息:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiP2pManager.CONNECT:  
  2.     if (DBG) logd(getName() + " sending connect");  
  3.     WifiP2pConfig config = (WifiP2pConfig) message.obj;  
  4.     if (isConfigInvalid(config)) {  
  5.         loge("Dropping connect requeset " + config);  
  6.         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);  
  7.         break;  
  8.     }  
  9.   
  10.     mAutonomousGroup = false;  
  11.     mWifiNative.p2pStopFind();  
  12.     if (reinvokePersistentGroup(config)) {  
  13.         transitionTo(mGroupNegotiationState);  
  14.     } else {  
  15.         transitionTo(mProvisionDiscoveryState);  
  16.     }  
  17.     mSavedPeerConfig = config;  
  18.     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);  
  19.     sendPeersChangedBroadcast();  
  20.     replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);  
  21.     break;  

这里分为persistent的连接方式和非persistent方式,对于persistent的连接,如果第一次连接成功后,wpa_supplicant会记录这次连接的所有信息,包含credential、GO MAC地址、Ssid等信息,所以判断对方是否采用persisten连接,就是去wpa_supplicant拿这些信息,并进行匹配。对于非persistent的连接方式,即采用negotiate方式,则跳转到ProvisionDiscoveryState,用于发送Provision discovery封包,ProvisionDiscoveryState的父State是GroupCreatingState。首先到GroupCreartingState和ProvisionDiscoveryState的enter函数去分析:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class GroupCreatingState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,  
  6.                 ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);  
  7.     }  
  8.   
  9. class ProvisionDiscoveryState extends State {  
  10.     @Override  
  11.     public void enter() {  
  12.         if (DBG) logd(getName());  
  13.         mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);  
  14.     }  

在GroupCreartingState中会发送一个delay message,用于设置P2P连接的timeout时间,timeout时间为120秒。在ProvisionDiscoveryState中调用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,来看ProvisionDiscoveryState如何处理这个消息:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1.             case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:  
  2.                 provDisc = (WifiP2pProvDiscEvent) message.obj;  
  3.                 device = provDisc.device;  
  4.                 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;  
  5.   
  6.                 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {  
  7.                     if (DBG) logd("Found a match " + mSavedPeerConfig);  
  8.                     p2pConnectWithPinDisplay(mSavedPeerConfig);  
  9.                     transitionTo(mGroupNegotiationState);  
  10.                 }  
  11.                 break;  
  12.   
  13. private void p2pConnectWithPinDisplay(WifiP2pConfig config) {  
  14.     WifiP2pDevice dev = fetchCurrentDeviceDetails(config);  
  15.   
  16.     String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());  
  17.     try {  
  18.         Integer.parseInt(pin);  
  19.         notifyInvitationSent(pin, config.deviceAddress);  
  20.     } catch (NumberFormatException ignore) {  
  21.         // do nothing if p2pConnect did not return a pin  
  22.     }  
  23. }  

ProvisionDiscoveryState通过调用p2pConnectWithPinDisplay,然后调用WifiNative的p2pConnect向wpa_supplicant发送P2P_CONNECT命令,如果采用keyPad的连接方式,会弹出pin码的对话框,供用户在对方设备上填入pin码;如果采用PBC的连接方式,WifiNative.p2pConnect返回”OK“,Integer.parseInt抛出异常,就不会弹出对话框了。然后ProvisionDiscoveryState跳转到GroupNegotiationState:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class GroupNegotiationState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.     }  
  6.   
  7.     @Override  
  8.     public boolean processMessage(Message message) {  
  9.         if (DBG) logd(getName() + message.toString());  
  10.         switch (message.what) {  
  11.             case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:  
  12.             case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:  
  13.                 if (DBG) logd(getName() + " go success");  
  14.                 break;  
  15.             case WifiMonitor.P2P_GROUP_STARTED_EVENT:  
  16.                 mGroup = (WifiP2pGroup) message.obj;  
  17.                 if (DBG) logd(getName() + " group started");  
  18.   
  19.                 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {  
  20.                     updatePersistentNetworks(NO_RELOAD);  
  21.                     String devAddr = mGroup.getOwner().deviceAddress;  
  22.                     mGroup.setNetworkId(mGroups.getNetworkId(devAddr,  
  23.                             mGroup.getNetworkName()));  
  24.                 }  
  25.   
  26.                 if (mGroup.isGroupOwner()) {  
  27.                     if (!mAutonomousGroup) {  
  28.                         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);  
  29.                     }  
  30.                     startDhcpServer(mGroup.getInterface());  
  31.                 } else {  
  32.                     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);  
  33.                     mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext,  
  34.                             P2pStateMachine.this, mGroup.getInterface());  
  35.                     // TODO: We should use DHCP state machine PRE message like WifiStateMachine  
  36.                     mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);  
  37.                     mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP);  
  38.                     WifiP2pDevice groupOwner = mGroup.getOwner();  
  39.                     WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);  
  40.                     if (peer != null) {  
  41.                         // update group owner details with peer details found at discovery  
  42.                         groupOwner.updateSupplicantDetails(peer);  
  43.                         mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);  
  44.                         sendPeersChangedBroadcast();  
  45.                     } else {  
  46.                         logw("Unknown group owner " + groupOwner);  
  47.                     }  
  48.                 }  
  49.                 transitionTo(mGroupCreatedState);  
  50.                 break;  

开始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,这里比较重要的一点是,P2pStateMachine不会调用DhcpStateMachine的registerForPreDhcpNotification,所以不会收到CMD_PRE_DHCP_ACTION等消息。然后更新group owner的相关信息,最后跳转至GroupCreatedState就表示连接完成了。

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class GroupCreatedState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         // Once connected, peer config details are invalid  
  6.         mSavedPeerConfig.invalidate();  
  7.         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, nullnull);  
  8.   
  9.         updateThisDevice(WifiP2pDevice.CONNECTED);  
  10.   
  11.         //DHCP server has already been started if I am a group owner  
  12.         if (mGroup.isGroupOwner()) {  
  13.             setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));  
  14.         }  
  15.   
  16.         // In case of a negotiation group, connection changed is sent  
  17.         // after a client joins. For autonomous, send now  
  18.         if (mAutonomousGroup) {  
  19.             sendP2pConnectionChangedBroadcast();  
  20.         }  
  21.     }  

在DhcpStateMachine获取到IP地址以后,就会发送DhcpStateMachine.CMD_POST_DHCP_ACTION消息给P2pStateMachine,相关的处理代码如下:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case DhcpStateMachine.CMD_POST_DHCP_ACTION:  
  2.     DhcpResults dhcpResults = (DhcpResults) message.obj;  
  3.     if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS &&  
  4.             dhcpResults != null) {  
  5.         if (DBG) logd("DhcpResults: " + dhcpResults);  
  6.         setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress);  
  7.         sendP2pConnectionChangedBroadcast();  
  8.         //Turn on power save on client  
  9.         mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);  
  10.     } else {  
  11.         loge("DHCP failed");  
  12.         mWifiNative.p2pGroupRemove(mGroup.getInterface());  
  13.     }  
  14.     break;  

这里主要调用sendP2pConnectionChangedBroadcast用于广播当前连接状态的改变,WifiP2pSettings会捕获这个WIFI_P2P_CONNECTION_CHANGED_ACTION并更新UI状态为已连接
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. private void sendP2pConnectionChangedBroadcast() {  
  2.     if (DBG) logd("sending p2p connection changed broadcast");  
  3.     Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);  
  4.     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT  
  5.             | Intent.FLAG_RECEIVER_REPLACE_PENDING);  
  6.     intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));  
  7.     intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));  
  8.     intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));  
  9.     mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);  
  10.     mWifiChannel.sendMessage(WifiP2pService.P2P_CONNECTION_CHANGED,  
  11.             new NetworkInfo(mNetworkInfo));  
  12. }  

被动连接

首先来看一下三种方式的连接流程图:


当在InactiveState中,收到对方发送的P2P-PROV-DISC-PBC-REQ消息后,WifiMonitor就会给P2pStateMachine发送P2P_PROV_DISC_PBC_REQ_EVENT,来看InactiveState对这个消息的解释:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:  
  2. case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:  
  3. case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:  
  4.     //We let the supplicant handle the provision discovery response  
  5.     //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.  
  6.     //Handling provision discovery and issuing a p2p_connect before  
  7.     //group negotiation comes through causes issues  
  8.     break;  

InactiveState并不关系这些消息,而是让wpa_supplicant自行处理,等待收到GO_NEGOTIATION_REQUEST_EVENT时再来处理,再来看InactiveState如何处理GO_NEGOTIATION_REQUEST_EVENT消息:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:  
  2.     config = (WifiP2pConfig) message.obj;  
  3.     if (isConfigInvalid(config)) {  
  4.         loge("Dropping GO neg request " + config);  
  5.         break;  
  6.     }  
  7.     mSavedPeerConfig = config;  
  8.     mAutonomousGroup = false;  
  9.     mJoinExistingGroup = false;  
  10.     transitionTo(mUserAuthorizingNegotiationRequestState);  
  11.     break;  

直接跳转至UserAuthorizingNegotiationRequsetState,到UserAuthorizingNegotiationRequsetState的enter函数去分析:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class UserAuthorizingNegotiationRequestState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         notifyInvitationReceived();  
  6.     }  

notifyInvitationReceived作用是弹出对话框,供用户选择取消或者确认,如果WPS方式是keypad或者display,则还有输入pin码的输入框或者显示框。以PBC为例,当用户点击确认后,则会给自身发送PEER_CONNECTION_USER_ACCEPT消息,来看UserAuthorizingNegotiationRequsetState如何处理:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case PEER_CONNECTION_USER_ACCEPT:  
  2.     mWifiNative.p2pStopFind();  
  3.     p2pConnectWithPinDisplay(mSavedPeerConfig);  
  4.     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);  
  5.     sendPeersChangedBroadcast();  
  6.     transitionTo(mGroupNegotiationState);  
  7.    break;  

这里也是调用p2pConnectWithPinDisplay,然后调用WifiNative的p2pConnect向wpa_supplicant发送P2P_CONNECT命令,后面transition到GroupNegoTiationState,与前面主动连接的方式一样了。

主动Invite

当设备已经形成Group时,则可以邀请其他设备加入到这个Group,形成两个及两个以上P2P设备形成的Group,从前面Group形成的知识我们知道,这时P2pStateMachine处于GroupCreatedState,WifiP2pSettings会给当前State发送CONNECT的消息,来看具体处理代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiP2pManager.CONNECT:  
  2.     WifiP2pConfig config = (WifiP2pConfig) message.obj;  
  3.     if (isConfigInvalid(config)) {  
  4.         loge("Dropping connect requeset " + config);  
  5.         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);  
  6.         break;  
  7.     }  
  8.     logd("Inviting device : " + config.deviceAddress);  
  9.     mSavedPeerConfig = config;  
  10.     if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {  
  11.         mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);  
  12.         sendPeersChangedBroadcast();  
  13.         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);  
  14.     } else {  
  15.         replyToMessage(message, WifiP2pManager.CONNECT_FAILED,  
  16.                 WifiP2pManager.ERROR);  
  17.     }  
  18.     // TODO: figure out updating the status to declined when invitation is rejected  
  19.     break;  

上面的实现中主要调用WifiNative的p2pInvite来实现邀请对方加入当前的Group中,如果成功执行并向对方发送invitate request后,WifiMonitor会收到P2P-INVITATION-RESULT,然后给P2pStateMachine发送P2P_INVITATION_RESULT_EVENT消息,来看一下处理代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_INVITATION_RESULT_EVENT:  
  2.     P2pStatus status = (P2pStatus)message.obj;  
  3.     if (status == P2pStatus.SUCCESS) {  
  4.         // invocation was succeeded.  
  5.         break;  
  6.     }  
  7.     loge("Invitation result " + status);  
  8.     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {  
  9.         // target device has already removed the credential.  
  10.         // So, remove this credential accordingly.  
  11.         int netId = mGroup.getNetworkId();  
  12.         if (netId >= 0) {  
  13.             if (DBG) logd("Remove unknown client from the list");  
  14.             if (!removeClientFromList(netId,  
  15.                     mSavedPeerConfig.deviceAddress, false)) {  
  16.                 // not found the client on the list  
  17.                 loge("Already removed the client, ignore");  
  18.                 break;  
  19.             }  
  20.             // try invitation.  
  21.             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);  
  22.         }  
  23.     }  
  24.     break;  

这里主要根据P2P-INVITATION-RESULT后面带到status状态来处理persistent连接的情况,比如device A和device B前面有连接过,这时再去连接的话,应该走invitation这条路,但如果在device B上面已经把和device A连接的credential给删除了。关于persistent的连接以后再来分析。接着会收到wpa_supplicant发送的P2P_PROV_DISC_PBC_REQ或者P2P_PROV_DISC_ENTER_PIN或者P2P_PROV_DISC_SHOW_PIN的event,wifiMonitor分别会发送P2P_PROV_DISC_PBC_REQ_EVENT、P2P_PROV_DISC_ENTER_PIN_EVENT和P2P_PROV_DISC_SHOW_PIN_EVENT三个消息给P2pStateMachine,来看相关处理代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:  
  2. case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:  
  3. case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:  
  4.     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;  
  5.     mSavedPeerConfig = new WifiP2pConfig();  
  6.     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;  
  7.     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {  
  8.         mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;  
  9.     } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {  
  10.         mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;  
  11.         mSavedPeerConfig.wps.pin = provDisc.pin;  
  12.     } else {  
  13.         mSavedPeerConfig.wps.setup = WpsInfo.PBC;  
  14.     }  
  15.     transitionTo(mUserAuthorizingJoinState);  
  16.     break;  

以P2P_PROV_DISC_PBC_REQ_EVENT为例,这里主要通过provision discovery中的消息来设置mSavedPeerConfig,记录这次连接的配置信息,然后就transition到UserAuthorizingJoinState中:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class UserAuthorizingJoinState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         notifyInvitationReceived();  
  6.     }  
  7.   
  8.     @Override  
  9.     public boolean processMessage(Message message) {  
  10.         if (DBG) logd(getName() + message.toString());  
  11.         switch (message.what) {  
  12.             case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:  
  13.             case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:  
  14.             case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:  
  15.                 //Ignore more client requests  
  16.                 break;  
  17.             case PEER_CONNECTION_USER_ACCEPT:  
  18.                 //Stop discovery to avoid failure due to channel switch  
  19.                 mWifiNative.p2pStopFind();  
  20.                 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {  
  21.                     mWifiNative.startWpsPbc(mGroup.getInterface(), null);  
  22.                 } else {  
  23.                     mWifiNative.startWpsPinKeypad(mGroup.getInterface(),  
  24.                             mSavedPeerConfig.wps.pin);  
  25.                 }  
  26.                 transitionTo(mGroupCreatedState);  
  27.                 break;  
  28.             case PEER_CONNECTION_USER_REJECT:  
  29.                 if (DBG) logd("User rejected incoming request");  
  30.                 transitionTo(mGroupCreatedState);  
  31.                 break;  
  32.             default:  
  33.                 return NOT_HANDLED;  
  34.         }  
  35.         return HANDLED;  
  36.     }  

在UserAuthorizingJoinState的enter函数中,通过notifyInvitationReceived来弹出对话框给用户选择确认或者取消,以及输入pin码等。当用户点击确认后,就会发送PEER_CONNECTION_USER_ACCEPT给它自身,接看看上面代码中处理PEER_CONNECTION_USER_ACCEPT消息,主要通过调用WifiNative的startWpsPbc进行连接,然后transition到GroupCreatedState中。在GroupCreatedState会收到WPS-SUCCESS以及AP-STA-CONNECT表示连接是否成功,当WifiMonitor收到AP-STA-CONNECT后,就会给P2pStateMachine发送AP_STA_CONNECTED_EVENT,来看这一段的处理代码:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.AP_STA_CONNECTED_EVENT:  
  2.     WifiP2pDevice device = (WifiP2pDevice) message.obj;  
  3.     String deviceAddress = device.deviceAddress;  
  4.     // Clear timeout that was set when group was started.  
  5.     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);  
  6.     if (deviceAddress != null) {  
  7.         if (mPeers.get(deviceAddress) != null) {  
  8.             mGroup.addClient(mPeers.get(deviceAddress));  
  9.         } else {  
  10.             mGroup.addClient(deviceAddress);  
  11.         }  
  12.         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);  
  13.         if (DBG) logd(getName() + " ap sta connected");  
  14.         sendPeersChangedBroadcast();  
  15.     } else {  
  16.         loge("Connect on null device address, ignore");  
  17.     }  
  18.     sendP2pConnectionChangedBroadcast();  
  19.     break;  

被动Invite

当已经形成Group的设备点击连接我们设备后,就会给我们设备发送invitation request,由前面的知识我们知道,这个request会被WifiMonitor接收并转换为P2P_INVITATION_RECEIVED_EVENT发送给P2pStateMachine,由于当前设备处于InactiveState,来看这个消息的处理:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:  
  2.     WifiP2pGroup group = (WifiP2pGroup) message.obj;  
  3.     WifiP2pDevice owner = group.getOwner();  
  4.   
  5.     if (owner == null) {  
  6.         loge("Ignored invitation from null owner");  
  7.         break;  
  8.     }  
  9.   
  10.     config = new WifiP2pConfig();  
  11.     config.deviceAddress = group.getOwner().deviceAddress;  
  12.   
  13.     if (isConfigInvalid(config)) {  
  14.         loge("Dropping invitation request " + config);  
  15.         break;  
  16.     }  
  17.     mSavedPeerConfig = config;  
  18.   
  19.     if ((owner = mPeers.get(owner.deviceAddress)) != null) {  
  20.         if (owner.wpsPbcSupported()) {  
  21.             mSavedPeerConfig.wps.setup = WpsInfo.PBC;  
  22.         } else if (owner.wpsKeypadSupported()) {  
  23.             mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;  
  24.         } else if (owner.wpsDisplaySupported()) {  
  25.             mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;  
  26.         }  
  27.     }  
  28.   
  29.     mAutonomousGroup = false;  
  30.     mJoinExistingGroup = true;  
  31.     transitionTo(mUserAuthorizingInviteRequestState);  
  32.     break;  

首先通过P2P_INVITATION_RECEIVED带的group owner的mac地址构造一个配置信息,并保存到mSavedPeerConfig中,然后根据group owner所有的WpsInfo会选择一个WSC方式,优选PBC方式,接着transition到UserAuthorizingInviteRequestState中:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. class UserAuthorizingInviteRequestState extends State {  
  2.     @Override  
  3.     public void enter() {  
  4.         if (DBG) logd(getName());  
  5.         notifyInvitationReceived();  
  6.     }  
  7.   
  8.     @Override  
  9.     public boolean processMessage(Message message) {  
  10.         if (DBG) logd(getName() + message.toString());  
  11.         boolean ret = HANDLED;  
  12.         switch (message.what) {  
  13.             case PEER_CONNECTION_USER_ACCEPT:  
  14.                 mWifiNative.p2pStopFind();  
  15.                 if (!reinvokePersistentGroup(mSavedPeerConfig)) {  
  16.                     // Do negotiation when persistence fails  
  17.                     p2pConnectWithPinDisplay(mSavedPeerConfig);  
  18.                 }  
  19.                 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);  
  20.                 sendPeersChangedBroadcast();  
  21.                 transitionTo(mGroupNegotiationState);  
  22.                break;  

UserAuthorizingInviteRequestState和UserAuthorizingNegotiationRequsetState类似,首先弹出对话框给用户选择同意或者拒绝,若选择keypad或者display的方式,还需要显示pin码等。当用户点击同意后,就会给自身发送PEER_CONNECTION_USER_ACCEPT,看上面处理PEER_CONNECTION_USER_ACCEPT的代码,首先尝试用persistent的方式连接;如果失败,则调用p2pConnectWithPinDisplay,然后调用WifiNative的p2pConnect向wpa_supplicant发送P2P_CONNECT命令,这样就回到与之前主动连接一样的流程当中了。
0 0
原创粉丝点击