andoid 网络学习

android 2.3 wifi  

2012-09-07 16:00:18|  分类: Android |  标签: |字号 订阅

 
 

1.    Wifi扫盲... 4

2.    Android Wifi框架的结构图... 5

3.    wpa_supplient 5

4.    Netd. 7

5.    FrameWork层架构... 7

6.    情景分析... 8

6.1.     情景1. 8

6.2.     情景2. 11

6.3.     情景3. 11

7.    Ad hoc的支持... 15

8.    wifi direct 16

9.    Soft ap支持... 17

10.   Wifi Tethering支持... 20

11.   Usb Tethering支持... 21

12.   Reverse usb Tethering. 21

13.   需要改动的地方... 22

14.   测试... 22

 

 

 




1.       Wifi扫盲

Access point: 也叫hotspot(热点), 家里的无线路由就是ap。

SoftAp:软ap, 用无线网卡模拟ap的功能。

Wifi网络有两种模式:


Infrastructure mode, in which wireless clients are connected to an access point. This is generally the default mode for 802.11b cards.
Ad hoc mode, in which clients are connected to one another without any access point.

请参考http://en.kioskea.net/contents/wifi/wifimodes.php3

我们既可以通过Ad hoc也可以通过SoftAp方式来实现共享网络(例如手机可以通过笔记本访问internet), 但是原理不同。

这里只是简单的概括, 详细的解释请google或百度。

 

2.       Android Wifi框架的结构图

    上图只是wifi工作于station模式时的图, 当工作于soft ap模式时最基本的不同是不通过wpa_supplicant而是Framework层直接通过netd daemon来控制驱动。

3.       wpa_supplient

    虽然本文不关心JNI层以下的部分, 但wpa_supplient是什么需要解释一下。 WPA是WiFi Protected Access的缩写, wpa_supplicant是“WiFi网络安全存取认证”的意思。Android是用的wpa_supplicant的修改版本。

       在Android wifi框架里, wpa_supplcant起着承上启下的作用。 它向上提供netlink socket接口, 向下依赖wifi驱动的wireless extention标准接口。 也就是说驱动必须支持wireless extention才可以。wireless extention其实是一个将要过时的标准, Android也将向nl80211标准过度, 采用未修改的wpa_supplicant。

请参见http://wireless.kernel.org/en/developers/Documentation/Android

       本节以下部分摘自《Android平台上无线网卡自动扫描并关联AP的实现》:http://hi.baidu.com/xyp86/blog/item/d371a1d78d4162d7a144dfd3.html。 

       Android平台使用的WiFi控制框架是基于大名鼎鼎的wpa_supplicant,它是一个安全中间件,为各种无线网卡提供统一的安全机制,如下图所示:

       客户端程序,包括wpa_cli命令行或java图形界面程序,通过unix本地socket与
wpa_supplicant daemon服务通信,发送命令并接收结果;wpa_supplicant daemon服务,对应上述中间部分,功能是“上传下达”。所有客户端通过它控制硬件网卡,通过发送字符串命令控制是否扫描AP,提取扫描结果和是否关联AP等操作,同时将驱动的执行状态发送给用户。该服务是设计支持多种无线网卡芯片,因此各个厂商共同提供了一个通用接口给wpa_supplicant调用

4.       Netd

Netd是android的一个守护进程, 是专门为Android开发的。 它功能很广, 包括设置nat, usb tethering, wifi tethering, soft ap设置, 还有网络接口add, remove, change事件的通知。 在FrameWork有NetworkManagementService负责和netd通信,framework代码可以通过 NetworkManagementService利用netd的全部功能。Netd的代码位于“android sources”/system/netd。

5.       FrameWork层架构

6.       情景分析

