Android WIFI框架分析(2)

上文講到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();
        -> mCallback.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進行處理。最後就可以自由的上網了

發佈了4 篇原創文章 · 獲贊 1 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章