`
473687880
  • 浏览: 535498 次
文章分类
社区版块
存档分类
最新评论

android wifi模块分析

 
阅读更多

声明:本文纯属网上资料收集,版权归源作者所有,转载时请标明为转载文章

现在对android平台的wifi模块了解了一段时间,现在做一些简要总结,以便以后查阅和与修正,上正文。

【Wifi模块学习流程】

最近研究Wifi模块,查了不少的相关资料,但发现基本上是基于android2.0版本的的分析,而现在研发的android移动平台基本上都是2.3的版本,跟2.0版本的差别,在Wifi模块上也是显而易见的。2.3版本Wifi模块没有了WifiLayer,之前的WifiLayer主要负责一些复杂的Wifi功能,如AP选择等以提供给用户自定义,而新的版本里面的这块内容基本上被WifiSettings所代替

本文就是基于android2.3版本的Wifi分析,主要分为两部分来分别说明:

(a) Wifi的启动流程(有代码供参考分析)

(b) Wifi模块相关文件的解析

(c) Wpa_supplicant解析


【A】wifi的基本运行流程(针对代码而言)

首先给一张我网上down下来的图,针对2.3版本之前的,由于不怎么擅长画这些,大家也就将就点,只要能助理解就可以了

(一)初始化

a.流程

1.在SystemServer启动的时候会生成一个ConnectivityService的实例

2.ConnectivityService的构造函数会创建WifiService

3.WifiStateTracker会创建WifiMonitor接受来自底层的事件,WifiService和WifiMonitor是整个wifi模块的核心,WifiService负责启动和关闭wpa_supplicant,启动和关闭WifiMonitor监视线程和把命令下方给wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接受事件通知

b.代码分析

要想使用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,Object value) {

        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使能(开启)结束,自动进入扫描阶段。


(二)扫描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) {

                case DRIVER_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()) {

           case DISCONNECTED:

           case INACTIVE:

           case SCANNING:

           case DORMANT:

                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);

       return super.onCreateOptionsMenu(menu);

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

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

public booleanonOptionsItemSelected(MenuItem item) {

       switch (item.getItemId()) {

           case MENU_ID_SCAN:

                if(mWifiManager.isWifiEnabled()) {

                    mScanner.resume();

                }

                return true;

           case MENU_ID_ADVANCED:

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

                return true;

       }

       return super.onOptionsItemSelected(item);

}
Handler类:
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 void handleMessage(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;

……

case EVENT_SCAN_RESULTS_AVAILABLE:

                if(ActivityManagerNative.isSystemReady()) {

                    mContext.sendBroadcast(new Intent(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 instanceof AccessPoint) {

           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 {

           return super.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) {

           WifiConfiguration config = 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 {

                int networkId =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;

        }

        return addOrUpdateNetwork(config);

}

private intaddOrUpdateNetwork(WifiConfiguration config) {

       try {

           return mService.addOrUpdateNetwork(config);

       } catch (RemoteException e) {

           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

                // to the 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) {

           case EVENT_SUPPLICANT_CONNECTION:

             ……

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

                dhcpThread.start();

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

	 ……
     
     case EVENT_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 {        //使用静态IP,IP信息从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获得成功消息事件

        }

}


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

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

void handleEvent(int event, String remainder) {

           switch (event) {

               case DISCONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED,remainder);

                   break;

               case CONNECTED:

                   handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED,remainder);

                   break;
                ……
	}

 

private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {

        StringBSSID = null;

        intnetworkId = -1;

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

           Matcher match = mConnectedEventPattern.matcher(data);

            if(!match.find()) {

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

            }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, int networkId) {

        Messagemsg = Message.obtain(

           this, EVENT_NETWORK_STATE_CHANGED,

            newNetworkStateChangeResult(newState, BSSID, networkId));

       msg.sendToTarget();

}


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

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

public void handleMessage(Message msg) {

 intevent;

 switch (msg.what) {

 case EVENT_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启动流程结束。



待续

(b) Wifi模块相关文件的解析

(c) Wpa_supplicant解析









分享到:
评论

相关推荐

    Android WIFI 模块分析

    对Android 下的WIFI 模块进行了分析和测试

    Android WIFI模块分析

    以下是对Android WIFI模块的深入分析: **WIFI模块框图** WIFI模块通常包括以下几个层次:应用程序层、框架层、JNI(Java Native Interface)层、硬件抽象层和内核驱动层。在框图中,我们可以看到WirelessSettings...

    Android Wifi模块分析

    本文将深入探讨Android Wi-Fi源码分析,特别是如何连接到一个接入点(Access Point,简称AP)的过程。 首先,当用户在AcessPointDialog中选择加密方式并点击连接按钮后,Android系统会执行连接操作。关键代码在于`...

    Android__WIFI模块分析

    Android WIFI模块分析 Wifi 模块框图 Wifi核心模块 Wifi工作步骤 Wifi模块代码总结

    Android__WIFI模块分析.ppt

    Android WIFI 模块分析 Android WIFI 模块分析是 Android 操作系统中负责 WIFI 连接的模块。该模块主要由 WifiService、WifiMonitor、Wpa_supplicant、Wifi 驱动模块、Wifi 电源管理模块等组件组成。 Wifi 模块...

    android与WIFI模块的数据传输 数据透传

    在Android平台上,与WIFI模块进行数据传输是一个常见的任务,特别是在物联网(IoT)设备的交互中。本项目中,开发者被要求创建一个Android应用程序,用于配置HLK-RM04 WIFI模块,进行数据读取、参数设置以及系统时间...

    Android WIFI模块测试

    在Android平台上,WIFI模块测试是一项关键任务,涉及到多个方面,确保设备能够稳定、高效地接入无线网络。下面将详细阐述Android WIFI模块测试涉及的知识点。 首先,WIFI是一种无线连接技术,基于IEEE802.11标准,...

    Android studio的WiFi模块连接和搜索

    在这个特定的主题中,我们聚焦于Android Studio中的WiFi模块,包括如何连接到WiFi网络以及如何进行WiFi热点搜索。这些功能涉及到Android系统的网络权限管理,这对于构建具有网络功能的应用至关重要。 1. **WiFi连接...

    深入理解Android:WiFi模块 NFC和GPS卷.邓凡平(文字版).pdf

    《深入理解Android:WiFi模块 NFC和GPS卷》是由邓凡平编著的一本技术书籍,主要探讨了Android系统中三个重要的无线通信技术:WiFi、NFC(近场通信)和GPS(全球定位系统)。这本书以文字版的形式,深入浅出地讲解了...

    T507 AndroidQ WIFI模块移植说明.pdf

    Android Q WIFI 模块移植指南 随着 Android 系统的不断发展和更新,WIFI 模块的移植成为 Android 设备开发中一个非常重要的步骤。T507 Android Q WIFI 模块移植说明文档提供了将 WIFI 模块移植到 Android Q 系统上...

    android wifi应用层框架分析

    Android WIFI 应用层框架分析是从应用程序的角度描述 Android WIFI 的工作流程,主要介绍了各个控制接收模块的数据走向,具体数据传输流程和所调用到的方法介绍。本文将从 WIFI 初始化、WIFI 启动、开始扫描 AP、...

    【Android 11】【WiFi模块】WiFi打开函数调用流程图

    Android 11 WiFi 模块 WiFi 打开函数调用流程图 Android 11 中的 WiFi 模块是如何打开的?下面是 WiFi 打开函数调用流程图的详细解释。 首先,用户打开 WiFi 时,系统会调用 WifiServiceImpl.java 中的 ...

    Android-WIFI.rar_WiFi模块程序_android wifi_android wifi slam_android

    在Android系统中,WiFi模块是实现无线网络连接的关键部分,对于开发者来说,理解和掌握如何进行Android WiFi开发至关重要。本文将深入探讨Android WiFi的模块程序、初始化过程、连接AP的步骤,以及WiFi SLAM...

    android wifi模块代码

    首先,Android Wi-Fi模块的核心代码主要位于Android源码树的`frameworks/base/services/core/java/com/android/server/wifi`目录下。这部分代码包含了Wi-Fi服务(WifiService)的实现,它是系统服务,负责管理Wi-Fi...

    Android wifi display功能优化

    其中,WiFi模块负责WiFi连接和数据传输,WiFi Display模块负责WiFi Display功能的控制和数据传输,而显示模块负责显示 WiFi Display的内容。 二、代码分析 WiFi Display功能的代码分析可以参考博客...

    Android8.0平台实现双wifi模块STA+AP模式

    在Android 8.0平台上实现双Wi-Fi模块的STA(Station)+AP(Access Point)模式,是一项技术挑战,涉及到Android系统的网络堆栈、Wi-Fi驱动以及框架层的深度定制。这种模式允许设备同时作为Wi-Fi客户端连接到一个网络...

    android环境下wifi模块编程

    在Android环境下进行WiFi模块编程,主要是利用Android系统提供的API来操控设备的WiFi功能,包括开启/关闭WiFi,扫描可用的WiFi网络,连接指定的网络,以及处理WiFi状态变化等。以下将详细介绍相关知识点: 1. **...

    深入理解Android WiFi模块 NFC和GPS卷

    总结来说,本资料“深入理解Android WiFi模块 NFC和GPS卷”将涵盖这些关键领域的基本概念、API使用、以及实践应用案例,是初学者学习Android开发中不可或缺的一部分。通过阅读这份文档,你将能够建立起对这些技术的...

Global site tag (gtag.js) - Google Analytics