android wifi工作流程

http://blog.csdn.net/hxh19871987/article/details/7320839

Wifi 网卡状态

1.    WIFI_STATE_DISABLED: WIFI网卡不可用

2.    WIFI_STATE_DISABLING: WIFI正在关闭

3.    WIFI_STATE_ENABLED:WIFI网卡可用

4.    WIFI_STATE_ENABLING:WIFI网卡正在打开

5.    WIFI_STATE_UNKNOWN:未知网卡状态

 

WIFI 访问网络需要的权限

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE">

</uses-permission>修改网络状态的权限

<uses-permission

android:name="android.permission.CHANGE_WIFI_STATE">

</uses-permission>修改WIFI状态的权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">

</uses-permission>访问网络权限

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE">

</uses-permission>访问WIFI权限

 

WIFI 核心模块

n  WifiService

由SystemServer启动的时候生成的ConnecttivityService创建,负责启动关闭wpa_supplicant,启动和关闭WifiMonitor线程,把命令下发给wpa_supplicant以及跟新WIFI的状态

n  WifiMonitor

  负责从wpa_supplicant接收事件通知

n  Wpa_supplicant

1、读取配置文件

2、初始化配置参数,驱动函数

3、让驱动scan当前所有的bssid

4、检查扫描的参数是否和用户设置的想否

5、如果相符,通知驱动进行权限 认证操作

6、连上AP

n  Wifi驱动模块

厂商提供的source,主要进行load firmware和kernel的wireless进行通信

n  Wifi电源管理模块

主要控制硬件的GPIO和上下电,让CPU和Wifi模组之间通过sdio接口通信

 

Wifi工作步骤

n  Wifi模块初期化

n  Wifi启动

n  查找热点(AP)

n  配置AP

n  配置AP参数

n  Wifi连接

n  IP地址配置

 

Wifi模块代码总结

n  Wifi Application代码

packages/apps/Settings/src/com/android/settings/wifi

n  Wifi Framework

frameworks/base/wifi/java/android/net/wifi

frameworks/base/services/java/com/android/server

n  Wifi JNI

frameworks/base/core/jni/android_net_wifi_Wifi.cpp

n  Wifi Hardware

hardware/libhardware_legacy/wifi/wifi.c

n  Wifi tool

external/wpa_supplicant

n  Wifi kernel

net/wireless     drivers/wlan_sd8688       arch/arm/mach-pxa/wlan_pm.c

 

Wifi模块的初始化:

在 SystemServer 启动的时候,会生成一个ConnectivityService 的实例, ConnectivityService 的构造函数会创建WifiService,WifiStateTracker 会创建WifiMonitor 接收来自底层的事件,WifiService 和WifiMonitor 是整个模块的核心。WifiService 负责启动关闭wpa_supplicant、启动关闭WifiMonitor 监视线程和把命令下发给wpa_supplicant,而WifiMonitor 则负责从wpa_supplicant 接收事件通知。

android wifi工作流程_第1张图片

 

Wifi模块的启动:

WirelessSettings 在初始化的时候配置了由WifiEnabler 来处理Wifi 按钮,

当用户按下Wifi 按钮后,Android 会调用WifiEnabler 的onPreferenceChange,再由WifiEnabler调用WifiManager 的setWifiEnabled 接口函数,通过AIDL,实际调用的是WifiService 的setWifiEnabled 函数,WifiService 接着向自身发送一条MESSAGE_ENABLE_WIFI 消息,在处理该消息的代码中做真正的使能工作:首先装载WIFI 内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ), 然后启动wpa_supplicant ( 配置文件硬编码为"/data/misc/wifi/wpa_supplicant.conf"),再通过WifiStateTracker 来启动WifiMonitor 中的监视线程。

 

android wifi工作流程_第2张图片

android wifi工作流程_第3张图片

查找热点(AP):

(Wifi开启)中讲到Wifi模块开启后会对外发送WIFI_STATE_CHANGED_ACTION。WifiLayer中注册了Action的Receiver。当WifiLayer收到此Action后开始scan的流程,具体如下

