wifi direct/p2p流程分析 基于android 5.1

 Wifi Direct流程分析

      Android平台中,P2P操作比较简单,用户只需要执行如下三个步骤:

      1)进入WifiP2pSettings界面

      2)搜索周围的P2P设备。搜索到的设备将显示在WifiP2pSettings

      3)用户选择其中的某个设备发起连接或者接受某设备发起的连接

     下面将根据这些步骤来分析WifiP2pSettingsWifiP2pService的流程,主要包括:P2P的使能、P2P的扫描、P2P的配对以及P2P的连接。


Wifi Direct环境的建立

WifiP2pSettings创建

      首先从WifiP2pSettings中的onActivityCreated()函数分析,代码如下:

public void onActivityCreated(Bundle savedInstanceState) {
        addPreferencesFromResource(R.xml.wifi_p2p_settings);

        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);
        final Activity activity = getActivity();
        mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        if (mWifiP2pManager != null) {
           mChannel = mWifiP2pManager.initialize(activity, getActivity().getMainLooper(), null);
            if (mChannel == null) {
                //Failure to set up connection
                Log.e(TAG, "Failed to set up connection with wifi p2p service");
                mWifiP2pManager = null;
            }
             ..............
        mRenameListener = new OnClickListener() {..............}
             ...............
        uper.onActivityCreated(savedInstanceState);
       }


 
  

      onActivityCreated()函数主要的做了三件事:

      ①将P2P特有的Action添加到过滤器中。

      ②构造和初始化WifiP2pManager对象,并建立和WifiService联系。

      ③创建UI中按钮对应的OnClickListener

      WifiP2pSettings主要通过通过监听广播方式了解系统中Wifi P2p信息以及变化情况,下面简要介绍这几个属于P2P特有的广播:

      1)WIFI_P2P_STATE_CHANGED_ACTION-用于通知P2P功能的请用情况。

      2)WIFI_P2P_PEERS_CHANGED_ACTION-系统内部保存搜索到其他P2P设备信息的变化情况

      3)WIFI_P2P_CONNECTION_CHANGED_ACTION-用于通知P2P的连接情况

      4)WIFI_P2P_THIS_DEVICE_CHANGED_ACTION-用于通知本机设备信息变化情况

      5)WIFI_P2P_DISCOVERY_CHANGED_ACTION-用于通知P2P Discovery的工作状态

      6)WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION-用于通知persistent group信息的变化情况。

WifiP2pService的启动

     首先WifiP2pServicenew了一个WifiP2pServiceimpl对象,下面主要来看看WifiP2pServiceimpl的构造函数:

public WifiP2pServiceImpl(Context context) {
    mContext = context;
    //STOPSHIP: get this from native side
mInterface = "p2p0";
..........
mP2pStateMachine = new P2pStateMachine(
    TAG, wifiP2pThread.getLooper(), mP2pSupported);
 mP2pStateMachine.start();
}

      WifiP2pServiceimpl构造函数主要是创建一个NetworkInfo,然后调用getPackageManager判断本机设备是否支持P2P功能。通过创建一个P2pStateMachine并启动StateMachine

     下面进入P2pStateMachine函数分析

