3系统启动后的 wifi 加载过程
============================ Wifi 启动代码流程 ====================
1、系统启动 首先加载init.rc,这个文件 会加载所有service,init是linux启动的 第一个 用户空间 的应用(属于linux进程,不属于Android应用)。
2、init.rc里有以下这句话:
Service wpa_supplicant /system/bin/wpa_supplicant –Dwext –iwlan0 –d –c /data/misc/wifi/wpa_supplicant.conf
3、加载linux内核模块/system/lib/modules/wlan.ko 这个wifi模块定义在/hardware/libhardware_legacy/wifi/wifi.c
4、在 SystemServer 启动的时候, 会生成一个 ConnectivityService 的实例 ,
ConnectivityService 的 构造函数 会创建 WifiService,
看看是怎么启动WiFi Service的:
if (DBG) Log.v(TAG, "Starting Wifi Service.");
mWifiStateTracker = new WifiStateTracker(context, handler);
WifiService wifiService = new WifiService(context, mWifiStateTracker);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
WifiStateTracker 会创建 WifiMonitor 接收 来自 底层 的事件, WifiService 和 WifiMonitor 是整个模块的核心 。WifiService 负责 启动关闭 wpa_supplicant、启动关闭 WifiMonitor监视线程 和把 命令下发 给 wpa_supplicant, 而WifiMonitor 则负责从 wpa_supplicant 接收 事件通知。它们与本地库的连接都是通过JNI方法,具体实现方法在android_net_wifi_Wifi.cpp中,在这个文件中可以大致看出APP会给wpa_supplicant下哪些命令。这些命令通过wifi.c的wifi_command发送给wpa_supplicant,在发送命令的过程中实际是调用wpa_ctrl_request来完成命令发送的,wpa_ctrl_request是通过socket的方式与wpa_supplicant进行通信的,然后通过wpa_ctrl_recv来接收来自wpa_supplicant的命令,并返回标识给wifi_wait_for_event。
--------------------------------------
流程图对应的源代码路径为:
WifiEnabler,WifiSettings对应的路径如下:
rootfs/packages/apps/Settings/src/com/android/settings/wifi/
WifiManager,WifiMonitor,WifiStateTracker,WifiNative.对应的源代码路径如下:
rootfs/frameworrks/base/wifi/java/android/net/wifi/
WifiService 对应代码的位置
rootfs/frameworks/base/services/java/com/android/server/
android_net_wifi_Wifi源代码路径如下:
rootfs/frameworks/base/core/jni/
wifi_command,wifi_wait_for_envent源代码路径如下:
/hardware/libhardware_legacy/wifi/wifi.c
wpa_ctrl_源代码路径如下:
rootfs/external/wpa_supplicant/wpa_ctrl.c
wpa_supplicant源代码路径如下:
rootfs/external/wpa_supplicant/
WIFI启动流程图:
Wireless Settings 在初始化的时候配置了由 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 中的 监视线程。
代码如下:
WifiService.java (frameworks/base/services/java/com/android/server)调用 setWifiEnabled()里面的sendEnableMessage(enable, true, Binder.getCallingUid());来发送一则消息
Message msg = Message.obtain(mWifiHandler, (enable? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),(persist ? 1 : 0), uid);
msg.sendToTarget();发送给自身的消息。
当enable 的时候 会调用setWifiEnabledBlocking这个函数,这个函数会做setWifiEnabledState ,然后做四件事:
1. 调用JNI的WifiNative.loadDriver -->加载 Wifi驱动
2. 调用JNI的WifiNative.startSupplicant -->启动wifi_start_supplicant
3. 启动 event loop.
4. 更新wifi的状态
成功启动wifi之后 setWifiEnabledBlocking 运行mWifiStateTracker.startEventLoop();事件循环,来监视事件mWifiMonitor.startMonitoring(); MonitorThread().start() 一直在线程里循环调用WifiNative.waitForEvent();
当 使能 成功后, 会广播发送
WIFI_STATE_CHANGED_ACTION 这个 Intent 通知外界 WIFI已 经 成功能了。WifiEnabler创 建 的 时 候 就 会 向 Android 注册 接收WIFI_STATE_CHANGED_ACTION, 因此它会收到该 Intent, 从而开始扫描。
二、 查找 AP
扫描的入口函数是 WifiService 的 startScan, 它其实也就是 往 wpa_supplicant 发送 SCAN 命令。
当 wpa_supplicant 处理完 SCAN 命令后, 它会向 控制通道 发送 事件 通知 扫描完成, 从而 wifi_wait_for_event函数会接收到该事件, 由此 WifiMonitor 中的 MonitorThread 会被执行来 处理 这个事件。对每一个扫描返回的 AP, WifiLayer 会调用
WifiSettings 的 onAccessPointSetChanged 函数, 从而最终把该 AP 加到 GUI 显示列表中。
三、配置 AP 参数
当用户在 WifiSettings 界面上选择了一个 AP 后,会显示配置 AP 参数的一个对话框,此对话框会显示当前选择的AP信号强度,若此AP设置了密码则需要用户输入密码才能登录。用户配置好之后,点击
连接按钮,onClick函数会被调用。
四、连接
当用户在 AcessPointDialog 中 选择好 加密方式 和 输入密钥 之后,再点击 连接按钮, Android就会去连接这个 AP。
WifiLayer 会先检测这个 AP 是不是之前被配置过, 这个是通过 向 wpa_supplicant 发送 LIST_NETWORK 命令 并且比较 返回值 来实现的,
// Need WifiConfiguration for the AP
WifiConfiguration config = findConfiguredNetwork(state);
如果 wpa_supplicant 没有这个 AP 的配置信息, 则会向 wpa_supplicant 发送 ADD_NETWORK 命令来添加该 AP,
if (config == null)
{
// Connecting for the first time, need to create it
config = addConfiguration(state, ADD_CONFIGURATION_ENABLE|ADD_CONFIGURATION_SAVE);
}
ADD_NETWORK 命令 会返回一个 ID , WifiLayer 再用这个返回的 ID 作为 参数 向wpa_supplicant 发送 ENABLE_NETWORK 命令,从而让 wpa_supplicant 去连接该 AP。
五、配置 IP 地址
当 wpa_supplicant 成功连接上 AP 之后, 它会向 控制通道 发送 事件通知连接上 AP 了,
wifi.c的wifi_wait_for_event函数阻塞调用,从而 wifi_wait_for_event 函数会 接收 到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行来 处理 这个事件,
WifiMonitor 再调用 WifiStateTracker 的 notifyStateChange, WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息 来 启动 DHCP 去获取 IP 地址, 然后再广播发送NETWORK_STATE_CHANGED_ACTION
这个 Intent, 最后由 WifiSettings类来响应,改变状态和界面信息。
注意:wpa_ctrl_request,通过socket方式向wpa_supplicant发送命令,以select模式阻塞在wpa_supplicant发送和接收。