android wifi p2p / wifi direct

版权声明:本文为博主原创文章,未经博主允许不得转载。https://blog.csdn.net/h784707460/article/details/81502574

 

一. wifi P2P协议相关

Wi-Fi Alliance(Wi-Fi联盟)推出的一项重要技术规范Wi-Fi P2P。该规范的商品名为Wi-Fi Direct,它支持多个Wi-Fi设备在没有AP的情况下相互连接。 借助P2P技术,Wi-Fi设备之间的直接相连将极大拓展Wi-Fi技术的使用场景。如智能终端设备之间的多屏共享和互动功能。

1.1 P2P架构

p2p架构中定义了两种角色,分别是:

  • P2P Group Owner:简称GO,其作用类似于Infrastructure BSS中的AP;
  • P2P Client:简称GC,其作用类似于Infrastructure BSS中的STA。

1.2 Device Discovery

Device Discovery使用Probe Request和Probe Response帧来交换设备信息。

P2P为Device Discovery定义了两个状态和两个阶段。

两个状态

  • Search State:在该状态中,P2P Device将在2.4GHz的1,6,11频段上分别发送Probe Request帧。这几个频段被称为Social Channels。
  • Listen State:在该状态下,P2P Device将随机选择在1,6,11频段中的一个频段(被选中的频段被称为Listen Channel)监听Probe Request帧并回复Probe Response帧。Listen Channel一旦选择好后,在整个P2P Discovery阶段就不能更改。

两个阶段

  • Scan Phase:扫描阶段。P2P Device会在其所支持的所有频段上发送Probe Request帧(主动扫描)。用于快速发现周围的Group。P2P Device在这一阶段中不会处理来自其他设备的Probe Request帧。(全信道扫描)
  • Find Phase:P2P Device将在Search State和Listen State之间来回切换。Search State中,P2P Device将发送Probe Request帧,而Listen State中,它将接收其他设备的Probe Request帧并回复Probe Response帧。

注:Operating Channel属性表示组建的P2P Group将在哪个频段上工作。并且其频段不限于Social Channels中指定的那三个频段。

1.3 GO Formation

GO Formation 包含两个阶段:

  • GO Negotiation:在这一阶段中,两个Device要协商好由谁来做GO。
  • Provisioning:GO和Client角色确定后,两个Device要借助WSC来交换安全配置信息。此后,Client就可以利用安全配置信息关联上GO。(Provision Discovery(PD)流程是为了确定交互双方使用的WSC方法,不属于GF流程)

GO协商包含一个三路握手过程,用于协商谁是GO以及P2P组的一些特征。 这三路握手过程主要主要交换如下一些信息:

  1.  Group Owner Intent Value
  2.  Acceptable Operating Channel the Group may use
  3.  Credentials for the P2P Group
  4.  Group Duration: Temporary or Persistent
  5.  Group support for other devices and optional capabilities

当一个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和AsyncChannel介绍

HSM(对应的类是StateMachine)和AsyncChannel是Android Java Framework中两个重要的类。目前还仅由Framework内部使用,SDK中并没有包含它们。

2.1 HSM(Hierarchical State Machine,结构化状态机)

HSM在传统状态机对所有状态都一视同仁的基础上做了一些改变,使得状态和状态之间有了层级关系。在父状态中实现generic的功能,而在子状态中实现一些特定的处理。

State中重要函数:

  • enter, SM进入某状态时将调用其EA(Entry Action);
  • exit,退出某状态时将调用其EXA(Exit Action);
  • processMessage,在HSM中,外界和HSM交互的方式就是向其sendMessage。Message由当前State的processMessage函数来处理。如果当前State成功处理此message,则返回HANDLED。否则返回NOT_HANDLED。在Message处理中,如果子状态返回NOT_HANDLED,则其父状态的processMessage将被调用。如果当前状态及祖先状态都不能处理,则HSM的unhandledMessage将被调用。 

HSM中一些重要的API:

  • addState:添加一个状态。同时还可指定父状态。
  • transitionTo:将状态机切换到某个状态。
  • obtainMessage:由于HSM内部是围绕一个Handler来工作的,所以外界只能调用HSM的obtainMessage以获取一个Message。
  • sendMessage:发送消息给HSM。HSM中的Handler会处理它。
  • start:启动状态机。
  • 停止状态机可使用quit或quitNow函数。