P2pStateMachine(String name, Looper looper, boolean p2pSupported) {
    super(name, looper);
    
addState(mDefaultState);
addState(mP2pNotSupportedState, mDefaultState);
   ..............
 if (p2pSupported) {
                setInitialState(mP2pDisabledState);
            } else {
                setInitialState(mP2pNotSupportedState);
            }
            setLogRecSize(50);
            setLogOnlyTransitions(true);

      分析构造函数,看出P2pStateMachine的各个State关系如下图:wifi direct/p2p流程分析 基于android 5.1_第1张图片

     P2pStateMachineWifiP2pService的核心,P2pStateMachine的初始状态是P2pDisableState


Wifi Direct模块的初始化

Wifi Direct的主要数据结构

     下面来分析Wifi Direct的几个主要的数据结构,首先看的是p2p_configp2p_data,它们的成员如下图5所示:

wifi direct/p2p流程分析 基于android 5.1_第2张图片

      p2p_config定义了25个回调函数,这些回调函数定义了P2P模块与外界交互的接口,均指向p2p_supplicant.c.

p2p_data指向一个p2p_config对象。

     下面来看下其他几个重要的数据结构。如下图6

wifi direct/p2p流程分析 基于android 5.1_第3张图片

        p2p_device代表一个p2p设备。其中设备名等信息存放在类型为p2p_peer_info的对象中

         p2p_group代表一个p2p group的信息,其内包含一个p2p_group_config对象和一个p2p_group_member链表。p2p_group_config代表group的配置信息,p2p_group_member链表代表的是p2p client信息。


Wifi DirectWPAS中的初始化流程

       Wifi DirectWPAS中的初始化工作主要从wpas_p2p_init()函数开始,下面看看wpas_p2p_init()代码:

int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
{
struct p2p_config p2p;
int i;
if (wpa_s->conf->p2p_disabled)
   if (wpa_s->conf->p2p_disabled)
..........
os_memset(&p2p, 0, sizeof(p2p));
p2p.cb_ctx = wpa_s;
p2p.debug_print = wpas_p2p_debug_print;
p2p.p2p_scan = wpas_p2p_scan;
p2p.send_action = wpas_send_action;
..........
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
p2p.dev_name = wpa_s->conf->device_name;
p2p.manufacturer = wpa_s->conf->manufacturer;
p2p.model_name = wpa_s->conf->model_name;
p2p.model_number = wpa_s->conf->model_number;
p2p.serial_number = wpa_s->conf->serial_number;
if (wpa_s->wps) {
		os_memcpy(p2p.uuid, wpa_s->wps->uuid, 16);
		p2p.config_methods = wpa_s->wps->config_methods;
	}
.........

	global->p2p = p2p_init(&p2p);
	if (global->p2p == NULL)
		return -1;
	global->p2p_init_wpa_s = wpa_s;
	for (i = 0; i < MAX_WPS_VENDOR_EXT; i++) {
		if (wpa_s->conf->wps_vendor_ext[i] == NULL)
			continue;
		p2p_add_wps_vendor_extension(
			global->p2p, wpa_s->conf->wps_vendor_ext[i]);
	}
        ...........
}

wpas_p2p_init()函数主要完成两件工作:

1)构造一个p2p_config对象并对p2p_config对象对象初始化,然后根据p2p_supplicant.conf文件的信息设置其中的内容。同时,为p2p模块设置回调函数。

2)调用p2p_init()函数初始化p2p模块

p2p_init()函数中主要构造了一个p2p_data结构体并设置相应的参数,p2p_init()函数代码比较简单感兴趣可以取分析。

 

3、注册Action

        本机设备和对端设备信息交互时候,Action帧扮演重要的角色。在P2P Device DiscovenryProvision Discovery流程以及GO Negotiation流程都涉及到Action帧的处理流程。因此,这边在初始化阶段对Action帧进行注册。

tatic int wpa_driver_nl80211_set_mode_impl(
	struct i802_bss *bss,
	enum nl80211_iftype nlmode,
	struct hostapd_freq_params *desired_freq_params)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
    int i;
int was_ap = is_ap_interface(drv->nlmode);
int res;
int mode_switch_res;
mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
mode_switch_res = 0;
......
if (is_ap_interface(nlmode)) {
		nl80211_mgmt_unsubscribe(bss, "start AP");
		/* Setup additional AP mode functionality if needed */
		if (nl80211_setup_ap(bss))
			return -1;
	} else if (was_ap) {
		/* Remove additional AP mode functionality */
		nl80211_teardown_ap(bss);
	} else {
		nl80211_mgmt_unsubscribe(bss, "mode change");
	}
	if (!bss->in_deinit && !is_ap_interface(nlmode) &&
	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
			   "frame processing - ignore for now");
	return 0;
}

        wpa_driver_nl80211_set_mode_impl()函数中主要的是调用了nl80211_mgmt_subscribe_non_ap()函数,nl80211_mgmt_subscribe_non_ap()将注册对Action帧的监听时间,其作用就是当设备收到Action帧后,Wifi driver将发送相对应的netlink消息给WPAS.