android wifi工作流程_第4张图片

当wpa_supplicant 处理完SCAN 命令后,它会向控制通道发送事件通知扫描完成,从wifi_wait_for_event 函数会接收到该事件,由此WifiMonitor 中的MonitorThread 会被执行来出来这个事件:

android wifi工作流程_第5张图片

配置 AP 参数:

当用户在 WifiSettings 界面上选择了一个AP 后,会显示配置AP 参数的一个对话框:

android wifi工作流程_第6张图片

 

Wifi连接:

 

android wifi工作流程_第7张图片

 

IP地址的配置:

android wifi工作流程_第8张图片

 

 

android wifi工作流程_第9张图片


首先交代开发环境——硬件平台:高通MSM8225,OS:Android2.3.5,无线模块:brodcom BCM4330。

一、WIFI:

      首先保证上好电:在platform/kernel/arch/arm/mach-msm/board-msm7x30.c中实现GPIO管脚的配置,也要配置好休眠唤醒的脚。再就是在板级__init里面配置好WIFI的上电以及下电时序问题,还有因为我们的无线芯片是基于SDIO进行通讯的,所以SDIO的driver也要配置好。

       再就是WIFI本身的驱动的开发了,我们是用博通公司提供的代码,在dhd_custemer_gpio.c中修改好相应的Power_en和reset脚的配置,然后配置wlan linux相关的驱动。最终编译生成dhd.ko文件。

        这个dhd.ko文件和nvram.txt以及sdio.bin文件共同加载了wlan0的驱动。在中间层有一个hardware/library_lib/wifi/wifi.c,就是把一些配置文件的加载,DHCP文件的文件路径等等综合在一起。

         在wifi移植过程中一定要注意MAC地址的有效性和可用性。这样才能连接热点已经被分配到IP地址。

二、Bluetooth:

        首先还是和wifi一样,上电是必须的!在platform/kernel/arch/arm/mach-msm/board-msm7x30.c中实现bluetooth_power_init,注意是在参数初始化的函数__init msm7x30_init函数中完成。

        由于BT的协议层,在开发的时候基本不用动什么,所以我们直接找跟芯片相关的文件进行修改。brodcom BT相关的文件在system/bluetooth/brcm_patchram_plus/

brcm_patchram_plus.c 中,里面主要完成了如下事件:1、读取BT的地址。2、执行parse相关命令。3、重启HCI服务,4、设置蓝牙通信的波特率。5、设置hci_pcm

        再就是开启BT的服务。目录在system/core/rootdir/A1/etc/init.qcom.bt.sh 中,实现start_hciattach和kill_hciattach的功能。


网上关于BT的驱动很少,所以我在开发过程中把其中的步骤记录下来。供大家相互学习讨论。


一、关于BT driver的移植:


1. Enablebluetootch in BoadConfig.mk

       BOARD_HAVE_BLUETOOTH := true


2.实现BT电源管理rfkill驱动。

Kernel/driver/bluetooth/bluetooth-power.c    高通的这个文件基本上不用动。

在kernel\arch\arm\mach_msm7x27.c: static int bluetooth_power(int on)中

实现:上电:把bt_reset pin 和bt_reg_on pin 拉低

                mdelay(10);

              把bt_resetpin 和bt_reg_on pin 拉高

              mdelay(150)

      下电:把bt_reset pin 和bt_reg_on pin 拉低       

 

3. RebuildAndroid image and reboot

命令行测试:

echo 0 >/sys/class/rfkill/rfkill0/state   //BT下电

echo 1 >/sys/class/rfkill/rfkill0/state   //BT上电

brcm_patchram_plus-d --patchram /etc/firmware/BCM4329B1_002.002.023.0061.0062.hcd/dev/ttyHS0

hciattach -s115200 /dev/ttyHS0 any

没任何错误提示是可以用以下测试

hciconfig hci0up

hcitool scan

 

