Android Wifi的工作流程

2019-04-13 17:03发布

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 访问网络需要的权限 "android.permission.CHANGE_NETWORK_STATE"> 修改网络状态的权限   android:name="android.permission.CHANGE_WIFI_STATE"> 修改WIFI状态的权限 "android.permission.ACCESS_NETWORK_STATE"> 访问网络权限 "android.permission.ACCESS_WIFI_STATE"> 访问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接收事件通知。   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 中的监视线程。   查找热点(AP): (Wifi开启)中讲到Wifi模块开启后会对外发送WIFI_STATE_CHANGED_ACTION。WifiLayer中注册了Action的Receiver。当WifiLayer收到此Action后开始scan的流程,具体如下 当wpa_supplicant 处理完SCAN 命令后,它会向控制通道发送事件通知扫描完成,从wifi_wait_for_event函数会接收到该事件,由此WifiMonitor 中的MonitorThread 会被执行来出来这个事件: 配置 AP 参数: 当用户在 WifiSettings 界面上选择了一个AP 后,会显示配置AP 参数的一个对话框:   Wifi连接:     IP地址的配置:    
  首先交代开发环境——硬件平台:高通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脚的配置,然后配置wlanlinux相关的驱动。最终编译生成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,注意是在参数初始化的函数__initmsm7x30_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   高通的这个文件基本上不用动。 在kernelarcharmmach_msm7x27.c: static int bluetooth_power(inton)中 实现:上电:把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睡眠唤醒机制 Kerneldriversluetoothluesleep.c一般来说这个文件改动比较少,但可能逻辑上会有些问题。需要小的改动。 在kernelarcharmmach_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     userbluetooth     groupqcom_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(structplatform_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_wakegpio ");
              ret =-ENODEV;
              gotofree_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)
              gotofree_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中ping192.168.1.101(嵌入式设备的IP),如果能Ping通则说明底层wifi设备与AP是连接通的。所以把问题转向上层。上层在frameworks/base/services/java/com/android/server/ConnectivityService.java文件中查看privatevoid 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的勾自动消失。
答:这种情况在adbshell中用ifconfig查看Wlan的接口用的是否是wlan0,有可能是eth0。如果是eth0则在hardware/libhardware_legacy/wifi/wifi.c中的#defineWIFI_DRIVER_MODULE_ARG "firmware_path=/system/etc/firmware/wlan/sdio.binnvram_path=/data/simcom/nvram.txt iface_name=wlan0"中查看iface_name=wlan0是否已经加上。
Part 6
问:有的路由器不能扫描的到。
答:查看wlan的设置的channel是否在1-14这个频段,因为如果wlan设置成USA模式则channel的范围在1-11之间,channel12,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 turnsoff
       【操作步骤】: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。