nl80211_mgmt_subscribe_non_ap()注册了两种类型的帧监听事件。

         1P2P Public Action帧监听事件:根据P2P规范,目前适用的军事802.11 P2P Public Action帧(Category的值为0x04)。目前GONP2P InvitationProvision Discovery以及Device Discoverability都是适用P2P Public Action帧。

         2P2P Action帧监听事件:这种类型的帧属于802.11Action帧的一种(Category的值为0x7F),目前Notice of AbsenceP2P PresenceGO Discoverability适用P2P Action帧。

 

3.2.Wifi Direct的使能

       P2pStateMachine虽然属于WifiP2pService,但它也受WifiStateMachine影响。平台支持P2PWifiStateMachine中将创建一个名为mWifiP2pChannelAsyncChannelde 的对象用于向P2pStateMachine发消息。

如果用户打开WiFI功能,P2pStateMachine就会收到来自WifiStateMachine发送的消息CMD_ ENABLE_P2P

CMD_ ENABLE_P2P消息的处理过程主要在wifip2pserviceinpl.javaP2pDisabledState函数中完成

class P2pDisabledState extends State {
 public boolean processMessage(Message message) {
     if (DBG) logd(getName() + message.toString());
     switch (message.what) {
     case WifiStateMachine.CMD_ENABLE_P2P:
         try {
             mNwService.setInterfaceUp(mInterface);
            } catch (RemoteException re) {
        ...............
                    }
                    mWifiMonitor.startMonitoring();
                    transitionTo(mP2pEnablingState);
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }
    }

接收到CMD_ ENABLE_P2P消息后,P2pStateMachine主要做了两件工作:

1)创建一个WifiMonitor用于接收来自wpa_supplicant的消息

2)同时将状态机转入到P2pEnablingState状态

WifiMonitor连接连接wpa_supplicant之后,WifiMonitor会发送一个SUP_CONNECT_EVENT

消息给P2pStateMachine,该消息由P2pEnablingState处理。

class P2pEnablingState extends State {
 public boolean processMessage(Message message) {
     if (DBG) logd(getName() + message.toString());
     switch (message.what) {
     case WifiMonitor.SUP_CONNECTION_EVENT:
         if (DBG) logd("P2p socket connection successful");
         transitionTo(mInactiveState);
         break;
     case WifiMonitor.SUP_DISCONNECTION_EVENT:
         loge("P2p socket connection failed");
         transitionTo(mP2pDisabledState);
         break;
         .......}
            return HANDLED;
        }
    }

         P2pEnablingState这时会跳转到InactiveState中,由前面P2pStateMachineState关系图我们可以知道,P2pEnabledStateInactiveState状态,我们先到P2pEnabledStateenter函数去分析:

class P2pEnabledState extends State {
 @Override
  public void enter() {
  if (DBG) logd(getName());
     sendP2pStateChangedBroadcast(true);
     mNetworkInfo.setIsAvailable(true);
     sendP2pConnectionChangedBroadcast();
     initializeP2pSettings();
   }

P2pEnabledState()函数主要工作如下:

1)通过sendP2pStateChangedBroadcast()发送WIFI_P2P_STATE_CHANGED_ACTION广播,它将携带WifiP2pInfoNetworkInfo信息,同时还将通过sendP2pConnectionChangedBroadcast()函数向WifiStateMachine发送WIFI_P2P_CONNECTION_CHANGED_ACTION广播。