6.1.      情景1

       当前系统正连接了以太网, Wifi是未使能的, 有无密码的Wifi信号存在, Wifi的优先级高于以太网。 此时在Settings使能Wifi, 系统就会连接到Wifi网络, 那么整个过程是怎样的呢?

       下面是整个过程的UML序列图。

    当在settings使能Wifi后, 首先会调用WifiService.setApEnabled(false), 也就是禁止Wifi模块的作为Ap(Access Point, 即一个接入点)的功能。需要了解的是, 现在的硬件Wifi模块即支持去连接附近的Ap, 也可以作为Ap供其它设备接入。那么给其它设备接入有什么用处呢? 那就是tethering, 即网络共享。 假设你的设备当前可以通过以太网访问因特网, 当在Wifi上使能Ap功能时, 其它连入的设备就可以通过这台设备访问因特网。 当然在同一时刻, 只能有一种身份。

       接着会调用WifiService.setWifiEnabled(true), 去加载wifi适配层, 启动supplient守护进程, 启动MonitorThread开始监听supplient的事件。

       首先 MonitorThread会收到DRIVER_STATE事件, 意味着硬件启动成功。 接着会调用到WifiNative.scanCommand()向supplient发送搜索Ap的命令。然后MonitorThread又进入等待事件的状态。

       当supplient搜索Ap结束时, MonitorThread会收到SCAN_RESULTS事件。 接下来会调用WifiNative. setScanResultHandlingCommand(NormalMode)来让supplient自行决定去连接到哪个Ap, supplient会挑选信号最强并且没有密码的Ap进行连接。同时WifiSettings会收到WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播,调用mWifiManager.getScanResults()得到扫描到得ap列表。 ScanResult里包含如下信息:

 

    public String SSID;

   

    public String BSSID;

   

    public String capabilities;

   

    public int level;

   

    public int frequency;

下面是几个ScanResult的例子:

SSID=”Exotica”

FEATURES=”[WPA2-PSK-CCMP]”

FREQ=2422

LEVEL=-40

BS=”01:02:03:04:05:06”

 

SSID=”Exotica”

FEATURES=”[WEP]”

FREQ=2432

LEVEL=-50

BS=”02:03:04:05:06:07”

 

       当supplient连接到一个Ap时, MonitorThread会收到CONNECTED事件。 接下来就会尝试配置IP地址, 如果IP地址配置成功就会发送EVENT_STATE_CHANGED给ConnectivityService,ConnectivityService就会根据网络优先级决定关掉以太网而通过Wifi联网的决定。这里要区分网络接口的disconnect和disable的不同之处, disconnected的接口依然可能enable, disable是指硬件上的。 在pc上当切换到其他网络只是disconnected以前的网络, 而Android为了省电, 是disable以前网络的。

6.2.      情景2

    系统启动时, Wifi和Ethernet都处于使能状态, 并且附近有没有密码的Wifi信号, Ethernet也是通的。系统启动后就会自动连接到Wifi网络, 那么系统启动时如何决定连接到哪个网络呢?

       在上一篇《Android的网络支持和管理(一)---以太网》中, 我们分析了从网线插上到以太网通畅的全过程。 这过程中驱动层一共向上发出了两个信号, 第一个代表硬件连接上了, 第二个代表网络连接上了(即IP地址配置成功)。

        刚才我们又分析了当使能Wifi到Wifi通畅的全过程。 这过程中驱动层一共向上发了三个信号, 第一个代表硬件使能成功,第二个代表搜索Ap完毕, 第三个代表网络连接上了(即IP地址配置成功)。

        在IP地址配置成功以前, 以太网和Wifi都是默默做着自己的工作, 丝毫没有参与网络管理。 当即IP地址配置成功后, 能够确保各自网络通畅时, 才通知ConnectivityManager。

        当启动时,如果以太网使能的话, 不管有没有网线连接都会去尝试根据保存的设置配置IP地址, 如果IP地址配置成功就会通知ConnectivityManager。同样, 如果Wifi使能的话, 就会加载Wifi驱动和启动wpa_supplient, 然后搜索AP并尝试连接, 接下来配置IP地址, 如果成果的话就会通知 ConnectivityManager。(注:WifiService.startWifi函数会在ConnectivityManager的构造函数里面调用去判断是不是要使能Wifi)无论ConnectivityManager先收到Wifi发出的信号还是以太网发出的信号, 最后的结果都是一样的, 当收到第二个信号时就会禁掉优先级小的以太网。

6.3.      情景3

系统中只有Wifi, 附近有好几个有密码的Ap, 当在Settings里使能Wifi后, 会搜索到这些Ap并显示出来。 我们选择一个Ap后会弹出WifiDialog要求输入密码, 输入密码后点确定。 下面是随后的过程。

       



       我们在WifiDialog中配置的信息可以用WifiConfigure来表示, 它包含的信息如下:

 

    public int networkId;

 

   

    public int status;

   

    public String SSID;

   

    public String BSSID;

 

   

    public String preSharedKey;

   

    public String[] wepKeys;

 

   

    public int wepTxKeyIndex;

 

   

    public int priority;

 

   

    public boolean hiddenSSID;

 

   

    public BitSet allowedKeyManagement;

   

    public BitSet allowedProtocols;

   

    public BitSet allowedAuthAlgorithms;

   

    public BitSet allowedPairwiseCiphers;

   

    public BitSet allowedGroupCiphers;

       ScanResult是Ap广播的信息,而WifiConfigure是wpa_supplicant用来尝试和Ap进行连接的信息。ScanResult说“窗前明月光”, WifiConfigure只有说“疑是地上霜”才能匹配。 WifiConfigure和wpa_supplicant配置文件里保存的信息格式是对应的, 关于wpa_supplicant更详细的介绍请看源码下的readme 。 可以说wpa_supplicant实现了所有我们需要的功能, 包括ap搜索, 连接,甚至设置的保存。Settings界面通过WifiManager来和wpa_supplicant通信。

7.       Ad hoc的支持

添加ad hoc的支持有两种方式,改wpa_supplicant和改Android Framework wpa_supplicant的原理和方法请参考http://www.xda-developers.com/android/android-ad-hoc-wireless-network-support/, 这种方法不推荐, 不是解决问题的根本。下面是改Android Framework的方法。

Android Framework中添加adhoc支持很简单, 可能只需要改一行代码(当然还没经过测试) 如下:

List<ScanResult> results = mWifiManager.getScanResults();

        if (results != null) {

            for (ScanResult result : results) {

                // Ignore hidden and ad-hoc networks.

                if (result.SSID == null || result.SSID.length() == 0 ||

                        result.capabilities.contains("[IBSS]")) {

                    continue;

                }

 

                boolean found = false;

                for (AccessPoint accessPoint : accessPoints) {

                    if (accessPoint.update(result)) {

                        found = true;

                    }

                }

                if (!found) {

                    accessPoints.add(new AccessPoint(this, result));

                }

            }

        }

上面一段代码在Settings应用的WifiSettings类里发生在wpa_supplicant扫描ap结束时||result.capabilities.contains("[IBSS]")去掉即可支持adhoc

可见google是故意禁了ad hoc的功能。 那么总有原因 下面摘自某论坛

What you say is true - it is relatively easy to support ad-hoc networks. I also appreciate that it sucks if you have to rely on ad-hoc wifi and you own an Android device.
However, there are good reasons as to why Android, or any OS for that matter, doesn't support it.

Ad-hoc networks are inherently insecure as they require no authentication for people joining the network. Ad-hoc networks were only ever intended to be used for very short term spontaneous and informal networks. "Short term", in this context, means the time it takes you to purchase a proper wireless access point.

Ad-hoc networks are highly discouraged, as not only are they insecure, but they interfere with people using the proper, secure, and recommended, infrastructure WiFi networks.

These facts probably demotivated Google from implementing support for it.

As most broadband (Cable or ADSL) routers come with WiFi these days, and as a lot of the rest of us (like me) use stand-alone wireless access points, the requirement for Ad-Hoc support is low. Also, as the phones that run Android have 3G, Edge, and GPRS support the need is even lower for Android users. As such, you can probably see why Google didn't bother - there are other features that more people "require", and so Google probably concentrated on adding those.

 

TODO: 怎样创建ad hoc网络让其它设备连进来?

8.       wifi direct

Wifi direct又叫wifi p2p, 是一种新型的技术, 用来取代蓝牙, 具有速度快连接方便的特点。 不过目前Android2.3还并不支持, 但应该会很快有支持。 下面是一些资料。

http://wireless.kernel.org/en/developers/p2p

 

Android4.0已经支持wifi direct api已经导出。

9.       Soft ap支持

Ap可以为游戏应用提供联机对战的功能, 也可以基于软ap实现网络共享, 即连接到软Ap上的设备可以共享软Ap设备的网络, 比如手机可以作为软Ap 笔记本连进来就可以通过手机的3g上网。

支持soft ap当然首先要驱动支持, 初步调研结论是ar6k驱动可以支持soft ap 后续还需确认。

Android 2.2(froyo)开始支持soft ap 可以在Settings程序里设置soft ap功能, 如下图:

       但是我们在模拟器上并无上面的界面, 是在运行时会调用ConnectivityManager.isTetheringSupported()函数来判断系统是否支持Tethering 如果不支持Tethering就隐藏上面界面。

       开启Soft ap功能在Settings程序的WifiApEnabler. onPreferenceChange里, 设置soft apWifiApDialog.onClick里。它们依赖WifiManager的如下接口:

 

    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, booleanenabled)

    

    public int getWifiApState()

    

    public WifiConfiguration getWifiApConfiguration()

    

    public boolean setWifiApConfiguration(WifiConfiguration wifiConfig)

       WifiManager调用WifiService实现的功能, WifiService最终调用NetworkManagementService.startAccessPoint函数, 如下:

public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)

                                                                                      throwsIllegalStateException {

        mContext.enforceCallingOrSelfPermission(

                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");

        mContext.enforceCallingOrSelfPermission(

                android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");

        try {

            mConnector.doCommand(String.format("softap stop " + wlanIface));

            mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));

            mConnector.doCommand(String.format("softap start " + wlanIface));

            if (wifiConfig == null) {

                mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));

            else {

                

                String str = String.format("softap set " + wlanIface + " " + softapIface +

                                           " %s %s %s", convertQuotedString(wifiConfig.SSID),

                                           wifiConfig.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ?

                                           "wpa2-psk" : "open",

                                           convertQuotedString(wifiConfig.preSharedKey));

                mConnector.doCommand(str);

            }

            mConnector.doCommand(String.format("softap startap"));

        catch (NativeDaemonConnectorException e) {

            throw new IllegalStateException("Error communicating to native daemon to start softap", e);

        }

    }

 

       NetworkManagementService顾名思义是Android系统的网络管理服务, 负责比较特殊的网络的设置(比如网络共享(Tether)和网络地址转换(Nat)ip 转发(ip forwording))和向上层通知网络相关的事件。mConnector是一个NativeDaemonConnector 这里用来和系统的netd守护进程通信。NetworkManagementService的好多功能都是通过Netd实现的。 Netd的代码在“android sources/system/netd里。Netdsoftap控制的功能在“android sources/system/netd/SoftapController.{h,cpp}里, 是通过wireless extention定义的SIOCGIWPRIV来调用网卡驱动的ap功能。 如果具体网卡驱动提供的soft ap接口不同, SoftapController的代码就需要改。比如ar6k的驱动厂家提供了hostapd来控制ap 就需要改SoftapController来适配hostapd提供的接口。

10.   Wifi Tethering支持

Settings程序里看不到关于Wifi Tethering的任何代码, 着实让我迷惑了一下。 原来开启soft ap功能后就会自动启动wifi tethering com.android.server.connectivity.Tethering类向NetworkManagementService(NetworkManagementService通过netd来监听, netdnetlink socket监听内核热插拔事件)类注册了一个Observer来监听Interfaceadd remove change的信息。 当使能soft ap时, 会以soft ap模式加载驱动, 此时驱动会发出热插拔事件。 Tethering类里面跑了两种状态机, 一个TetherMasterSM nTetherInterfaceSM(每个tetherable interface对应一个) 添加Interface时就会启动一个TetherInterfaceSM状态机, 并进入Initial状态, 发出ConnectivityManager.ACTION_TETHER_STATE_CHANGED广播。 WifiService收到广播后调用ConnectivityService.tethering(inf)函数, TetherInterfaceSM发送CMD_TETHER_REQUESTED命令, 进入tethered状态。

UpstreamIface(比如现在不共享以太网而变为共享3g网络)发生变化时, TetherMasterSM会通知所有TetherInterfaceSM改变nat

TetherMasterSM初始阶段UpstreamIface的选择是根据从NetworkManagementServicem获得所有Ingerface,能匹配上com.android.internal.R.array.config_tether_upstream_regexs(base.core.res.res.values.configs中定义, 原始为空需要根据实际情况来改)的第一个状态为upinterface即被选为UpstreamIface

运行时UpstreamIface也可能变化, Tethering类监听ConnectivityManager.CONNECTIVITY_ACTION事件(当网络连接变化时由ConnectivityService发出) 当收到时给TetherMasterSMTetherMasterSM.CMD_UPSTREAM_CHANGED消息。 TetherMasterSM收到后重新选择UpstreamIface,并向所有TetherInterfaceSM发送TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED事件来用新的UpstreamIface重启Nat

Tethering原理如下:

NetworkManagementService.setIpForwardingEnabled(true)

NetworkManagementService.startTethering(mDhcpRange)// 启动dnsmasq(负责dhcpdns forwarding)

NetworkManagementService. setDnsForwarders(mDnsServers)//通过给dnsmasq发命令来设置dns服务器

NetworkManagementService.enableNat(String internalInterface, String externalInterface)//启动nat(网络地址转换)

11.   Usb Tethering支持

何谓usb tethering 这里举个例子, 我们的设备连上了wifi 此时将设备通过usb连接到pc pc即可以共享我们设备的wifi网络, 可以将我们的设备看做是一块usb接口的无线网卡。

Wifi Tethering从用户的角度来看是手动启动(通过Settings使能soft ap) 但从原理上看是自动启动, 使能soft apNetworkManagementService收到interfaceAdded信号后便自动启动wifi tethering

usb tethering则不同, 无论从用户的角度还是从原理的角度都是手动启动。 当设备通过usb连上pc时,NetworkManagementService会收到interfaceAdded信号。 不过并不能立刻开启tethering 因为连上pc的目的并不只有一个, 用户想要的可能是读写设备的sd卡。所以Usb Tethering会很关心Usb.ACTION_USB_STATEIntent.ACTION_MEDIA_SHAREDIntent.ACTION_MEDIA_UNSHARED事件。 只有当usb连上并且media unshared的情况下才可以usb tethering tethering过程中收到Intent.ACTION_MEDIA_SHARED Tethering类和WifiSettings类都会有相应的动作。

手动在Settings里启动UsbTethering时, 会调用ConnectivityService.Tethering(inf)函数开启usb tethering

原理如下:

NetworkManagementService.setIpForwardingEn cpRange)// 启动dnsmasq(负责dhcpdns forwarding)

NetworkManagementService.setDnsForwarders(mDnsServers)//通过给dnsmasq发命令来设置dns服务器

Tethering.configureUsbIface(true)//配置usb interface ip netmask up

Tethering.enableUsbRndis(true)//开启Usb Rndis(Remote Network Driver Interface Specification),使设备变成usb无线网卡

NetworkManagementService.enableNat(String internalInterface, String externalInterface)//启动nat(网络地址转换)abled(true)

NetworkManagementService.startTethering(mDh

另外补充一点,如果是Windows还需要安装usb tethering驱动才可以: http://www.android.com/tether

12.   Reverse usb Tethering

何谓Reverse usb Tetheringusb Tetheringpc可以通过我们的设备上网,  Reverse usb Tethering是设备可以通过Pc上网, 只要usb线连上pc

目前Android不支持, Framework只改Settings程序应该就可以添加支持, 在驱动层也需要支持, 可能只是编译内核时打开某些选项而已, 待确定。

未完待续……

13.   Ethernet Tethering

所谓Ethernet Tethering Pc机通过网线连接到设备时即可共享设备的wifi3g网络。

目前Android不支持,有线网卡connected3gwifi都会禁掉。

14.   需要改动的地方

针对5201平台(ar6k驱动) 我们需要对framework做如下修改。

 

基本:

android sources\hardware\libhardware_legacy\wifi\wifi.c:驱动名称

l         Adhoc支持:

Settings应用的WifiSettings类:将隐藏adhoc网络的代码去掉

l         Softap支持:

android sources/system/netd/SoftapController.{h,cpp}:适配到hostapd

android sources\hardware\libhardware_legacy\wifi\wifi.c:驱动的参数决定模式(ap or station)

com.android.server.connectivity: ip default dns

l         Wifi Tethering支持:

base.core.res.res.values.configs 根据平台实际情况修改config_tether_upstream_regexsarray.config_tether_wifi_regexs,  array.config_tether_usb_regexs

l         Usb Tethering支持:

base.core.res.res.values.configs:根据平台实际情况修改array.config_tether_usb_regexs

15.   测试

驱动的测试可以借助工具比如wpa_cli 当我们改好framework代码后, 怎样确保它能工作呢?Android framework针对ConnectivityManagerWifiManager的单元测试,位于core.test.ConnectivityManagerTest中,  都是依赖于真实硬件的, 模拟器做不了。 当我们改了代码后, 可以运行这些单元测试来确保我们的改动。

运行WifiConnectionTest命令:

adb shell am instrument -e class  \

     com.android.connectivitymanagertest.functional.WifiConnectionTest  \

-w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner

       运行WifiSoftAPTest命令:

adb shell am instrument \

-w com.android.connectivitymanagertest/.ConnectivityManagerUnitTestRunner

    详情看代码。

16.   调试中遇到的问题

系统中多个Dhcpcd进程存在, 经查是setproperty(“ctl.stop”, “dhcpcd_eth0”)不能停掉Dhcpcd进程, 以至于下次启动时又会创建新的Dhcpcd进程。 最后发现是启动dhcp参数问题导致,应用-B参数不让dpcp以daemon形式运行即可。

 

posted on 2012-10-26 14:12  nanjing  阅读(3556)  评论(0编辑  收藏  举报

导航