zoukankan      html  css  js  c++  java
  • android4.1 Wifi 浅析

    简单分析下wifi相关类,首先了解几个主要概念

    AsyncChannel

    简单理解:

    AsyncChannel,就是借助Messenger 机制,让两个不同的handler之间进行通信。

    AsyncChannel类有两个Messenger对象:mSrcMessenger,mDstMessenger。

    mSrcMessenger,一般用于封装源端handler对象

    mDstMessenger,一般用于封装目的端handler对象

    而后,调用AsyncChannel的sendMessage方法时,执行两个操作:

    1. msg.replyTo = mSrcMessenger; //重设消息的replyTo值

    2. mDstMessenger.send(msg); //该方法就会将消息发送给目的端的handler去处理

    由于重设了消息的replyTo值,之后在目的端发出的消息,将返回给源端handler处理。

     

    参考:Android源码阅读笔记:AsyncChannel与层次状态机StateMachine

     

    wifi 相关文件

    framework
    WifiManager
        管理所有wifi操作,提供API调用,主要用于上层应用调用
    WifiService
        处理Wifi操作请求。一般都是在WifiManager中被调用
    WifiStateMachine
        处理wifi各个阶段状态所要处理的消息
    WifiMonitor
        监听所有来自wpa_supplicant的事件,并传递给WifiStateMachine处理
    WifiNative
        native方法,发送消息给wpa_supplicant
    
    jni层
    android_net_wifi_Wifi.cpp
    
    wpa_supplicant适配器层
    wifi.c
    
    wpa_supplicant层
    wpa_supplicant.c

     

    接下来分析wifi启动、扫描、连接ap的流程。

    一、 Wifi相关类创建

    1.SystemServer::ServerThread::run---->new WifiService(...);
    
    2.WifiService(...)---->new WifiStateMachine(...);
    
    3.WifiStateMachine(...)
    
    ---->new WifiNative(...)
    
    ---->new WifiMonitor(...)
    
    ---->AsyncChannel::connectSync(...)
    
     
    
    ps: AsyncChannel::connectSync将WifiStateMachine和wifiApConfigStore通过AsyncChannel关联起来。
    
     
    4. SystemServer::ServerThread::run ServiceManager.addService(...);

     over~~

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

     

    二、 wifi功能启动

    先贴出整体流程时序图

    1. 检查系统属性中的wifi状态信息

    SystemServer::ServerThread::run
    --->WifiService::checkAndStartWifi (该方法只在开机时调用,用来检查wifi是否需要开启)

    分析WifiService::checkAndStartWifi方法:

        public void checkAndStartWifi() {
            mAirplaneModeOn.set(isAirplaneModeOn());
            mPersistWifiState.set(getPersistedWifiState());
            /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
            boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
            Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                    (wifiEnabled ? "enabled" : "disabled"));
    
            // If we are already disabled (could be due to airplane mode), avoid changing persist
            // state here
            if (wifiEnabled) setWifiEnabled(wifiEnabled);
    
            mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
                   makeWifiWatchdogStateMachine(mContext); //以后分析
    
        }

    (1)isAirplaneModeOn()/getPersistedWifiState():都是获取系统属性进行判断。

    (2)shouldWifiBeEnabled():判断mAirplaneModeOn/mPersistWifiState中的值,其实就是上述两个方法获得的值。

    (3)testAndClearWifiSavedState():获取系统属性中保存的wifi状态的值,返回,之后清空状态,置为0。

    另注意:以下分析都是基于条件:开机启动时,wifi状态为on。

     

    因此,接着会调用setWifiEnabled(true)方法,下面分析。

    到此,检查wifi系统属性状态的操作结束,over~~

     

    2.setWifiEnabled(true)执行流程

    2.1

    该方法中主要执行以下语句:

            if (FeatureQuery.FEATURE_CT_FMC_SUPPORT && WifiManager.fmcV2Support()) {
                mWifiStateMachine.fmcV2SetWifiEnabled(enable);
            } else {
                mWifiStateMachine.setWifiEnabled(enable);
            }

    分析:

    FeatureQuery.FEATURE_CT_FMC_SUPPORT/WifiManager.fmcV2Support()

    (1)FeatureQuery.FEATURE_CT_FMC_SUPPORT 

    这个属性值在build/buildplus/target/FeatureQuery.java里可以找到。

     

    (2)WifiManager::fmcV2Support方法如下

        public static boolean fmcV2Support() {
            return (SystemProperties.getInt("ro.config.cwenable", 0) == 1)
                     && (SystemProperties.getInt("ro.config.fmcv2support", 0) == 1);
        }

    就是获取两个系统属性,判断是否支持FMC功能,有两种方式可以查看

    (a)out/target/product/msm8625/system/build.prop中可以找到

    (b)命令提示符下,adb shell,然后使用命令:getprop XX ,就可以获得属性值。XX表示系统属性名。

    总结:这两个条件的作用就是判断是否支持FMC功能(固定网络与移动网络融合)

     

    2.2

    行mWifiStateMachine.fmcV2SetWifiEnabled法:

        public void fmcV2SetWifiEnabled(boolean enable) {
            if (!enable) {
                ......
            } else {
                setWifiEnabled(enable);
            }
        }

    接着调用WifiStateMachine::setWifiEnabled(enable): 发送两个消息。

        public void setWifiEnabled(boolean enable) {
            mLastEnableUid.set(Binder.getCallingUid());
            if (enable) {
                /* Argument is the state that is entered prior to load */
                sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));
                sendMessage(CMD_START_SUPPLICANT);
            } else {
               ......
            }
        }

    接收CMD_LOAD_DRIVER消息的是DriverUnloadedState状态。

     

    2.4 DriverUnloadedState状态处理

    public boolean processMessage(Message message) {
          if (DBG) log(getName() + message.toString() + "
    ");
          switch (message.what) {
               case CMD_LOAD_DRIVER:
                   transitionTo(mDriverLoadingState);
                   break;
                   ......
    }

    在这里CMD_LOAD_DRIVER消息被处理,切换到DriverLoadingState状态。

     

    2.5 DriverLoadingState 处理状态

    public void enter() {
      ......
      final Message message = new Message();
      message.copyFrom(getCurrentMessage());
      new Thread(new Runnable() {
                    public void run() {
                        mWakeLock.acquire();
                        //enabling state
                        switch(message.arg1) {
                            case WIFI_STATE_ENABLING:
                                setWifiState(WIFI_STATE_ENABLING);
                                break;
                            case WIFI_AP_STATE_ENABLING:
                                setWifiApState(WIFI_AP_STATE_ENABLING);
                                break;
                        }
    
                        if(mWifiNative.loadDriver()) {
                            if (DBG) log("Driver load successful");
                            sendMessage(CMD_LOAD_DRIVER_SUCCESS);
                      }
            .....
    }

    (1)enter方法中通过message.copyFrom(getCurrentMessage())重新获得了(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0)息,然后开启一个线程来处理。

    (2)线程中首先判断消息参数arg1,进入”case WIFI_STATE_ENABLING调用setWifiState方法。该方法主要是用来设置电池使用统计中的wifi信息。然后会发出一个WIFI_STATE_CHANGED_ACTION广播。

    (3)调用 WifiNative.loadDriver()方法加载wifi相关驱动,成功后发送CMD_LOAD_DRIVER_SUCCESS消息。该消息会在当前DriverLoadingState状态的processMessage方法中被处理。

    (4)处理CMD_LOAD_DRIVER_SUCCESS消息

    case CMD_LOAD_DRIVER_SUCCESS:
          transitionTo(mDriverLoadedState);
          break;
    .....

    状态切换到DriverLoadedState

     

    2.6 DriverLoadedState状态处理

    处理WifiStateMachine::setWifiEnabled方法发出的CMD_START_SUPPLICANT消息(在此之前,该消息一直未被处理)

    case CMD_START_SUPPLICANT:
       ......
         if(mWifiNative.startSupplicant(mP2pSupported)) {
                if (DBG) log("Supplicant start successful");
                mWifiMonitor.startMonitoring();
                transitionTo(mSupplicantStartingState);
         } 
         ......
    }

    (1)启动wpa_supplicant:

    调用startSupplicant方法启动。

    (2)启动WifiMonitor监听

    startMonitoring
    
    --->new MonitorThread().start()
    
    --->MonitorThread::run
    
    --->WifiMonitor::connectToSupplicant()
    
    --->WifiNative::connectToSupplicant() [最多尝试5次]
    
           ---> mStateMachine.sendMessage(SUP_CONNECTION_EVENT)

    最后成功连接上wpa_supplicant后,发出SUP_CONNECTION_EVENT消息。

     

    (3)切换到SupplicantStartingState状态

    处理SUP_CONNECTION_EVENT消息:

    case WifiMonitor.SUP_CONNECTION_EVENT:
          if (DBG) log("Supplicant connection established");
          setWifiState(WIFI_STATE_ENABLED);
        ......
          sendSupplicantConnectionChangedBroadcast(true);
          transitionTo(mDriverStartedState);
          break;
    ......

    设置电池统计为enabled,发出WIFI_STATE_CHANGED_ACTION广播。这个广播会被wifi应用和状态栏接收处理;sendSupplicantConnectionChangedBroadcast方法发出广播,只在测试代码中被处理;最后切换到DriverStartedState状态。

     

    到此为止,开机启动wifi的工作就完成了,over~~

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

    三、打开wifi,自动扫描AP

    1. WifiSettings类构造函数:

    (1)定义了一个广播;

    (2)创建了一个Scanner对象(Scanner类是一个Handler子类,用来启动扫描功能)

    2. WifiSettings::onActivityCreated

    ---->new WifiEnabler(...)
    
    ---->WifiEnabler::resume()
    
    ---->resume方法中,为Switch开关设置了checkedChange的监听方法。

    3. 初始化相关类对象的工作已完成,现在打开wifi

    首先点击Switch开关,将触发onCheckedChanged方法。在这里,会先对飞行模式、wifi的状态进行判断。

    ---->WifiManger::setWifiEnabled
    
    ---->WifiService::setWifiEnabled
    
    ---->WifiStateMachine::setWifiEnabled
    
    ---->接下来的操作同” 开机wifi功能启动”。直到开机wifi功能启动完毕。

    此时,WifiStateMachine::SupplicantStartingState::processMessage:

    ---->case WifiMonitor.SUP_CONNECTION_EVENT:
    
    setWifiState(WIFI_STATE_ENABLED); //wifi状态为enabled
    
    ......

    该方法会发送一个WIFI_STATE_CHANGED_ACTION的粘性广播。这个广播会被WifiSettings类接收到。

     

    4. WifiSettings处理WIFI_STATE_CHANGED_ACTION广播

    BroadcastReceiver::onReceive
    
    ---->handleEvent
    
    ---->updateWifiState  //在该方法中,接着会调用Scanner::resume方法。
    
    ---->Scanner::resume
    
    ---->Scanner::sendEmptyMessage(0) 
    
    ---->Scanner::handleMessage
    
    调用WifiManager::startScanActive方法进行扫描
    
    ---->WifiManager::startScanActive
    
    ---->WifiService::startScan
    
    ---->WifiStateMachine::startScan //发出CMD_START_SCAN消息
    
    该消息会被DriverstartedState状态处理。
    
    ---->WifiNative::scan

    接着就调用到native层去了...这里就不分析下去了,等后面整体分析...

    分析完毕,over~~

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

     

    四、打开wifi,连接AP

    分成两个部分分析:

    1.wifi ap 提示框的创建

    2.输入密码,连接ap

     

    1. wifi ap 提示框的创建

    初始条件:这里分析安全性为加密的ap

    1.1 点击某个ap,调用流程:

    ---->WifiSettings::onPreferenceTreeClick
    
    ---->WifiSettings::showDialog(选择的AP, false)
    
    接着调用父类的showDialog方法
    
    ---->SettingsPreferenceFragment::showDialog(WIFI_DIALOG_ID) 

    SettingsPreferenceFragment类中,会创建一个SettingsDialogFragment对象,代码如下:

        protected void showDialog(int dialogId) {
            if (mDialogFragment != null) {
                Log.e(TAG, "Old dialog fragment not null!");
            }
            //创建一个SettingsDialogFragment对象
            mDialogFragment = new SettingsDialogFragment(this, dialogId); //(1)
            mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); //(2)
        }

    (1) SettingsDialogFragment类继承自DialogFragment类,会在onCreate后调用onCreateDialog方法。

    ---->SettingsDialogFragment(DialogCreatable fragment, int dialogId)
    
    ---->SettingsDialogFragment::onCreateDialog()

    因为初始情况下,savedInstanceStatenull,所以该方法直接回调构造函数中传入的fragment参数的onCreateDialog方法,即WifiSettings::onCreateDialog

    ---->WifiSettings::onCreateDialog

    回到WifiSettings类:

    WifiSettings::onCreateDialog方法中,会创建一个WifiDialog类对象。

    跳转到WifiDialog类:

    执行WifiDialog类的onCreate方法,会发现它创建了一个WifiConfigController类对象。

    再看WifiConfigController类:

    该类的构造函数主要是初始化了ap提示框的界面,当然还包括”添加网络”的界面。

    这样,界面就创建了,需要显示出来,这就是下一步的作用了。

     

    (2)调用了DialogFragment::show方法,将提示框显示出来。

    至此,提示框分析完毕。

     

    2. 输入密码,连接ap

    (1)点击ap提示框的“连接”按钮,会调用WifiSettings::onClick方法:

        public void onClick(DialogInterface dialogInterface, int button) {
            if (button == WifiDialog.BUTTON_FORGET && mSelectedAccessPoint != null) {
                forget();
            } else if (button == WifiDialog.BUTTON_SUBMIT) {
                if (FeatureQuery.FEATURE_CT_FMC_SUPPORT) {
                shouldShowErrorMsg = true;
                }
                submit(mDialog.getController());
            }
        }

    (2) 接着便调用submit方法,参数为WifiConfigController类对象。

    (3) submit方法中会调用WifiManager::connect方法进行连接。

    over~~

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

     

    分析framework-->native-->wpa_supplicant几个方法的调用流程

    mWifiNative.isDriverLoaded()
    
    ---> android_net_wifi_Wifi.cpp::android_net_wifi_isDriverLoaded
    
    ---> wifi.c:: is_wifi_driver_loaded()
    --->查看系统属性wlan.driver.status(ok为已加载驱动,unloaded为未加载)
    mWifiNative.loadDriver()
    
    ---> android_net_wifi_Wifi.cpp::android_net_wifi_loadDriver
    
    ---> wifi.c:: wifi_load_driver()
       ---> ensure_wlan_driver_config_file_exists 
          //首先判断wifi的驱动配置文件是否加载
         --->property_set  //设置属性
         --->insmod //install modules 载入驱动模块等
    mWifiNative.startSupplicant(mP2pSupported)
    参数为mP2pSupported,即是否支持p2p
    
    ---> android_net_wifi_Wifi.cpp::android_net_wifi_startSupplicant
    
    ---> wifi.c::wifi_start_supplicant(p2pSupported)
       ---> ensure_config_file_exists
          //首先判断wifi的配置文件是否加载
    "/data/misc/wifi/wpa_supplicant.conf";
    "/data/misc/wifi/p2p_supplicant.conf";
         --->property_set("ctl.start", supplicant_name);  
     // 这里supplicant_name为p2p_supplicant,所以就会启动init.rc中名为p2p_supplicant的服务了

    ps:

    property_set("ctl.start",xxx)

    property_set("ctl.stop",xxx) 

    来使得android property service 去开启或结束 xxx service.

     

    因为init.qcom.rcservice p2p_supplicant中已经包含了wpa_supplicant启动所需的语句及参数,所以后面会开始执行wpa_supplicant/main.c::main方法来初始化wpa_supplicant了。

    wpa_supplicant初始化  见wpa_supplicant初始化

     

    WifiMonitor::connectToSupplicant
    
    ---> mWifiNative.connectToSupplicant()
    ---> mWifiNative.connectToSupplicant(mInterface)
        //mInterface是创建WifiNative对象的时候传递进来的参数
    
    ---> android_net_wifi_Wifi::android_net_wifi_connectToSupplicant
    
    ---> wifi.c:: wifi_connect_to_supplicant(ifname.c_str())
    
    ---> 首先判断文件IFACE_DIR = "/data/system/wpa_supplicant";是否存在,
         存在:ifname="/data/system/wpa_supplicant/wlan0";
       不存在:ifname=wlan0
    
    ---> wifi_connect_on_socket_path
        /* 首先,判断系统属性:
       * wlan.driver.status 是否为ok
       * init.svc.p2p_supplicant 是否为running
       * 然后,创建两个socket(通过wpa_ctrl_open方法)
       * ctrl_conn:用于向wpa_supplicant发送命令并接收response
       * monitor_conn:它一直阻塞等待从wpa_supplicant过来的event
       * 最后调用wpa_ctrl_attach将monitor_conn信息注册到wpa_supplicant
       */

    wpa_ctrl_attach作用:由于socket是数据报方式的,这一步是必须的,对于存在于wpa_supplicant的服务器端,它是所有客户端共享的,由于它需要主动向monitor_conn客户端发送事件,所以它必须先记录下该客户端的详细信息,wpa_supplicant就可以将event发向该socket。

    这样,就通过socket,建立起native-->wpa_supplicant的连接了。

     

    mWifiNative.waitForEvent()
    该函数是有返回值的,返回值即为wpa_supplicant传递过来的消息。
    
    java层会通过jni方式调用android_net_wifi_waitForEvent(在线程MonitorThread中调用)方法,该方法会调用wifi_wait_for_event。在wifi_wait_for_event方法里,会阻塞接收从wpa_supplicant模块传来的事件,一旦wpa_supplicant模块发出事件,wifi_wait_for_event接收到后,会将包含事件的buf通过函数参数的方式回传到java层,java收到事件后,再继续调用wifi_wait_for_event函数进行阻塞等待接收,从而完成一个循环。
    
    ---> mWifiNative::waitForEvent(mInterface)
    
    ---> android_net_wifi_Wifi.cpp::android_net_wifi_waitForEvent
    
    ---> wifi.c::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf)
      ---> wifi_wait_on_socket
      ---> wifi_ctrl_recv
      ---> wpa_ctrl_recv
      ---> recv
    ps:从wpa_supplicant传递过来的值由recv函数接收,一直向上传递到buf参数中,最终返回return env->NewStringUTF(buf)给WifiMonitor。

     

     

     

  • 相关阅读:
    Roadblocks(poj 3255)
    最小集合(51nod 1616)
    绿色通道(codevs 3342)
    解的个数(codevs 1213)
    多米诺(codevs 3052)
    abcd
    dwarf tower
    第K 小数
    noip2016复习
    文化之旅(洛谷 1078)
  • 原文地址:https://www.cnblogs.com/chenbin7/p/3221922.html
Copyright © 2011-2022 走看看