调用函数initializeP2pSettings()初始化P2P的一些设,包括deviceNameDeviceTypeConfigMethods,并且获取以前persistent的相关device信息


3.3.Wifi Direct的扫描

           P2P的扫描还是从WifiP2psettings开始,当用户单击“SEARCH”按钮搜索P2P设备。该按钮对应的函数是WifiP2pSettingsstartSearch()函数。

           startSearch()函数调用WifiManagerdiscoverPeers搜索周围的P2P设备。discoverPeers()函数主要的工作是发布DISCOVER_PEERS消息,由WifiP2pServiceP2pEnabledState函数处理。

          下面来看下WifiP2pServicediscoverPeers处理流程。

class P2pEnabledState extends State {
           ..............
     public boolean processMessage(Message message) {
            if (DBG) logd(getName() + message.toString());
            switch (message.what) {
                  ....................
            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)) {
                        replyToMessage(
                         message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
                        sendP2pDiscoveryChangedBroadcast(true);
                    } else {
                        replyToMessage(
                         message, WifiP2pManager.DISCOVER_PEERS_FAILED,
                                WifiP2pManager.ERROR);
                    }
                    break;
                     ...........
               }
}

P2pEnabledState()收到DISCOVER_PEERS主要做了三件事:

1通过clearSupplicantServiceRequest()取消Service Discovery请求。

2调用WifiNativep2pFind函数wpa_supplicant发送P2P_FIND命令。

 3)通过sendP2pDiscoveryChangedBroadcast()函数发送 

WIFI_P2P_DISCOVERY_CHANGE_ACTION广播通知P2P Device Discovery已经启动。

          其中,wpa_supplicant收到P2P_FIND命令开始搜索周边的P2P设备,如果找到就会向WifiMonitor发送P2P-DEVICE-FOUND这样的EVENT这个event会带有对方设备的信息,包括MAC地址、device type、设备名字以及config methodsWifiMonitor收到这样的event后,会将P2P-DEVICE-FOUND后面的data数据封装成为一个WifiP2pDevice对象,然后发送P2P_DEVICE_FOUND_EVENT消息给WIfiStateMachine处理。

          下面来看下WifiP2pServiceP2P_DEVICE_FOUND_EVENT处理流程。

class P2pEnabledState extends State {
           ..............
     public boolean processMessage(Message message) {
            if (DBG) logd(getName() + message.toString());
            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();
                    break;
                  }.................
}

P2pEnabledState()收到P2P_DEVICE_FOUND_EVENT,在构造函数中主要做了两件事:

①通过WPAS反馈的信息构建一个WifiP2pDevice对象

②发送WIFI_P2P_PEERS_CHANGED_ACTION广播

下面来看看WifiP2pSetting收到WIFI_P2P_PEERS_CHANGED_ACTION广播以及

WIFI_P2P_DISCOVERY_CHANGE_ACTION广播后的处理过程。

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            ............
            }else if
                 WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action))  
                {
                        mPeers = (WifiP2pDeviceList) intent.getParcelableExtra(
                                  WifiP2pManager.EXTRA_P2P_DEVICE_LIST);
                        handlePeersChanged();
             }............
             else if(
            WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action))    
             {
                    ...............
                    updateSearchMenu(true);
                    .. ........
                }
}

            WifiP2pSetting收到WIFI_P2P_PEERS_CHANGED_ACTION广播后,通过WifiManagerhandlepeerschanged()函数获取P2P Device信息。收到WIFI_P2P_DISCOVERY_CHANGED_ACTION调用updateSearchMenu()函数显示所有的设备。至此,P2P扫描的全部过程已经完成。P2P扫描的时序图如图3

wifi direct/p2p流程分析 基于android 5.1_第4张图片

            由前面可知,P2pStateMachine将通过发送P2P_FIND命令给WPAS触发P2P Device Discovery流程。下面来看下P2P Device Discovery扫描过程,如下图4

