本帖最后由 Wince.Android 于 2015-3-18 10:59 编辑
趁做Android WIFI驱动移植,对Android WIFI框架做了深刻的分析,并做此文档共同学习。 一、SDIO 设备驱动移植
很不巧内核已经“被”支持了,我就先不费这事了。
二、配置内核以支持Marvel无线WIFI
在这里我编译成模块的方式:
Device Drivers --->
Network device support --->
Wireless LAN --->
Marvell 8xxx Libertas WLAN driver support
Marvell Libertas 8385 and 8686 SDIO802.11b/g cards
Networking support --->
Wireless --->
<*> Improved wireless configuration API
cfg80211 regulatory debugging
nl80211 new netlink interface support
{*} Common routines for IEEE802.11 drivers
|
配置好后执行:make zImage 然后,make modules以生成我们要的驱动模块。把编译好的drivers/net/wireless/libertas/目下的驱动模块文件libertas.ko和libertas_sdio.ko复制到Android文件系统下的/system/lib/modules/目录下。后面发现根文件系统里面也“被”支持了,很郁闷!
三、放置好固件
创建firmware路劲为/system/etc/firmware目录,把helper_sd.bin,sd8686.bin移动至/system/etc/firmware下面,并更改helper_sd.bin为sd8686_helper.bin
#mkdir /system/etc/firmware
#mv /helper_sd.bin sd8686.bin /system/etc/firmware/
#cd /system/etc/firmware
#mv helper_sd.bin sd8686_helper.bin
使用如下加载方法:
insmod /system/lib/modules/libertas.ko
insmod /system/lib/modules/libertas_sdio.ko libertas_sdio: Libertas SDIO driver
libertas_sdio: Copyright Pierre Ossman
此时:ifconfig -a
查看有没有创建wlan0这个设备节点,若没有驱动好网卡,再次热插拔一下就好 # err = -123
mmc1: new SDIO card at address 0001
__func__ = if_sdio_prog_helper
libertas_sdio mmc1:0001:1: firmware: requesting sd8686_helper.bin
init: untracked pid 2074 exited
libertas_sdio mmc1:0001:1: firmware: requesting sd8686.bin
init: untracked pid 2077 exited
libertas: 00:0b:6c:89:62:4b, fw 9.70.3p23, cap 0x00000303
……
四、手动连接AP
首先得在Android上移植好无线工具,和FS2410类似(可参考我有关介绍Android上移植无线工具iwconfig、iwlist等)。
移植好无线工具后便可以测试了:
ifconfig -a 查看是否有wlan0 网络节点。
利用无线工具连接:
ifconfig wlan0 up
iwlist wlan0 scanning
iwconfig wlan0 essid "FS2410"
ifconfig wlan0 192.168.1.99 netmask 255.255.255.0 up
这时可以执行:
ping 192.168.1.1& 64 bytes from 192.168.1.1: seq=0 ttl=64 time=2.247 ms
64 bytes from 192.168.1.1: seq=1 ttl=64 time=1.900 ms
……
(可以kill -9 pid 结束进程) 五、自动连接AP,Android方式
……(下一节) 下一节为正式项目课题:基于Android的SDIO-WIFI移植(2) 对上层WIFI的应用,基本流程为:(1)WIFI初始化 (2)Wifi启动 (3)开始扫描AP (4)显示扫描的AP (5)配置AP (6)连接AP (7)获取IP地址 (8)上网 一、Android WIFI模块初始化 上文Android系统启动分析 讲到在SystemServer中实例化了ConnectivityService,接着的便是WIFI初始化:
frameworks/base/services/java/com/android/server/ConnectivityService.java
ConnectivityService 的构造函数会创建WifiService, if (DBG) Log.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService); WifiStateTracker 会创建WifiMonitor 接收来自底层的事件,WifiService 和WifiMonitor 是整个模块的核心。WifiService 负责启动关闭wpa_supplicant、启动关闭WifiMonitor 监视线程和把命令下发给wpa_supplicant,而WifiMonitor 则负责从wpa_supplicant 接收事件通知。
具体流程图如下: 二、WIFI模块启动 WirelessSettings 在初始化的时候配置了由WifiEnabler 来处理Wifi 按钮 WirelessSettings 在初始化的时候配置了由WifiEnabler 来处理Wifi 按钮 Packages\apps\settings\src\com\android\settings\WirelessSettings.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.wireless_settings);
initToggles();
mAirplaneModePreference = (CheckBoxPreference) findPreference(KEY_TOGGLE_AIRPLANE);
}
private void initToggles() {
…………
mWifiEnabler = new WifiEnabler(
this, (WifiManager) getSystemService(WIFI_SERVICE),
(CheckBoxPreference) wifiPreference);
…………
} 当用户按下Wifi 按钮后,Android 会调用WifiEnabler 的onPreferenceChange,再由WifiEnabler调用WifiManager 的setWifiEnabled 接口函数,通过AIDL,实际调用的是WifiService 的setWifiEnabled 函数,WifiService 接着向自身发送一条MESSAGE_ENABLE_WIFI 消息,在处理该消息的代码中做真正的使能工作:
首先装载WIFI 内核模块(该模块的位置硬编码为"/system/lib/modules/libertas_sdio.ko" ),
然后启动wpa_supplicant ( 配置文件硬编码为"/data/misc/wifi/wpa_supplicant.conf"),再通过WifiStateTracker 来启动WifiMonitor 中的监视线程。
WifiEnabler.java public boolean onPreferenceChange(Preference preference, Object value) {
// Turn on/off Wi-Fi
setWifiEnabled((Boolean) value);
}
private void setWifiEnabled(final boolean enable) {
if (!mWifiManager.setWifiEnabled(enable)) {
}
} WifiManager.java
public boolean setWifiEnabled(boolean enabled) {
return mService.setWifiEnabled(enabled);
}
IWifiManager mService;
interface IWifiManager{
…………
boolean startScan(boolean forceActive);
boolean setWifiEnabled(boolean enable);
…………
}
IWifiManger.aidl编译后生成了IWifiManger.java,并生成IWifiManger.Stub(服务器端抽象类)和IWifiManger.Stub.Proxy(客户端代理实现类)。WifiService通过继承IWifiManger.Stub实现,而客户端通过getService()函数获取IWifiManger.Stub.Proxy(即Service的代理类),将其作为参数传递给WifiManger,供其与WifiService通信时使用。
WifiService.java public boolean setWifiEnabled(boolean enable) {
…………
sendEnableMessage(enable, true, Binder.getCallingUid());
…………
}
private void sendEnableMessage(boolean enable, boolean persist, int uid) {
Message msg = Message.obtain(mWifiHandler,
(enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
(persist ? 1 : 0), uid);
msg.sendToTarget();
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2);
case MESSAGE_START_WIFI:
mWifiStateTracker.restart();
case MESSAGE_DISABLE_WIFI:
setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2);
case MESSAGE_STOP_WIFI:
mWifiStateTracker.disconnectAndStop();
break;
}
}
}
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
if (enable) {
if (!WifiNative.loadDriver()) {
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
}
if (!WifiNative.startSupplicant()) {
WifiNative.unloadDriver();
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop();
} else {
………………
}
// Success!
setWifiEnabledState(eventualWifiState, uid);
}
private void setWifiEnabledState(int wifiState, int uid) {
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
}
JNI android_net_wifi_wifi.cpp
// ---------------------------------------------------------------------------- /*
* JNI registration.
*/
static JNINativeMethod gWifiMethods[] = {
/* name, signature, funcPtr */
{ "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },
{ "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant },
{ "scanResultsCommand", "()Ljava/lang/String;", (void*) android_net_wifi_scanResultsCommand },
{ "reconnectCommand", "()Z", (void *)android_net_wifi_reconnectCommand },
{ "scanCommand", "(Z)Z", (void*) android_net_wifi_scanCommand },
}
1)static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz)
{
return (jboolean)(::wifi_load_driver() == 0);
}
2)static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz)
{
return (jboolean)(::wifi_start_supplicant() == 0);
}
3)WifiStateTracker.java
mWifiStateTracker.startEventLoop();
public void startEventLoop() {
mWifiMonitor.startMonitoring();
}
//WifiMonitor.java
public void startMonitoring() {
new MonitorThread().start();
} 当使能成功后,会广播发送WIFI_STATE_CHANGED_ACTION 这个Intent 通知外界WIFI已经成功使能了。//Success!后广播的。 上文讲到WIFI的启动流程,当然接着便扫描热点(AP),然后显示扫描到的AP、配置AP(填写IP地址等信息)、连接AP、获取IP地址、最后就是想要的上网咯! 一、扫描热点(AP) 上文启动WIFI成功后:// Success!
setWifiEnabledState(eventualWifiState, uid);
private void setWifiEnabledState(int wifiState, int uid) {
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
} 当使能成功后,会广播发送WIFI_STATE_CHANGED_ACTION 这个Intent 通知外界WIFI已经成功使能了。WifiLayer 创建的时候就会向Android 注册接收WIFI_STATE_CHANGED_ACTION,因此它会收到该Intent,从而开始扫描。 WifiSetting.java: protected void onCreate(Bundle savedInstanceState) {
mWifiLayer.onCreate();
} ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- WifiLayer.java:
public void onCreate() {
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
}
public void onResume() {
mContext.registerReceiver(mReceiver, mIntentFilter);
if (isWifiEnabled()) {
// Kick start the continual scan
queueContinuousScan();
}
} 以上就是WifiLayer.java注册接收的部分事件。接收部分事件处理有:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
handleNetworkStateChanged(
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO),
intent.getStringExtra(WifiManager.EXTRA_BSSID));
} else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
handleScanResultsAvailable();
} …… else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN));
}
}
}; 从可接受的事件看,当WIFI_STATE_CHANGED_ACTION时,对应的处理函数有: handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN)); private void handleWifiStateChanged(int wifiState) {
attemptScan();
…………
} public void attemptScan() {
if (!mWifiManager.startScanActive()) {
postAttemptScan();
}
} WifiManager.java:
public boolean startScanActive() {
return mService.startScan(true);
} -------AIDL------------------------------------------------------------------------------------------------------------------------------------------------------------------------- WifiService.java:
public boolean startScan(boolean forceActive) {
…………
return WifiNative.scanCommand(forceActive);
} ---------JNI--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- android_net_wifi_wifi.cpp:
{ "scanCommand", "(Z)Z", (void*) android_net_wifi_scanCommand },
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)
{
…………
result = doBooleanCommand("SCAN", "OK");
}
static jboolean doBooleanCommand(const char *cmd, const char *expect)
{
if (doCommand(cmd, reply, sizeof(reply)) != 0) {
return (jboolean)JNI_FALSE;
}
}
static int doCommand(const char *cmd, char *replybuf, int replybuflen)
{
if (::wifi_command(cmd, replybuf, &reply_len) != 0)
return -1;
…………
} -------HAL------------------------------------------------------------------------------------------------------------------------------------------------------------------------ wifi.c:
int wifi_command(const char *command, char *reply, size_t *reply_len)
{
return wifi_send_command(ctrl_conn, command, reply, reply_len);
}
int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
{
ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
…………
}
wpa_ctrl.c:
int wpa_ctrl_request()在wpa_ctrl.c中其实就是执行SCAN命令。 二、显示扫描的AP 当扫描成后,WifiMonitor 中的MonitorThread 会被执行来出来这个事件: void handleEvent(int event, String remainder) {
switch (event) {
case SCAN_RESULTS:
mWifiStateTracker.notifyScanResultsAvailable();
->sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE);
break;
} WifiStateTracker.java
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_SCAN_RESULTS_AVAILABLE:
if (ActivityManagerNative.isSystemReady()) {
mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
} WifiLayer注册接收SCAN_RESULTS_AVAILABLE_ACTION这个Intent: private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
{ handleScanResultsAvailable(); }
handleScanResultsAvailable();
-> list = mWifiManager.getScanResults();
-> mCallback.onAccessPointSetChanged(ap, true); handleScanResultsAvailable()中首先会去拿到SCAN的结果(最终是往wpa_supplicant中发送SCAN_RESULT命令并读取返回值来实现的),对每一个扫描返回的AP,WifiLayer会回调WifiSetting的onAccessPointSetChanged函数,从而最终把该AP加到GUI显示列表中。 三、配置AP 当用户在 WifiSettings 界面上选择了一个AP 后,会显示配置AP 参数的一个对话框: public boolean onPreferenceTreeClick()
->showAccessPointDialog(state, AccessPointDialog.MODE_INFO);
->AccessPointDialog dialog =
new AccessPointDialog(this, mWifiLayer);
showDialog(dialog); 当用户在AccessPointDialog中选择好加密方式和输入密钥之后,再点击连接按钮,Android就会去连接这个AP。 四、连接AP 在AccessPointDialog.java中点击连接后会执行: public void onClick(DialogInterface dialog, int which) {
handleConnect();
-> mWifiLayer.connectToNetwork(mState);
-> // Need WifiConfiguration for the AP
WifiConfiguration config = findConfiguredNetwork(state);
config = addConfiguration(state, 0);
managerEnableNetwork(state, false)
->mWifiManager.enableNetwork()
->mService.enalbeNetwork()
->WifiNative.enableNetworkCommand() 接下去就JNI { "enableNetworkCommand", "(IZ)Z", (void*)android_net_wifi_enableNetworkCommand },最终就是向wpa_supplicant发送连接命令
五、获取IP地址 当wpa_supplicant成功连接上AP之后,它会向控制通道发送事件通知连接上AP了,从而wifi_wait_for_event函数会接收到该事件,由此WifiMonitor中的MonitorThread会被执行来出来这个事件: void handleEvent(int event, String remainder) {
switch (event) {
case CONNECTED:
handleNetworkStateChange();
-> mWifiStateTracker.notifyStateChange(newState, BSSID, networkId);
->msg.sendToTarget();
break;
} WifiStateTracker.java
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_NETWORK_STATE_CHANGED:
sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
}
}
WifiStateTracker中注册的对Wifi相关数据库的观察者if(changed) 则启动:
private void configureInterface()
-> mDhcpTarget.sendEmptyMessage();
private class DhcpHandler extends Handler
handleMessage()
->switch (msg.what) {
case EVENT_DHCP_START:
Target.sendEmptyMessage(event); DhcpHandler会发送EVENT_DHCP_START消息启动DHCP去获取IP地址,当DHCP拿到IP地址之后,会发送EVENT_INTERFACE_CONFIGURATION_SUCCEEDED的消息,然后WifiStateTacker中的handleMessage会处理这样的消息 case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED:
sendNetworkStateChangeBroadcast(mWifiInfo.getBSSID());
-> Intent intent = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-> mContext.sendStickyBroadcast(intent); 这次带上完整的IP地址信息。WifiLayer中注册了此Intent的接受者,会调用handleNetworkStateChanged进行处理。最后就可以自由的上网了 转载自http://blog.csdn.net/yicao821/article/details/6895044
|