4.实现BT睡眠唤醒机制

Kernel\drivers\bluetooth\bluesleep.c一般来说这个文件改动比较少,但可能逻辑上会有些问题。需要小的改动。

在kernel\arch\arm\mach_xxx/board_xxx.c:bluesleep_resources中定义gpio_host_wake(BT唤醒host脚)、gpio_ext_wake(host唤醒BT脚)、host_wake(BT唤醒host的中断号)。

注:各个平台的board_xxx.c文件名字不同,请客户确认 


5.系统集成

1)在init.qcom.rc中确认有下面的内容:

service hciattach/system/bin/sh /system/etc/init.qcom.bt.sh

    user bluetooth

    group qcom_oncrpc bluetooth net_bt_admin

    disabled

    oneshot

 

2)修改init.qcom.bt.sh

确认有:

BLUETOOTH_SLEEP_PATH=/proc/bluetooth/sleep/proto

echo 1 >$BLUETOOTH_SLEEP_PATH

/system/bin/hciattach-n /dev/ttyHS0 any 3000000 flow & 改为:

./brcm_patchram_plus--enable_lpm –enable_hci --patchram /system/etc/wifi/BCM4329BT.hcd --baudrate3000000 /dev/ttyHS0 &

注掉:高通下载firmware的命令。

 

6.重新编译system。此时BT应该能运行了。


二、BT的休眠唤醒配置


BT的休眠在driver/bluetooth/bluesleep.c中,首先驱动的名字叫“bluesleep”与arch/arm/mach-msm/board-msm7x30.c相匹配就执行platform_driver_probe(&bluesleep_driver, bluesleep_probe)然后调用static int __init bluesleep_probe(struct platform_device *pdev),这里会配置两个引脚HOST_WAKE_BT & BT_WAKE_HOST 

bsi = kzalloc(sizeof(struct bluesleep_info), GFP_KERNEL);
        if (!bsi)
                return -ENOMEM;

        res = platform_get_resource_byname(pdev, IORESOURCE_IO,
                                "gpio_host_wake");
        if (!res) {
                BT_ERR("couldn't find host_wake gpio\n");
                ret = -ENODEV;
                goto free_bsi;
        }
        bsi->host_wake = res->start;
        //[SIMT-zhangmin-111230] change the configuration of BT sleep gpio from bt_power to here {
        gpio_tlmm_config(GPIO_CFG(bsi->host_wake, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),GPIO_CFG_ENABLE);
        //[SIMT-zhangmin-111230] }
        ret = gpio_request(bsi->host_wake, "bt_host_wake");
        if (ret)
                goto free_bsi;
        ret = gpio_direction_input(bsi->host_wake);

 bsi->host_wake_irq = platform_get_irq_byname(pdev, "host_wake");

如上代码所示,主要将HOST_WAKE_BT设置为输出脚,BT_WAKE_HOST 设置为输入脚并也设置为中断脚,等待BT芯片的唤醒。

然后再bluesleep_init函数中建立BT目录/proc/bluetooth/sleep/读btwake中HOST_WAKE_BT的状态。读出的状态值为0或1。

或在BT目录/proc/bluetooth/sleep/写btwake中HOST_WAKE_BT的状态。写出状态值为0或1。


 Part 1 
