您的位置:首页 > 移动开发 > Android开发

Android WIFI框架分析(2)

2016-12-23 09:07 405 查看
  上文讲到WIFI的启动流程,当然接着便扫描热点(AP),然后显示扫描到的AP、配置AP(填写IP地址等信息)、连接AP、获取IP地址、最后就是想要的上网咯!
一、扫描热点(AP)

上文启动WIFI成功后:// Success!       

        setWifiEnabledState(eventualWifiState, uid);

private void setWifiEnabledState(int wifiState, int uid) {

 // Broadcast

        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);

}

当使能成功后,会广播发送WIFI_STATE_CHANGED_ACTION 这个Intent 通知外界WIFI已经成功使能了。WifiLayer 创建的时候就会向Android
注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该Intent,从而开始扫描。

WifiSetting.Java:

protected void onCreate(Bundle savedInstanceState) {

    mWifiLayer.onCreate();

}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

WifiLayer.java:

public void onCreate() {

        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);

       

        mIntentFilter = new IntentFilter();

        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);

        mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

        mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);        

    }

public void onResume() {

        mContext.registerReceiver(mReceiver, mIntentFilter);       

        if (isWifiEnabled()) {

            // Kick start the continual scan

            queueContinuousScan();

        }

    }

以上就是WifiLayer.java注册接收的部分事件。接收部分事件处理有:

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {

            final String action = intent.getAction();

            if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {

                handleNetworkStateChanged(

                        (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),

                        intent.getStringExtra(WifiManager.EXTRA_BSSID));

            } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {

                handleScanResultsAvailable();

            } ……

           else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {

                handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,

                        WifiManager.WIFI_STATE_UNKNOWN));

            }           

        }

    };

从可接受的事件看,当WIFI_STATE_CHANGED_ACTION时,对应的处理函数有:

handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,

                        WifiManager.WIFI_STATE_UNKNOWN));

private void handleWifiStateChanged(int wifiState) {

   attemptScan();

   …………

 }

public void attemptScan() {

  if (!mWifiManager.startScanActive()) {

            postAttemptScan();

        }

}

WifiManager.java:

public boolean startScanActive() {

 return mService.startScan(true);

}

-------AIDL-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

WifiService.java:

public boolean startScan(boolean forceActive) {

 …………

 return WifiNative.scanCommand(forceActive);

}

---------JNI---------------------------------------------------------------------------------------------------------------------------------------------------------------------------

android_net_wifi_wifi.cpp:

{ "scanCommand", "(Z)Z", (void*)
android_net_wifi_scanCommand },

static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)

{

 …………

 result = doBooleanCommand("SCAN", "OK");

}

static jboolean doBooleanCommand(const char *cmd, const char *expect)

{

 if (doCommand(cmd, reply, sizeof(reply)) != 0) {

        return (jboolean)JNI_FALSE;

    }

}

static int doCommand(const char *cmd, char *replybuf, int replybuflen)

{

 if (::wifi_command(cmd, replybuf, &reply_len) != 0)

        return -1;

 …………

}

-------HAL------------------------------------------------------------------------------------------------------------------------------------------------------------------------

wifi.c:

int wifi_command(const char *command, char *reply, size_t *reply_len)

{

    return wifi_send_command(ctrl_conn, command, reply, reply_len);

}

int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)

{

 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);

 …………

}
wpa_ctrl.c:

int wpa_ctrl_request()在wpa_ctrl.c中其实就是执行SCAN命令。

二、显示扫描的AP

当扫描成后,WifiMonitor 中的MonitorThread 会被执行来出来这个事件:

  void handleEvent(int event, String remainder) {

            switch (event) {   

                case SCAN_RESULTS:

                    mWifiStateTracker.notifyScanResultsAvailable();

->sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE);

    break;

}

 WifiStateTracker.java
public void handleMessage(Message msg) {              

  switch (msg.what) {

               case EVENT_SCAN_RESULTS_AVAILABLE:

                        if (ActivityManagerNative.isSystemReady()) {

                                mContext.sendBroadcast(new   Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));       

                     }

}

WifiLayer注册接收SCAN_RESULTS_AVAILABLE_ACTION这个Intent:

private BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

 else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))

       {             

             handleScanResultsAvailable();     

     }
 handleScanResultsAvailable();

       -> list = mWifiManager.getScanResults();

        -> m
4000
Callback.onAccessPointSetChanged(ap, true);

handleScanResultsAvailable()中首先会去拿到SCAN的结果(最终是往wpa_supplicant中发送SCAN_RESULT命令并读取返回值来实现的),对每一个扫描返回的AP,WifiLayer会回调WifiSetting的onAccessPointSetChanged函数,从而最终把该AP加到GUI显示列表中。

三、配置AP

当用户在 WifiSettings 界面上选择了一个AP 后,会显示配置AP 参数的一个对话框:

public boolean onPreferenceTreeClick()

          ->showAccessPointDialog(state, AccessPointDialog.MODE_INFO);

                    ->AccessPointDialog dialog   =

                                            new AccessPointDialog(this,    mWifiLayer);

                                     showDialog(dialog);

当用户在AccessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP。

四、连接AP

在AccessPointDialog.java中点击连接后会执行:

public void onClick(DialogInterface dialog, int which) {

           handleConnect();

   -> mWifiLayer.connectToNetwork(mState);

    ->  // Need WifiConfiguration for the AP

                               WifiConfiguration config = findConfiguredNetwork(state);

                                config = addConfiguration(state, 0);

                                managerEnableNetwork(state, false)

          ->mWifiManager.enableNetwork()

                                         ->mService.enalbeNetwork()

                     ->WifiNative.enableNetworkCommand() 

接下去就JNI { "enableNetworkCommand", "(IZ)Z", (void*)android_net_wifi_enableNetworkCommand},最终就是向wpa_supplicant发送连接命令
五、获取IP地址

当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行来出来这个事件:

void handleEvent(int event, String remainder) {

       switch (event) {   

              case CONNECTED:

                  handleNetworkStateChange();

                  -> mWifiStateTracker.notifyStateChange(newState, BSSID, networkId);

  ->msg.sendToTarget();

                  break;

}

WifiStateTracker.java

public void handleMessage(Message msg) {         

  switch (msg.what) {              

            case EVENT_NETWORK_STATE_CHANGED:

                       sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());      

                     }

}

WifiStateTracker中注册的对Wifi相关数据库的观察者if(changed)   则启动:

 private void configureInterface()

   ->  mDhcpTarget.sendEmptyMessage();

 private class DhcpHandler extends Handler

          handleMessage()

              ->switch (msg.what) {

                      case EVENT_DHCP_START:
                              Target.sendEmptyMessage(event);

DhcpHandler会发送EVENT_DHCP_START消息启动DHCP去获取IP地址,当DHCP拿到IP地址之后,会发送EVENT_INTERFACE_CONFIGURATION_SUCCEEDED的消息,然后WifiStateTacker中的handleMessage会处理这样的消息 

case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:

     sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());

            ->  Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);

            -> mContext.sendStickyBroadcast(intent);

这次带上完整的IP地址信息。WifiLayer中注册了此Intent的接受者,会调用handleNetworkStateChanged进行处理。最后就可以自由的上网了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: