Wifi模块解析和启动流程

来源:互联网 发布:app模型制作软件 编辑:程序博客网 时间:2024/06/11 04:33
http://blog.csdn.net/ylyuanlu/article/details/7711433

模块解析和启动流程

WIFI整体框架如图所示:

首先,用户程序使用WifiManager类来管理Wifi模块,它能够获得Wifi模块的状态,配置和控制Wifi模块,而所有这些操作都要依赖 Wifiservice类来实现。

 WifiService和WifiMonitor类是Wifi框架的核心,如图所示。下面先来看看WifiService是什么时候,怎么被创建和初始化 的。

 在systemServer启动之后,它会创建一个 ConnectivityServer对象,这个对象的构造函数会创建一个WifiService的实例,代码如下所示:

 

framework/base/services/java/com/android/server/ConnectivityService.java

{

……

case ConnectivityManager.TYPE_WIFI:

               if(DBG) Slog.v(TAG, "Starting Wifi Service.");

               WifiStateTrackerwst = new WifiStateTracker(context,mHandler);                            //创建WifiStateTracker实例

               WifiService wifiService = newWifiService(context,wst);//创建WifiService实例

               ServiceManager.addService(Context.WIFI_SERVICE,wifiService);           //向服务管理系统添加Wifi服务

               wifiService.startWifi();    //启动Wifi

               mNetTrackers[ConnectivityManager.TYPE_WIFI]= wst;

               wst.startMonitoring(); //启动WifiMonitor中的WifiThread线程

……

}

       WifiService的主要工作:WifiMonitor和Wpa_supplicant的启动和关闭,向Wpa_supplicant发送命令。

       WifiMonitor的主要工作:阻塞监听并接收来自Wpa_supplicant的消息,然后发送给WifiStateTracker。

      上面两个线程通过AF_UNIX套接字和Wpa_supplicant通信,在通信过程中有两种连接方式:控制连接和监听连接。它们创建代码如下:

ctrl_conn =wpa_ctrl_open(ifname);

.. .. ..

 monitor_conn = wpa_ctrl_open(ifname);

1.2      Wifi启动流程

       (1)使能Wifi

      要想使用Wifi模块,必须首先使能Wifi,当你第一次按下Wifi使能按钮时,WirelessSettings会实例化一个WifiEnabler 对象,实例化代码如下:

packages/apps/settings/src/com/android/settings/WirelessSettings.java

protected void onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

……

             CheckBoxPreferencewifi = (CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI);

             mWifiEnabler=new WifiEnabler(this, wifi);

……

}

       WifiEnabler类的定义大致如下,它实现了一个监听接口,当WifiEnabler对象被初始化后,它监听到你按键的动作,会调用响应函数 onPreferenceChange(),这个函数会调用WifiManager的setWifiEnabled()函数。

public class WifiEnabler implementsPreference.OnPreferenceChangeListener{

……

public boolean onPreferenceChange(Preference preference,Objectvalue) {

        booleanenable = (Boolean)value;

……

if (mWifiManager.setWifiEnabled(enable)){

               mCheckBox.setEnabled(false);

……

}

……

}

       我们都知道Wifimanager只是个服务代理,所以它会调用WifiService的setWifiEnabled()函数,而这个函数会调用 sendEnableMessage()函数,了解android消息处理机制的都知道,这个函数最终会给自己发送一个 MESSAGE_ENABLE_WIFI的消息,被WifiService里面定义的handlermessage()函数处理,会调用 setWifiEnabledBlocking()函数。下面是调用流程:

mWifiEnabler.onpreferencechange()=>mWifiManage.setWifienabled()=>mWifiService.setWifiEnabled()=>mWifiService.sendEnableMessage()=>mWifiService.handleMessage()=>mWifiService.setWifiEnabledBlocking().

在 setWifiEnabledBlocking()函数中主要做如下工作:加载Wifi驱动,启动wpa_supplicant,注册广播接收器,启动 WifiThread监听线程。代码如下:

……

if (enable) {

           if(!mWifiStateTracker.loadDriver()) {

               Slog.e(TAG,"Failed toload Wi-Fi driver.");

               setWifiEnabledState(WIFI_STATE_UNKNOWN,uid);

               return false;

           }

           if(!mWifiStateTracker.startSupplicant()) {

               mWifiStateTracker.unloadDriver();

               Slog.e(TAG, "Failed tostart supplicant daemon.");

               setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

               return false;

           }

 

           registerForBroadcasts();

           mWifiStateTracker.startEventLoop();

……

 至此,Wifi使能结束,自动进入扫描阶段。

(2) 扫描AP

      当驱动加载成功后,如果配置文件的AP_SCAN = 1,扫描会自动开始,WifiMonitor将会从supplicant收到一个消息EVENT_DRIVER_STATE_CHANGED,调用 handleDriverEvent(),然后调用mWifiStateTracker.notifyDriverStarted(),该函数向消息队列 添加EVENT_DRIVER_STATE_CHANGED,handlermessage()函数处理消息时调用scan()函数,并通过 WifiNative将扫描命令发送到wpa_supplicant。

Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

private void handleDriverEvent(Stringstate) {

           if(state == null) {

               return;

           }

           if(state.equals("STOPPED")) {

               mWifiStateTracker.notifyDriverStopped();

           }else if (state.equals("STARTED")) {

               mWifiStateTracker.notifyDriverStarted();

           }else if (state.equals("HANGED")) {

               mWifiStateTracker.notifyDriverHung();

           }

       }

Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

case EVENT_DRIVER_STATE_CHANGED:

        

               switch(msg.arg1) {

               caseDRIVER_STARTED:

                   /**

                    *Set the number of allowed radio channels according

                    *to the system setting, since it gets reset by the

                    *driver upon changing to the STARTED state.

                    */

                   setNumAllowedChannels();

                   synchronized(this) {

                       if(mRunState == RUN_STATE_STARTING) {

                           mRunState= RUN_STATE_RUNNING;

                           if(!mIsScanOnly) {

                               reconnectCommand();

                           }else {

                               // In somesituations, supplicant needs to be kickstarted to

                               // start thebackground scanning

                               scan(true);

                           }

                       }

                   }

                   break;             

上面是启动Wifi 时,自动进行的AP的扫描,用户当然也可以手动扫描AP,这部分实现在WifiService里面,WifiService通过startScan()接 口函数发送扫描命令到supplicant。

Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

public boolean startScan(booleanforceActive) {

       enforceChangePermission();

 

       switch(mWifiStateTracker.getSupplicantState()) {

           caseDISCONNECTED:

           caseINACTIVE:

           caseSCANNING:

           caseDORMANT:

               break;

           default:

               mWifiStateTracker.setScanResultHandling(

                       WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);

               break;

       }

       return mWifiStateTracker.scan(forceActive);

    }

       然后下面的流程同上面的自动扫描,我们来分析一下手动扫描从哪里开始的。我们应该知道手动扫描是通过菜单键的扫描键来响应的,而响应该动作的应该是 WifiSettings类中Scanner类的handlerMessage()函数,它调用WifiManager的 startScanActive(),这才调用WifiService的startScan()。

packages/apps/Settings/src/com/android/settings/wifiwifisettings.java

public boolean onCreateOptionsMenu(Menu menu) {

       menu.add(Menu.NONE,MENU_ID_SCAN, 0, R.string.wifi_menu_scan)

               .setIcon(R.drawable.ic_menu_scan_network);

       menu.add(Menu.NONE,MENU_ID_ADVANCED, 0, R.string.wifi_menu_advanced)

               .setIcon(android.R.drawable.ic_menu_manage);

       returnsuper.onCreateOptionsMenu(menu);

    }

       当按下菜单键时,WifiSettings就会调用这个函数绘制菜单。如果选择扫描按钮,WifiSettings会调用 onOptionsItemSelected()。

packages/apps/Settings/src/com/android/settings/wifiwifisettings.java

public booleanonOptionsItemSelected(MenuItem item) {

       switch (item.getItemId()){

           caseMENU_ID_SCAN:

               if(mWifiManager.isWifiEnabled()) {

                   mScanner.resume();

               }

               return true;

           caseMENU_ID_ADVANCED:

               startActivity(new Intent(this,AdvancedSettings.class));

               return true;

       }

       returnsuper.onOptionsItemSelected(item);

}

 

private class Scanner extends Handler {

       private int mRetry = 0;

 

       void resume() {

           if (!hasMessages(0)) {

               sendEmptyMessage(0);

           }

       }

 

       void pause() {

           mRetry= 0;

           mAccessPoints.setProgress(false);

           removeMessages(0);

       }

 

       @Override

       public voidhandleMessage(Message message) {

           if(mWifiManager.startScanActive()){

               mRetry = 0;

           }else if (++mRetry >= 3) {

               mRetry = 0;

               Toast.makeText(WifiSettings.this,R.string.wifi_fail_to_scan,

                       Toast.LENGTH_LONG).show();

               return;

           }

           mAccessPoints.setProgress(mRetry!= 0);

           sendEmptyMessageDelayed(0, 6000);

       }

    }

这里的mWifiManager.startScanActive()就会调用WifiService里 的startScan()函数,下面的流程和上面的一样,这里不赘述。

当supplicant完成了这个扫描命令后,它会发送一个消息给上 层,提醒他们扫描已经完成,WifiMonitor会接收到这消息,然后再发送给WifiStateTracker。

Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

void handleEvent(int event, String remainder) {

           switch (event) {

               caseDISCONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);

                   break;

 

               case CONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);

                   break;

 

               case SCAN_RESULTS:

                   mWifiStateTracker.notifyScanResultsAvailable();

                   break;

 

               case UNKNOWN:

                   break;

            }

        }

WifiStateTracker将会广播SCAN_RESULTS_AVAILABLE_ACTION消息:

Frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

public voidhandleMessage(Message msg) {

        Intent intent;

……

caseEVENT_SCAN_RESULTS_AVAILABLE:

               if(ActivityManagerNative.isSystemReady()) {

                   mContext.sendBroadcast(newIntent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

               }

               sendScanResultsAvailable();

               /**

                * On receiving the first scanresults after connecting to

                * the supplicant, switch scanmode over to passive.

                */

               setScanMode(false);

               break;

……

       由于WifiSettings类注册了intent,能够处理SCAN_RESULTS_AVAILABLE_ACTION消息,它会调用 handleEvent(),调用流程如下所示。

WifiSettings.handleEvent()=>WifiSettings.updateAccessPoints() => mWifiManager.getScanResults()=> mService.getScanResults()=> mWifiStateTracker.scanResults() =>WifiNative.scanResultsCommand()……

将 获取AP列表的命令发送到supplicant,然后supplicant通过Socket发送扫描结果,由上层接收并显示。这和前面的消息获取流程基本 相同。

(3)配置,连接AP

当用户选择一个活跃的AP时,WifiSettings响应打开一个对话框来配 置AP,比如加密方法和连接AP的验证模式。配置好AP后,WifiService添加或更新网络连接到特定的AP。

packages/apps/settings/src/com/android/settings/wifi/WifiSetttings.java

public booleanonPreferenceTreeClick(PreferenceScreen screen,Preference preference) {

       if (preference instanceofAccessPoint) {

           mSelected= (AccessPoint) preference;

           showDialog(mSelected, false);

       } else if (preference ==mAddNetwork) {

           mSelected= null;

           showDialog(null,true);

       } else if (preference ==mNotifyOpenNetworks) {

           Secure.putInt(getContentResolver(),

                   Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,

                   mNotifyOpenNetworks.isChecked()? 1 : 0);

       } else {

           returnsuper.onPreferenceTreeClick(screen, preference);

       }

       return true;

    }

       配置好以后,当按下“Connect Press”时,WifiSettings通过发送LIST_NETWORK命令到supplicant来检查该网络是否配置。如果没有该网络或没有配置 它,WifiService调用addorUpdateNetwork()函数来添加或更新网络,然后发送命令给supplicant,连接到这个网络。 下面是从响应连接按钮到WifiService发送连接命令的代码:

packages/apps/settings/src/com/android/settings/wifi/WifiSetttings.java

public void onClick(DialogInterfacedialogInterface, int button) {

       if (button ==WifiDialog.BUTTON_FORGET && mSelected != null) {

           forget(mSelected.networkId);

       } else if (button ==WifiDialog.BUTTON_SUBMIT && mDialog !=null) {

           WifiConfigurationconfig = mDialog.getConfig();

 

           if(config == null) {

               if (mSelected != null&& !requireKeyStore(mSelected.getConfig())) {

                   connect(mSelected.networkId);

               }

           }else if (config.networkId != -1) {

               if (mSelected != null) {

                   mWifiManager.updateNetwork(config);

                   saveNetworks();

               }

           }else {

               intnetworkId =mWifiManager.addNetwork(config);

               if (networkId != -1) {

                   mWifiManager.enableNetwork(networkId,false);

                   config.networkId =networkId;

                   if (mDialog.edit || requireKeyStore(config)){

                       saveNetworks();

                   } else {

                       connect(networkId);

                   }

               }

           }

       }

    }

Frameworks\base\wifi\java\android\net\wifi\WifiManager.java

public intupdateNetwork(WifiConfiguration config) {

        if(config == null ||config.networkId < 0) {

           return-1;

        }

        returnaddOrUpdateNetwork(config);

}

private intaddOrUpdateNetwork(WifiConfiguration config) {

       try {

           returnmService.addOrUpdateNetwork(config);

       } catch (RemoteExceptione) {

           return-1;

       }

    }

 

WifiService.addOrUpdateNetwork()通过调用mWifiStateTracker.setNetworkVariable()将连接命令发送到Wpa_supplicant。

(4) 获取IP地址

当连接到supplicant后,WifiMonitor就会通知WifiStateTracker。

Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

Public void Run(){

if (connectToSupplicant()) {

               // Send a message indicatingthat it is now possible to send commands

               // tothe supplicant

               mWifiStateTracker.notifySupplicantConnection();

           }else {

               mWifiStateTracker.notifySupplicantLost();

               return;

           }

……

}

WifiStateTracker 发送EVENT_SUPPLICANT_CONNECTION消息到消息队列,这个消息有自己的handlermessage()函数处理,它会启动一个 DHCP线程,而这个线程会一直等待一个消息事件,来启动DHCP协议分配IP地址。

frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java

void notifySupplicantConnection() {

       sendEmptyMessage(EVENT_SUPPLICANT_CONNECTION);

}

 

public void handleMessage(Message msg) {

       Intent intent;

 

       switch (msg.what) {

           caseEVENT_SUPPLICANT_CONNECTION:

            ……

            HandlerThread dhcpThread =newHandlerThread("DHCP Handler Thread");

               dhcpThread.start();

               mDhcpTarget =newDhcpHandler(dhcpThread.getLooper(), this);

……

……

}

当 Wpa_supplicant连接到AP后,它会发送一个消息给上层来通知连接成功,WifiMonitor会接受到这个消息并上报给 WifiStateTracker。

Frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java

void handleEvent(int event, String remainder) {

           switch(event) {

               caseDISCONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);

                   break;

 

               caseCONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);

                   break;

               ……

}

 

private void handleNetworkStateChange(NetworkInfo.DetailedStatenewState, String data) {

        StringBSSID = null;

        intnetworkId = -1;

        if(newState ==NetworkInfo.DetailedState.CONNECTED) {

           Matchermatch = mConnectedEventPattern.matcher(data);

           if(!match.find()) {

               if(Config.LOGD) Log.d(TAG, "Could not find BSSID in CONNECTEDeventstring");

           }else {

               BSSID= match.group(1);

               try{

                   networkId= Integer.parseInt(match.group(2));

               }catch (NumberFormatException e) {

                   networkId= -1;

               }

            }

        }

        mWifiStateTracker.notifyStateChange(newState,BSSID,networkId);

}

      

void notifyStateChange(DetailedState newState, StringBSSID, intnetworkId) {

        Messagemsg =Message.obtain(

           this,EVENT_NETWORK_STATE_CHANGED,

           newNetworkStateChangeResult(newState, BSSID, networkId));

       msg.sendToTarget();

    }

 

caseEVENT_NETWORK_STATE_CHANGED:

……

configureInterface();

……

 

private void configureInterface() {

       checkPollTimer();

        mLastSignalLevel = -1;

        if(!mUseStaticIp){          //使用DHCP线程动态IP

           if(!mHaveIpAddress && !mObtainingIpAddress) {

               mObtainingIpAddress= true;

 

                                  //发送启动DHCP线程获取IP

               mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START);

            }

        } else{        //使用静态IPIP信息从mDhcpInfo中获取

           intevent;

           if(NetworkUtils.configureInterface(mInterfaceName,mDhcpInfo)) {

               mHaveIpAddress= true;

               event= EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;

               if(LOCAL_LOGD) Log.v(TAG, "Static IP configurationsucceeded");

           }else {

               mHaveIpAddress= false;

               event= EVENT_INTERFACE_CONFIGURATION_FAILED;

               if(LOCAL_LOGD) Log.v(TAG, "Static IP configuration failed");

            }

           sendEmptyMessage(event);          //发送IP获得成功消息事件

        }

    }

             DhcpThread获取EVENT_DHCP_START消息事件后,调用handleMessage()函数,启动DHCP获取IP地址的服务。

public void handleMessage(Message msg) {

           intevent;

switch (msg.what) {

               caseEVENT_DHCP_START:

 

……

Log.d(TAG, "DhcpHandler: DHCP requeststarted");

//启动一个DHCPclient的精灵进 程,为mInterfaceName请求分配一个IP地//址

    if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {

     event=EVENT_INTERFACE_CONFIGURATION_SUCCEEDED;

         if(LOCAL_LOGD)Log.v(TAG, "DhcpHandler: DHCP request succeeded");

    } else {

           event=EVENT_INTERFACE_CONFIGURATION_FAILED;

          Log.i(TAG,"DhcpHandler: DHCP request failed: " +

                           NetworkUtils.getDhcpError());

        }

……

}

这 里调用了一个NetworkUtils.runDhcp()函数,NetworkUtils类是一个网络服务的辅助类,它主要定义了一些本地接口,这些接 口会通过他们的JNI层android_net_NetUtils.cpp文件和DHCP client通信,并获取IP地址。

至此,IP 地址获取完毕,Wifi启动流程结束。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 音响音量键坏了怎么办 摩托罗拉移动电话通话没声音怎么办 摩托罗拉对讲机充电座坏了怎么办 手机导航键太灵敏怎么办 经侦大队不立案怎么办 槐茂酱菜太咸怎么办 法院执法局执法不公怎么办 搞养殖卖不出去怎么办 孔雀吃了蚯蚓该怎么办 多肉幼苗长徒了怎么办 小鸵鸟嘴断了怎么办 武汉早谢怎么办博大直上 威猛先生伤手了怎么办 嗓子眼边条线下边长块肉怎么办 线长在肉里怎么办 北京买车没有号怎么办 租的车处理违章怎么办 以租代购车不要怎么办 订车的合同掉了怎么办 买车合同丢了怎么办 车的证件都丢了怎么办 桃树直立的徒长枝怎么办 月季花长了独枝怎么办? 6岁半B超没子宫怎么办 学生学籍号和身份证号不一致怎么办 学生学籍号和身份证号不一样怎么办 领导交代的任务完不成怎么办 洗衣机里的衣服有味道怎么办 新买的洗衣机有味道怎么办 模拟工业装置没有数据验证怎么办 民办学校的指标生学费怎么办 孩子上初中后成绩不好怎么办 孩子考最后一名怎么办 数学大题不会做怎么办 小学六年级数学考30分怎么办 六年级数学考了30分怎么办 数学考了30分怎么办 没有给直接领导报到怎么办 小学二年级成绩不好怎么办 初中孩子上课注意力不集中怎么办 学生打架家长争吵老师怎么办