问:打开wifi,连接wifi热点,提示连接成功,但headbar上不显示wifi图标,back退出wifi设置,再进入,提示wifi已断开。
答:首先现象复现,当现象复现时进入adb shell,然后输入ifconfig 查看是否有wlan0 端口,然后在adb shell 中ping 192.168.1.101(嵌入式设备的IP),如果能Ping通则说明底层wifi设备与AP是连接通的。所以把问题转向上层。上层在frameworks/base/services/java/com/android/server/ConnectivityService.java文件中查看private void handleDisconnect(NetworkInfo info)函数的实现,问题可能出现在这里。
Part 2
问:出现新热点,需要重启WIFI才可以扫描到。
问:20s内无法连接到WIFI热点。
问:已连接的热点关闭,不会自动连接下一个热点。
答:这些问题都是供应商芯片的firmware没有配置好,所以直接找FAE换掉。
Part 3
问:调试中如果遇到dhd_sdio_probe fail 。
问:发现sdio register timeout 。
答:因为我们用到的WIFI数据通道是SDIO接口,所以要在log信息中查看sdcard是否有加载。没加载的话就看看WIFI芯片的上电(如WIFI_REG_ON这个PIN脚)。
Part 4
问:如果在wifi的设置里面选中wifi选项出现ERRO(或错误)的提示。
答:首先在adb shell中lsmod查看.ko文件是否已经加载。如没加载cat /proc/kmsg查看是否是版本匹配的问题。如遇版本匹配则在kernel/scripts/setlocalversion中将echo “+”中去掉。如果顺利加载了驱动,则要看看MAC地址是否有,并且是否合理。
Part 5
问:发现在WIFI设置选项中有已经选上了wifi并且勾应打上了,过一会出现wifi的勾自动消失。
答:这种情况在adb shell中用ifconfig查看Wlan的接口用的是否是wlan0,有可能是eth0。如果是eth0则在hardware/libhardware_legacy/wifi/wifi.c中的#define WIFI_DRIVER_MODULE_ARG  "firmware_path=/system/etc/firmware/wlan/sdio.bin nvram_path=/data/simcom/nvram.txt iface_name=wlan0" 中查看iface_name=wlan0是否已经加上。
Part 6
问:有的路由器不能扫描的到。
答:查看wlan的设置的channel是否在1-14这个频段,因为如果wlan设置成USA模式则channel的范围在1-11之间,channel 12,13,14就不会收索的到。所以要在nvram.txt中修改成ccode=ALL,并且在gqcom_cfg.ini中把APCntryCode=ALL。这样应该就可以扫描到所有的channel了。当然如果上层还是没有收索到的话,在Settings.java中也要做相应的修改。
常用的命令:wl channels_in_country
wl chanlist
wl channels

wl country

Part 7

问:【预置条件】:wifi 已连接 wifi sleep policy模式为When screen turns off
        【操作步骤】:wifi连接网络,静置屏幕熄灭 大约5分钟,再次点亮屏幕
        【测试结果】:wifi一直处在scanning状态,无法连接网络,关闭再打开恢复正常
        【预期结果】:点亮屏幕后,wifi自动连接成功
答:调试分析记录:
1.在frameworks/base/services/java/com/android/server/WifiService.java中修改LCD灭屏后关掉WIFI的时间长短,由以前的2分钟修改为现在的1秒钟。
结果是短时间休眠后唤醒可以顺利连上AP,但经过长时间休眠(如15分钟)后唤醒机器还是无法连接AP。
2.检查Kernel中POWER_ON使能脚,看是否有其它地方被占用过,结果是屏蔽所有其它用到过该脚的代码还是无用。
3.检查CP侧代码,将CP侧POWER_ON引脚由以前的某种特殊功能设置成普通的Output模式,然后AP就可以自由的控制其高低电平了。
修改后的结果还是以无效告终。
4.检查external/wpa_supplicant_6/wpa_supplicant/文件夹下面的代码,检查WEXT驱动代码。结果还是失败。
5.最后在机器休眠15分钟后,用底层命令行来scan、连接等动作的操作,结果根本无法扫描到AP。故把问题集中在驱动底层。经过修改dhd.ko、sdio.bin文件
现在此Bug终于得解。

6.也有问题不出现在驱动dhd.ko文件中,可能出现在mmc驱动中的sdio通道。在函数mmc_pm_notify中当出现PM_POST_SUSPEND或PM_POST_HIBERNATION的情况时就有可能移除掉了sdio通道,所以函数mmc_detect_change(host, 0)要加一个判断,当sdio作为wifi通道时就不能移除。移除后的后果就是此Bug。


你可能感兴趣的:(wifi,frameworks)