HSM中状态和状态之间的层级关系体现:

  • SM启动后,初始状态的EA将按派生顺序执行。即其祖先状态的EA先执行,子状态的 EA后执行。
  • 当State发生切换时,旧State的exit先执行,新State的enter后执行,并且新旧State派生树上对应的State也需要执行exit或enter函数。但公共祖先状态的EXA和EA不会执行。EA执行顺序由祖先类开始直至子孙类,而EXA执行先从子孙类开始,直到祖先类。
  • State处理Message时,如果子状态不能处理(返回NOT_HANDLED),则交给父状态去 处理。

2.2 AsyncChannel

AsyncChannel用于两个Handler之间的通信。具体的通信方式为源Handler通过sendMessage向目标Handler发送消息,而目标Handler通过replyToMessage回复源Handler处理结果。这两个Handler可位于同一个进程,也可分属两个不同的进程.

用法包含两种不同的应用模式(usage model)。

  • 简单的request/response模式(一对多的通信方式)下,Server端无须维护Client的信息,它只要处理来自Client的请求即可。通信前双方不需要显示建立连接。客户端(发送方)将请求发送给服务器(接收方),服务器则通过replayToMessage方法向客户端发送应答消息。

  • 一对一的通信方式,这种应用模式就是Server端维护Client的信息。这样,Server可以向Client发送自己的状态或者其他一些有意义的信息。

WifiService相关模块中,第二种应用模式使用得较多。

三. WifiP2pSettings和WifiP2pService介绍

WifiP2pSettings是Settings应用中负责处理P2P相关UI/UE逻辑的主要类,与之交互的则是位于SystemServer进程中的WifiP2pService。

3.1 涉及源码文件名及位置(Marshmallow - 6.0.1_r10)

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

3.2 WifiP2pSettings

加载界面元素

通过监听广播的方式来了解系统中Wi-Fi P2P相关的信息及变化情况,进行相应的处理:

  • WIFI_P2P_STATE_CHANGED_ACTION:用于通知系统中P2P功能的启用情况,如该功能是enable还是disable。
  • WIFI_P2P_PEERS_CHANGED_ACTION:系统内部将保存搜索到的其他P2P设备信息,如果这些信息有变化,则系统将发送该广播。接收者需要通过WifiP2pManager的requestPeers函数重新获取这些P2P设备的信息。
  • WIFI_P2P_CONNECTION_CHANGED_ACTION:用于通知P2P连接情况,该广播可携带WifiP2pInfo和NetworkInfo两个对象。相关信息可从这两个对象中获取。
  • WIFI_P2P_THIS_DEVICE_CHANGED_ACTION:用于通知本机P2P设备信息发生了变化。
  • WIFI_P2P_DISCOVERY_CHANGED_ACTION:用于通知P2P Device Discovery的工作状态,如启动或停止。
  • WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION:用于通知之persistent group信息发生了变化。

WifiP2pSettings将借助WifiP2pManager和系统中的WifiP2pService交互。WifiP2pSettings主要使用WifiP2pManager的几个重要函数:

  • initialize:初始化WifiP2pManager.Channel ,WifiP2pManager内部将和WifiP2pService通过AsyncChannel建立交互关系。
  • discoverPeers:触发WifiP2pService发起P2P Device扫描工作。
  • requestPeers:获取系统中保存的P2P Device信息。
  • connect:和指定P2P Device发起连接,也就是相互协商以创建或加入一个P2P网络,即一个Group。
  • requestGroupInfo:获取当前连接上的Group信息。

3.3 WifiP2pService

WifiP2pService是Android系统中P2P功能的Java层核心模块。其家族类图如下。

  • IWifiP2pManager、IWifiP2pManager.Stub和IWifiP2pManager.Stub.Proxy类均由IWifiP2pManager.aidl文件在编译时通过aidl工具转换而来。
  • WifiP2pService派生自IWifiP2pManager.Stub类,它是Binder服务端。
  • WifiP2pManager是WifiP2pService的客户端。它通过成员变量mService和WifiSP2pervice进行Binder交互。

P2pStateMachine是WifiP2pService定义的内部类,P2pStateMachine是WifiP2pService的核心。P2pStateMachine中定义的各个状态及层级关系如图:

3.4 WifiP2pService工作流程

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处理。

四. P2P流程

相关文件简介: 

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++代码。

4.1 P2P扫描流程 

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));
    } 

4.2 P2P连接流程

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相关. 发现一些流程已经不是很清楚了, 翻出来两年前自己整理的资料, 发现远超现在的水平.

逆水行舟, 不进则退.

猜你喜欢

转载自blog.csdn.net/h784707460/article/details/81502574