网上对android WiFi源码解读的帖子也有不少,但大部分是android 2.3左右。最近研究了下android4.0 的WiFi源码,发现跟2.3的还是相差蛮大的,所以在此记录下,以便跟大家一起分享,探讨。
本文主要讨论的类及相关位置如下:
02 | packages/apps/Settings/src/com/android/settings/wifi |
03 | (WifiEnabler.java、WifiSetting.java) |
06 | frameworks/base/services/java/com/android/server |
07 | (SystemServer.java、WifiService.java) |
10 | frameworks/base/wifi/java/android/net/wifi |
11 | (IWifiManager.aidl、WifiManager.java、WifiStateMachine.java、WifiNative.java) |
12 | frameworks/base/services/java/com/android/server |
15 | frameworks/base/core/jni/android_net_wifi_Wifi.cpp |
18 | hardware/libhardware_legacy/wifi/wifi.c |
1、从SystemServer.java说起,系统刚启动时,怎么启动wifi服务的
01 | classServerThreadextendsThread { |
02 | privatestaticfinalString TAG ="SystemServer"; |
07 | wifi =newWifiService(context); |
08 | ServiceManager.addService(Context.WIFI_SERVICE, wifi); |
10 | connectivity =newConnectivityService( |
11 | context, networkManagement, networkStats, networkPolicy); |
12 | ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); |
13 | wifi.checkAndStartWifi(); |
15 | location =newLocationManagerService(context); |
16 | ServiceManager.addService(Context.LOCATION_SERVICE, location); |
20 | publicclassSystemServer { |
21 | privatestaticfinalString TAG ="SystemServer"; |
22 | nativepublicstaticvoidinit1(String[] args); |
24 | publicstaticvoidmain(String[] args) { |
25 | System.loadLibrary("android_servers"); |
28 | publicstaticfinalvoidinit2() { |
29 | Slog.i(TAG,"Entered the Android system server!"); |
30 | Thread thr =newServerThread(); |
31 | thr.setName("android.server.ServerThread"); |
在SystemThread中通过ServiceManager.addService()会添加注册各种服务(wifi、location、connectivity、bluetooth、、)
其 中ConnectivityService连接服务,它跟所有手机的无线通信都有联系,包括wifi,蓝牙,2g网络,3g网络等。然后 SystemServer会加载"android servers"的本地库(位于/frameworks/base/cmds/system server/library),其中会调用init2方法启动SystemThread。
系统启动时就完成以上动作,当所有服务正常启动后,系统就开始做好运行新的应用程序的准备。
2、再到手机设置界面开启Wifi
进入wifi设置界面,相关文件WifiSettings.java
开启Wifi的组件是一个CompoundButton,跟它关联起来的是一个WifiEnabler.java类,它是在WifiSettings里面初始化的
1 | publicvoidonActivityCreated(Bundle savedInstanceState) { |
2 | mWifiEnabler =newWifiEnabler(activity, actionBarSwitch); |
当用户点击wifi的开启按钮时候,会触发WifiEnabler里面的onCheckedChanged函数
1 | publicvoidonCheckedChanged(CompoundButton buttonView,booleanisChecked) { |
3 | if(mWifiManager.setWifiEnabled(isChecked)) { |
4 | mSwitch.setEnabled(false); |
6 | Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show(); |
在onCheckedChanged函数里面,调用了WifiManager的setWifiEnabled方法
1 | publicbooleansetWifiEnabled(booleanenabled) { |
3 | returnmService.setWifiEnabled(enabled); |
4 | }catch(RemoteException e) { |
它返回的是mService.setWifiEnabled(enabled),这里的mService是WifiService的代理,所以它实际调用的是wifiService里面的setWifiEnabled函数
1 | publicclassWifiServiceextendsIWifiManager.Stub |
我们可以看到WifiService继承一个接口IWifiManager.Stub,凡是继承了像这种形式写法的接口服务,都可以进行远程调用,这就是Android内部的aidl通信。接下来进入wifiservice
1 | publicsynchronizedbooleansetWifiEnabled(booleanenable) { |
3 | mWifiStateMachine.setWifiEnabled(enable); |
可以看到,又进入WifiStateMachine的setWifiEnabled方法,mWifiStateMachine是在Wifiservice的构造函数完成初始化 的
1 | WifiService(Context context) { |
3 | mWifiStateMachine =newWifiStateMachine(mContext, mInterfaceName); |
在android4.0中的Wifi启动过程中,WifiStateMachine是一个非常重要的类,下面我们介绍一个这个类。
WifiStateMachine继承了StateMachine这个类,它是一个wifi状态机,其中包含了好多状态:DefaultState、
InitialState、DriverLoadingState、DriverLoadedState、DriverUnloadingState、DriverUnloadedState、DriverFailedState。每种状态都有enter()、exit()、processMessage()3个函数,分别处理进入该状态,退出该状态的动作,以及消息处理。
关于WifiStateMachine详细的解读参考:
01 | publicclassWifiStateMachineextendsStateMachine { |
03 | publicWifiStateMachine(Context context, String wlanInterface) { |
04 | addState(mDefaultState); |
05 | addState(mInitialState, mDefaultState); |
06 | addState(mDriverUnloadingState, mDefaultState); |
07 | addState(mDriverUnloadedState, mDefaultState); |
08 | addState(mDriverFailedState, mDriverUnloadedState); |
09 | addState(mDriverLoadingState, mDefaultState); |
10 | addState(mDriverLoadedState, mDefaultState); |
11 | addState(mSupplicantStartingState, mDefaultState); |
12 | addState(mSupplicantStartedState, mDefaultState); |
13 | addState(mDriverStartingState, mSupplicantStartedState); |
14 | addState(mDriverStartedState, mSupplicantStartedState); |
15 | addState(mScanModeState, mDriverStartedState); |
16 | addState(mConnectModeState, mDriverStartedState); |
17 | addState(mConnectingState, mConnectModeState); |
18 | addState(mConnectedState, mConnectModeState); |
19 | addState(mDisconnectingState, mConnectModeState); |
20 | addState(mDisconnectedState, mConnectModeState); |
21 | addState(mWaitForWpsCompletionState, mConnectModeState); |
22 | addState(mDriverStoppingState, mSupplicantStartedState); |
23 | addState(mDriverStoppedState, mSupplicantStartedState); |
24 | addState(mSupplicantStoppingState, mDefaultState); |
25 | addState(mSoftApStartingState, mDefaultState); |
26 | addState(mSoftApStartedState, mDefaultState); |
27 | addState(mTetheredState, mSoftApStartedState); |
28 | addState(mWaitForP2pDisableState, mDefaultState); |
30 | setInitialState(mInitialState); |
34 | //start the state machine |
在进入WifiStateMachine的初始状态为:setInitialState(mInitialState),下面是InitialState类:
01 | classInitialStateextendsState { |
04 | if(WifiNative.isDriverLoaded()) { |
05 | transitionTo(mDriverLoadedState); |
08 | transitionTo(mDriverUnloadedState); |
这里通过WifiNative.isDriverLoaded()判断wifi的驱动是已经加载,如果加载就将状态转到mDriverLoadedState,不然将状态转到mDriverUnloadedState。WifiNative这个类稍微讲解。
下面回到:mWifiStateMachine.setWifiEnabled(enable);
1 | publicvoidsetWifiEnabled(booleanenable) { |
3 | sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING,0)); |
4 | sendMessage(CMD_START_SUPPLICANT); |
6 | sendMessage(CMD_STOP_SUPPLICANT); |
7 | sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED,0)); |
不管enble为何值,都会向状态机发送两个消息,一个是load/unload wifi驱动,一个是start/stop配置文件。由于从WifiService进入WifiStateMachine时,构造函数先进入了 InitialState状态,由于最开始wifi驱动是没有加载的,所以mDriverUnloadedState,
01 | classDriverUnloadedStateextendsState { |
03 | publicbooleanprocessMessage(Message message) { |
04 | switch(message.what) { |
06 | mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING); |
07 | transitionTo(mWaitForP2pDisableState); |
09 | caseWifiP2pService.P2P_ENABLE_PENDING: |
10 | mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED); |
这里处理了刚才setWifiEnabled发送的消息CMD_LOAD_DRIVER;然后转向mWaitForP2pDisableState;
01 | classWaitForP2pDisableStateextendsState { |
03 | publicbooleanprocessMessage(Message message) { |
04 | if(DBG) log(getName() + message.toString() +"\n"); |
05 | switch(message.what) { |
06 | caseWifiP2pService.WIFI_ENABLE_PROCEED: |
07 | //restore argument from original message (CMD_LOAD_DRIVER) |
08 | message.arg1 = mSavedArg; |
09 | transitionTo(mDriverLoadingState); |
12 | caseCMD_UNLOAD_DRIVER: |
13 | caseCMD_START_SUPPLICANT: |
14 | caseCMD_STOP_SUPPLICANT: |
17 | deferMessage(message); |
然后继续转到状态mDriverLoadingState;
01 | classDriverLoadingStateextendsState { |
04 | newThread(newRunnable() { |
08 | switch(message.arg1) { |
09 | caseWIFI_STATE_ENABLING: |
10 | setWifiState(WIFI_STATE_ENABLING); |
12 | caseWIFI_AP_STATE_ENABLING: |
13 | setWifiApState(WIFI_AP_STATE_ENABLING); |
17 | if(WifiNative.loadDriver()) { |
18 | if(DBG) log("Driver load successful"); |
19 | sendMessage(CMD_LOAD_DRIVER_SUCCESS); |
21 | loge("Failed to load driver!"); |
完成两个动作1、 setWifiState(WIFI_STATE_ENABLING);2、WifiNative.loadDriver();
下面讲解WifiNative。
01 | publicclassWifiNative { |
03 | publicnativestaticbooleanloadDriver(); |
05 | publicnativestaticbooleanisDriverLoaded(); |
07 | publicnativestaticbooleanunloadDriver(); |
09 | publicnativestaticbooleanstartSupplicant(); |
在WifiNative中的函数有好大一部分都是native函数,熟悉android JNI的同学都知道,这些函数的实现都在本地实现。
这些函数的实现都在/frameworks/base/core/jni目录下的 android_net_wifi_Wifi.cpp中。
01 | staticjboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject) |
03 | return(jboolean)(::is_wifi_driver_loaded() == 1); |
06 | staticjboolean android_net_wifi_loadDriver(JNIEnv* env, jobject) |
08 | return(jboolean)(::wifi_load_driver() == 0); |
11 | staticjboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject) |
13 | return(jboolean)(::wifi_unload_driver() == 0); |
16 | staticjboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject) |
18 | return(jboolean)(::wifi_start_supplicant() == 0); |
其中这些函数都调用的是系统范围内的相应的函数,这些函数都位于:/hardware/libhardware_legacy/wifi下的wifi.c文件中
03 | #ifdef WIFI_DRIVER_MODULE_PATH |
04 | chardriver_status[PROPERTY_VALUE_MAX]; |
05 | intcount = 100;/* wait at most 20 seconds for completion */ |
07 | if(is_wifi_driver_loaded()) { |
11 | if(insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) |
14 | if(strcmp(FIRMWARE_LOADER,"") == 0) { |
15 | /* usleep(WIFI_DRIVER_LOADER_DELAY); */ |
16 | property_set(DRIVER_PROP_NAME,"ok"); |
19 | property_set("ctl.start", FIRMWARE_LOADER); |
23 | if(property_get(DRIVER_PROP_NAME, driver_status, NULL)) { |
24 | if(strcmp(driver_status,"ok") == 0) |
26 | elseif(strcmp(DRIVER_PROP_NAME,"failed") == 0) { |
33 | property_set(DRIVER_PROP_NAME,"timeout"); |
37 | property_set(DRIVER_PROP_NAME,"ok"); |
这个函数中会加载WIFI_DRIVER_MODULE_PATH路径中的驱动模块。这个模块位于:/system/lib/modules/wlan.ko(进入android系统的终端可以查看到,其中我自己的驱动模块名为:wl12xx_sdio.ko)
另外在函数int wifi_start_supplicant_common(const char *config_file)中会加载wifi的配置文件,位于:/data/misc/wifi/wpa_supplicant.conf
在android系统的终端截图如下:
最后你可以在终端上使用命令:lsmod 可以查看当前的系统加载的模块。
当关闭wifi的时候,你发现会少一个模块名为:wlan.ko(我手机上为:wl12xx_sdio.ko),当你在设置界面启动wifi后,你通过命令可以查看发现系统中多加载了一个模块:wlan.ko(我手机上为:wl12xx_sdio.ko),截图如下:
关闭wifi后,即没加载wlan.ko(我手机上为:wl12xx_sdio.ko)时:
启动wifi后,即加载wlan.ko(我手机上为:wl12xx_sdio.ko)后:
最后你可以进入目录:/proc/modules查看你系统所有可用的模块(系统可能加载了,也可能没加载)
写了两天终于写完了,请各位大牛不吝赐教,以免误导像我这样的菜鸟。