wifi direct/p2p流程分析 基于android 5.1_第5张图片

P2P Device Discovery扫描过程主要做了三件工作:

1)接受来之P2pStateMachine的命令,设置搜索方式。

2)调用wpas_p2p_scan()函数设置SSIDProbe Request帧中的WSC IE信息、P2P IE以及其他扫描参数。

3)调用wpa_driver_nl80211_scan()函数开始扫描以及设置P2P扫描结果处理指针函数主要调用wpas_p2p_scan_res_handle()函数。

其中,搜索方式主要有三种:

P2P_FIND_ONLY_WITH_FULL:默认设置。表示先扫描所有频段,然后再扫描social channels.

P2P_FIND_ONLY_SOCIAL:只扫描social channels

    P2P_FIND_PROGRESSIVE:P2P_FIND_ONLY_WITH_FULL扫描过程相类似,只不过Search

State阶段将逐个扫描所有的频段。

对扫描结果的处理主要从wpas_p2p_scan_res_handle()开始。数据结构wpa_scan_results用于存储扫描结果,如图5为扫描结果的时序图:

wifi direct/p2p流程分析 基于android 5.1_第6张图片

wpas_p2p_scan_res_handler()函数中主要存在两个关键函数p2p_scan_res_handler()和p2p_scan_res_handled()。

每一个存储在wpa_scan_results结构体中的扫描结果,都会调用p2p_scan_res_handler()进行处理。p2p_scan_res_handler()函数主要的工作有两方面:

1)p2p_add_device()函数构造一个p2p Device对象加入到devices链表并获取对端设备的P2P DEVICE信息。

2)设置一个dev_found指针指向wpas_dev_found()函数,wpas_dev_found()将向WifiMonitor发送消息P2P DEVICE FOUND告知上层对端设备找到。

处理完扫描结果将调用第二个关键函数p2p_scan_res_handled()进入listen state状态。这边需要注意的是:

1)p2p_build_probe_resp_ies()函数为wifi driver设置P2P IE消息,如果wifi driver自己处理Probe Request帧,则wifi driver将把此处设置的P2P IE信息填写到Probe Response帧中。

2) wpa_drv_set_ap_wps_ie()要求wifi driver收到Probe Request帧后,发送EVENT_RX_PROBE_REQWPAS

3)wpa_drv_remain_on_channel()函数要求wifi driver在指定的频段工作一段时间,若切换到某一频段,wifi driver会发送EVENT_REMAIN_ON_CHANNAL消息给WPAS.

 

3.4.Wifi Direct的连接

3.4.1Wifi Direct的连接

               Wifi P2P连接主要分为:主动连接 、被动连接、主动invite以及被动invite,本文主要分析主动连接。

Wifi P2P扫描完成后,用户可以在界面中选择某个P2P设备并与之连接,Wifi P2P连接也是有WifiP2pSettings.java开始。先来看看WifiP2pSettingsonPreferenceTreeClick函数:

public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
        if (preference instanceof WifiP2pPeer) {
            mSelectedWifiPeer = (WifiP2pPeer) preference;
            if (mSelectedWifiPeer.device.status == WifiP2pDevice.CONNECTED) {
                showDialog(DIALOG_DISCONNECT);
            } else if (mSelectedWifiPeer.device.status == WifiP2pDevice.INVITED) {
                showDialog(DIALOG_CANCEL_CONNECT);
            } else {
                WifiP2pConfig config = new WifiP2pConfig();
                config.deviceAddress = mSelectedWifiPeer.device.deviceAddress;

                int forceWps = SystemProperties.getInt("wifidirect.wps", -1);

                if (forceWps != -1) {
                    config.wps.setup = forceWps;
                } else {
                    if (mSelectedWifiPeer.device.wpsPbcSupported()) {
                        config.wps.setup = WpsInfo.PBC;
                    } else if (mSelectedWifiPeer.device.wpsKeypadSupported()) {
                        config.wps.setup = WpsInfo.KEYPAD;
                    } else {
                        config.wps.setup = WpsInfo.DISPLAY;
                    }
                }

                mWifiP2pManager.connect(mChannel, config,
                        new WifiP2pManager.ActionListener() {...................}
                    }..............
            }
     }

onPreferenceTreeClick()主要做了三件事:

①获取用户指定的WifiP2pPeer项。

②获取对端设备的WSC的配置方法。

③构造WifiP2pConfig对象存储对端设备信息并调用WifiP2pManagerconnect函数向该对端设备发起连接。

connect函数的工作主要是通过ChannelAsyncChannelP2pStatuesMachine发送CONNECT消息。

下面来看下CONNECT消息的处理流程。

class InactiveState extends State {
           ..............
     public boolean processMessage(Message message) {
           
            if (DBG) logd(getName() + message.toString());
            switch (message.what) {
                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)) {
                        transitionTo(mGroupNegotiationState);
                    } else {
                        transitionTo(mProvisionDiscoveryState);
                    }
                    ...................
               }.................
          }

                  这里分为persistent的连接方式和非persistent的连接,对于persistent连接,如果第一次连接成功wpa_supplicant会记录连接的记录,包括credentialGO MAC地址、ssid等信息。采用非persistent的连接(即negotiate方式)则跳转到ProvisionDiscoveryState函数,调用WifiNativep2pProvisionDiscovery向对端设备发送Provision discovery封包。对端设备处理Provision discovery封包后就会回复provision response,经wpa_supplicant处理WifiMonitor会收到P2P-PROV-DISC-PBC-RESP(WPS方式为PBC方式时), WifiMonitor就会向P2pStateMachine发送P2P_PROV_DISC_PBC_RSP_EVENT

下面来看看P2P_PROV_DISC_PBC_RSP_EVENT消息的处理过程,主要做两件事

①调用p2pConnectWithPinDisplay函数插法WPAS发送GON Request(调用WifinativeP2pconnect函数有兴趣可以看看)

②跳转到GroupNegotiationState,开始Group negotiate

class ProvisionDiscoveryState extends State {
           ..............
     public boolean processMessage(Message message) {
           ..............
           switch (message.what) {
                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);
                    }
            ...................
          }

下面来看下Group negotiate过程:

class GroupNegotiationState extends State {
           ..............
     public boolean processMessage(Message message) {
           ..............
           switch (message.what) {               
                case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
                case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
                    if (DBG) logd(getName() + " go success");
                    break;
                case WifiMonitor.P2P_GROUP_STARTED_EVENT:
                    mGroup = (WifiP2pGroup) message.obj;
                    if (DBG) logd(getName() + " group started"); 
                   if (mGroup.getNetworkId()=WifiP2pGroup.PERSISTENT_NET_ID)  {
                    updatePersistentNetworks(NO_RELOAD);
                    String devAddr = mGroup.getOwner().deviceAddress;
                    mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
                    mGroup.getNetworkName()));
                   }
                   if (mGroup.isGroupOwner()) {
                     if (!mAutonomousGroup) {
                         mWifiNative.setP2pGroupIdle(
                         mGroup.getInterface(), GROUP_IDLE_TIME_S); 
                         }
                        startDhcpServer(mGroup.getInterface());
                     } else {.............}
                    transitionTo(mGroupCreatedState);
                              }
          }

             开始group negotiate后,wpa_supplicant会发多个eventWifiMonitorWifiMonitor处理后也会发送多个event消息给P2pStateMachine。其中比较重要的是P2P_GROUP_STARTED_EVENT

GroupNegotiationState()接收到P2P_GROUP_STARTED_EVENT主要做了四件事:

①更新和设置mgroup的信息。

②调用DHCP为两端设备分配IP地址。

③向wifiP2pSettings发送广播。

④更新Group owner信息,跳转到GroupCreatedState连接完成。

GroupCreatedState函数主要调用sendP2pConnectionChangedBroadcast()广播当前连接状态的改变,WifiP2pSettings会捕获这个WIFI_P2P_CONNECTION_CHANGED_ACTION这个消息并且更新UI为已连接状态。GroupCreatedState代码比较简单,感兴趣可以自行分析,到此P2P的主动连接已经结束。

P2P主动连接的时序图如图6

wifi direct/p2p流程分析 基于android 5.1_第7张图片


3.4.2Wifi DirectProvision Discovery流程

                  P2P规范定义Provision Discovery流程,为了是确定两个P2P Device交互双方适用的WSC方法,只有在双方适用相同的WSC配置方法才能建立P2P Group

前文分析知道,当P2pStateMachineProvisionDiscoveryState发送P2P_PROV_DISC命令给WPAS时便启动了Provision Discovery流程。

Provision Discovery流程可以分为三个步骤:PD Request帧的发送流程(时序图19)、Action帧的接收流程(时序图1019)以及PD Response帧的处理流程。Provision Discovery流程时序图如下图7所示:


wifi direct/p2p流程分析 基于android 5.1_第8张图片

          PD Request帧最终通过p2p_send_action()函数发送出去,p2p_send_action()将涉及off channel发送以及处理对应的netlink消息的过程。

           PD Response帧属于Public Action帧的一种,PD Response帧主要有两种帧:对端设备发来的PD Response帧以及本机设备发送的管理帧TX Report,详细请分析process_bss_event()函数。无论是代表由本机发送的管理帧TX Report帧(NL80211_CMD_FRME_TX_STATUS)还是代表本机接收到的对端神杯发来的管理时间的帧(NL80211_CMD_FRME)最终都会调用mlme_event()函数。

PD Response帧处理流程主要做的工作:

1)解析PD Response帧,判断PD Response帧返回的WSC方法是否与所要求的WSC方法一致。

2)调用wpas_prov_disc_resp()发消息给客户端。对于前面提到的WSC PBC方式而言,wpas将发送P2P_EVENT_PROV_DISC_PBC_RESP消息给客户端。

 

3.4.3Wifi DirectGO Negotiation流程

               由3.3.1节分析知道P2pStateMachine收到P2P_PROV_DISC_PBC_RSP_EVENT消息后,将会通过ProvisionDiscoveryState中调用p2pConnectWithPinDisplay()函数,该函数内部将发送命令P2P_CONNECTWPAS开始GO Negotiation流程。

GO Negotiation流程主要有四个过程:P2P_CONNECT处理流程、GON Request帧发送流程、GON Request帧处理流程以及EVENT_TX_STATUS处理流程。

8P2P_CONNECT处理和GON Request帧的发送流程。

wifi direct/p2p流程分析 基于android 5.1_第9张图片

              对端设备设备根据接收到的GON Request帧回复GON Response帧,由前文分析知道GON Request帧将在p2p_process_go_neg_resp()函数负责处理。这段代码比较复杂暂且不进行分析,如果感兴趣自行分析。

              当GON Confirmation帧发送出去后,wifi driver将向WPAS发送一个NL80211_CMD_FRAME _TX_STATUS,该消息直接导致driver wrapper发送EVENT_TX_STATUS消息给WPAS。图9EVENT_TX_STATUS消息的处理流程:

wifi direct/p2p流程分析 基于android 5.1_第10张图片

                      当Group Negotiation完成后,WPAS将创建一个wpa_supplicant对象,它将用于管理和操作专门用于P2P Groupvirtual interface(GON Request帧发送过程创建)。一个interface对应一个wpa _supplicant对象,如果wpa_supplicant对象为GO角色,其MAC地址为P2P interface address;如果wpa_supplicant对象用于非P2P Group操作,其MAC地址为P2P Device address.


你可能感兴趣的:(嵌入式-wifi实践)