分类: 嵌入式
2015-01-04 15:48:48
原文地址:调试WIFI时的一些札记 作者:wibnmo
------------------------------------------------------------------------------------------------------
Wifi Application
packages/apps/Settings/src/com/android/settings/wifi/
Wifi Framework
frameworks/base/wifi/java/android/net/wifi/
frameworks/base/services/java/com/android/server/
Wifi JNI
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
Wifi Hardware
hardware/libhardware_legacy/wifi/wifi.c(这个文件里调用的函数在system/core/libnetutils/下面有实现)
Wifi wpa_supplicant
external/wpa_supplicant
Wifi Driver
hardware/broadcom/wlan/bcm4329/src/
kernel/arch/arm/mach-msm/board-msm7x30-xxx.c
------------------------------------------------------------------------------------------------------
各重要类路径:
Service Manager
frameworks/base/cmds/servicemanager/service_manager.c
WifiService WifiHandler
frameworks/base/services/java/com/android/server/WifiService.java
WifiManager.java、WifiMonitor.java、WifiStateTracker.java、WifiNative.java
frameworks/base/wifi/java/android/net/wifi/
frameworks/base/core/java/android/os/Message.java
frameworks/base/core/java/android/content/Context.java
packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
frameworks/base/services/java/com/android/server/ConnectivityService.java
------------------------------------------------------------------------------------------------------
WiFi子系统分析
初始化
SystemServer 是 Android Java 层的系统服务模块,这个模块主要功能就是管理供 Android 应用开发的 system service.
init.rc 文件一行service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server启动SystemServer。Zygote 进程是整个 Android 的孵化器进程,所有的 Activity 进程均是通过它来生成的。在 zygote 进程启动过程中指定了这么一个参数“– start-system-server” ,这个参数就是在 zygote 进程启动的同时启动 SystemServer。
在SystemServer启动的时候,会生成一个ConnectivityService的实例,关键代码片段:
try {
Slog.i(TAG, "Connectivity Service");
connectivity = ConnectivityService.getInstance(context);
ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
connectivity.startCne();
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Connectivity Service", e);
}
frameworks/base/services/java/com/android/server/ConnectivityService.java
ConnectivityService的构造函数会创建WifiService,关键代码片段如下:
case ConnectivityManager.TYPE_WIFI:
if (DBG) Slog.v(TAG, "Starting Wifi Service.");
WifiStateTracker wst = new WifiStateTracker(context, mHandler);
WifiService wifiService = new WifiService(context, wst);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
wifiService.startWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring();
break;
frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
public void startMonitoring() {
/*
* Get a handle on the WifiManager. This cannot be done in our
* constructor, because the Wifi service is not yet registered.
*/
mWM = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
}
WifiStateTracker会创建WifiMonitor接收来自底层的事件,WifiService和WifiMonitor是整个模块的核心。WifiService负责启动关闭wpa_supplicant、启动关闭WifiMonitor监视线程和把命令下发给 wpa_supplicant,而WifiMonitor则负责从wpa_supplicant接收事件通知。
1.使能WIFI
WirelessSettings 在初始化的时候配置了由WifiEnabler来处理Wifi按钮,
private void initToggles() {
mWifiEnabler = new WifiEnabler(
this,
(WifiManager) getSystemService(WIFI_SERVICE),
(CheckBoxPreference) findPreference(KEY_TOGGLE_WIFI));
当用户按下Wifi按钮后,Android会调用WifiEnabler的onPreferenceChange,再由WifiEnabler调用WifiManager的setWifiEnabled接口函数,通过AIDL机制,实际调用的是WifiService的setWifiEnabled函数,WifiService接着向自身发送一条MESSAGE_ENABLE_WIFI消息,这个消息会经过android os(frameworks/base/core/java/android/os/)中的Message类的sendToTarget()方法发送到Handler类中,Handler类通过MessageQueue类维护一个消息队列,它会在指定的时间把消息发送出去。最终由WifiHandler类的handleMessage()方法来处理消息(注意在WifiStateTracker类中也有一个handleMessage函数,WifiService中的handleMessage函数是用来处理在本类中定义的message消息类型;WifiStateTracker类中的handleMessage函数是用来处理在WifiStateTracker中定义的事件类型),它会调用setWifiEnabledBlocking()方法。在setWifiEnabledBlocking方法中做真正的使能工作:首先装载 WIFI内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ),然后启动wpa_supplicant(配置文件为"/data/misc/wifi/wpa_supplicant.conf")再通过WifiStateTracker来启动WifiMonitor中的监视线程。关键代码片段如下:
private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
......
if (enable) {
if (!mWifiStateTracker.loadDriver()) {
Slog.e(TAG, "Failed to load Wi-Fi driver.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
if (!mWifiStateTracker.startSupplicant()) {
mWifiStateTracker.unloadDriver();
Slog.e(TAG, "Failed to start supplicant daemon.");
setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);
return false;
}
registerForBroadcasts();
mWifiStateTracker.startEventLoop(); //-->startEventLoop()-->mWifiMonitor.startMonitoring();
}
......
setWifiEnabledState(eventualWifiState, uid);
return true; |
} |
V
private void setWifiEnabledState(int wifiState, int uid) {
......
// Update state
mWifiStateTracker.setWifiState(wifiState);
// Broadcast
final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
mContext.sendStickyBroadcast(intent);
}
当使能成功后,会广播发送 WIFI_STATE_CHANGED_ACTION 这个Intent通知外界,WIFI已经成功使能了。由于WifiEnabler初始化时注册了BroadcastReceiver,因此它会收到该Intent,从而开始扫描。
private void handleWifiStateChanged(int wifiState) {
if (wifiState == WIFI_STATE_ENABLED) {
loadConfiguredAccessPoints();
attemptScan();
}
2.查找AP
扫描的入口函数是WifiService的startScan,它其实也就是往wpa_supplicant发送SCAN命令。
static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz)
{
jboolean result;
// Ignore any error from setting the scan mode.
// The scan will still work.
if (forceActive && !sScanModeActive)
doSetScanMode(true);
result = doBooleanCommand("SCAN", "OK");
if (forceActive && !sScanModeActive)
doSetScanMode(sScanModeActive);
return result;
}
|
V
doBooleanCommand("SCAN", "OK");
|
V
char reply[256];
doCommand(cmd, reply, sizeof(reply))
|
V
size_t reply_len = replybuflen - 1;
::wifi_command(cmd, replybuf, &reply_len) (以上-->frameworks/base/core/jni/android_net_wifi_Wifi.cpp)
|
V
int wifi_command(const char *command, char *reply, size_t *reply_len)
|
V
wifi_send_command(ctrl_conn, command, reply, reply_len); (以上-->hardware/libhardware_legacy/wifi/wifi.c)
|
V
wpa_ctrl_request (external/wpa_supplicant_6/wpa_supplicant/src/common/wpa_ctrl.c)
command一直传送到wifi_send_command这个函数为止,程序开始变的复杂了一些。注意wifi_send_command的四个参数都是传的指针,后面三个参数都是从上面一直传过来的,下面我们来分析下第一个参数是怎么得来的。
ctrl_conn是一个全局静态变量,是这样定义的:static struct wpa_ctrl *ctrl_conn;
它在wifi_connect_to_supplicant()函数中初始化的。wifi_connect_to_supplicant()调用ctrl_conn = wpa_ctrl_open(ifname),其中ifname是"wlan0",这个wlan0是在system/core/rootdir/etc/init.qcom.rc中设置的:setprop wifi.interface wlan0。wpa_ctrl_open函数就是建立并初始化一个Unix domain socket的client结点,并与作为server的wpa_supplicant结点绑定。
接下来monitor_conn = wpa_ctrl_open(ifname),monitor_conn是用来监视从wpa_supplicant发出的event事件。然后调用wpa_ctrl_attach(monitor_conn)。wpa_ctrl_attach最后又调用了wpa_ctrl_request,wpa_ctrl_request用select系统调用来监听socket是否有数据过来,这个socket就是在wpa_ctrl_open函数里初始化的。
我们分析下wpa_ctrl_open函数:
当前项目中代码为:external/wpa_supplicant_6/wpa_supplicant_broadcom/src/common/wpa_ctrl.c
WIFI用的是UNIX domain IPC, wpa_ctrl_open做的工作就是创建两个socket, 服务端是/data/misc/wifi/sockets/wpa_ctrl_185-16,客户端是/dev/socket/wpa_wlan0。客户端socket文件名后缀wlan0正是我们在上面传入过来的。还有一个监听用的socket文件,/data/misc/wifi/sockets/wpa_ctrl_185-17。wpa_ctrl_request函数做的工作其实很简单,就是客户端向服务端发送了一个命令,只不过用的是select机制,猛一看上去可能有点复杂。然后就一步步返回了。还有一点就是monitor_conn,在wifi_connect_to_supplicant函数中会调用wpa_ctrl_attach(monitor_conn)-->wpa_ctrl_attach_helper(ctrl, 1)-->wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, buf, &len, NULL),调用到wpa_ctrl_request,我们上面分析过是往socket中发命令。在wifi.c中的wifi_wait_for_event会调用wpa_ctrl_recv(monitor_conn, buf, &nread)接收刚才发送的命令。
现在问题是与底层driver通信的代码在哪?ATTACH这个命令最终由谁来解析?
当 wpa_supplicant 处理完 SCAN 命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event(hardware/libhardware_legacy/wifi/wifi.c)函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行来处理这个事件:
void handleEvent(int event, String remainder) {
case SCAN_RESULTS:
mWifiStateTracker.notifyScanResultsAvailable();
break;
WifiStateTracker 则接着广播发送 SCAN_RESULTS_AVAILABLE_ACTION 这个 Intent:
case EVENT_SCAN_RESULTS_AVAILABLE:
mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
WifiLayer(packages/apps/Settings/src/com/android/settings/wifi/WifiStatusTest.java)注册了接收 SCAN_RESULTS_AVAILABLE_ACTION 这个 Intent,所以它的相关处理函数 handleScanResultsAvailable 会被调用,在该函数中,先会去拿到 SCAN 的结果(最终是往wpa_supplicant发送SCAN_RESULT命令并读取返回值来实现的), List list = mWifiManager.getScanResults();对每一个扫描返回的 AP,WifiLayer 会调用 TextView 的 setText 函数,从而最终把该 AP 加到 GUI 显示列表中。
3. 连接
用户在 WifiSettings 界面上选择一个 AP,输入密钥,点击连接按钮,Android 就会去连接这个 AP。
private void handleConnect() {
String password = getEnteredPassword();
if (!TextUtils.isEmpty(password)) {
mState.setPassword(password);
}
mWifiLayer.connectToNetwork(mState);
}
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。
// Make sure that network is enabled, and disable others
mReenableApsOnNetworkStateChange = true;
if (!mWifiManager.enableNetwork(state.networkId, true)) {
Log.e(TAG, "Could not enable network ID " + state.networkId);
error(R.string.error_connecting);
return false;
}
4. 配置 IP 地址
当 wpa_supplicant 成功连接上 AP 之后,它会向控制通道发送事件通知连接上 AP 了,wifi_wait_for_event 函数会接收到该事件,然后由 WifiMonitor 中的 MonitorThread 来处理这个事件,
void handleEvent(int event, String remainder) {
case CONNECTED:
handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
break;
WifiMonitor 再调用 WifiStateTracker 的 notifyStateChange,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动 DHCP 去获取 IP 地址,
private void handleConnectedState() {
setPollTimer();
mLastSignalLevel = -1;
if (!mHaveIPAddress && !mObtainingIPAddress) {
mObtainingIPAddress = true;
mDhcpTarget.obtainMessage(EVENT_DHCP_START).sendToTarget();
}
}
然后再广播发送 NETWORK_STATE_CHANGED_ACTION 这个 Intent
case EVENT_NETWORK_STATE_CHANGED:
if (result.state != DetailedState.DISCONNECTED || !mDisconnectPending) {
intent = newIntent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
if (result.BSSID != null)
intent.putExtra(WifiManager.EXTRA_BSSID, result.BSSID);
mContext.sendStickyBroadcast(intent);
}
break;
WifiLayer 注册了接收 NETWORK_STATE_CHANGED_ACTION 这个 Intent,所以它的相关处理函数 handleNetworkStateChanged 会被调用,当 DHCP 拿到 IP 地址之后,会再发送 EVENT_DHCP_SUCCEEDED 消息,
private class DhcpHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DHCP_START:
if (NetworkUtils.runDhcp(mInterfaceName, mDhcpInfo)) {
event = EVENT_DHCP_SUCCEEDED;
}
WifiLayer 处 理 EVENT_DHCP_SUCCEEDED 消息 , 会再次广播发送 NETWORK_STATE_CHANGED_ACTION 这个 Intent,这次带上完整的 IP 地址信息。
case EVENT_DHCP_SUCCEEDED:
mWifiInfo.setIpAddress(mDhcpInfo.ipAddress);
setDetailedState(DetailedState.CONNECTED);
intent = newIntent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
intent.putExtra(WifiManager.EXTRA_NETWORK_INFO, mNetworkInfo);
mContext.sendStickyBroadcast(intent);
break;
从framework到app的整个连接过程就是这样的。
------------------------------------------------------------------------------------------------
wpa_supplicant提供上行接口和下行接口。上行接口用于与其他模块(如UI)通信。下行接口与内核通信。wpa_supplicant提供的上行接口包括Dbus和Unix domain socket。
Wpa_supplicant 提供两种由外部模块获取信息的方式:一种是外部模块通过发送request 命令然后获取response的问答模式,另一种是wpa_supplicant主动向外部发送event事件,由外部模块监听接收。一般的常用做法是外部模块通过调用wpa_ctrl_open()两次,建立两个control interface接口,一个为ctrl interface,用于发送命令,获取信息,另一个为monitor interface,用于监听接收来自于wpa_supplicant的event时间。这样可以降低通信的耦合性,避免response和event的相互干扰。
下行接口包括:
1.PF_INET socket接口,主要用于向kernel 发送ioctl命令,控制并获取相应信息。
2.PF_NETLINK socket接口,主要用于接收kernel发送上来的event事件。
3.PF_PACKET socket接口,主要用于向driver传递802.11x报文。
具体实现在external/wpa_supplicant/目录下。
------------------------------------------------------------------------------------------------
wifi 动态 mac:
给一itemid,默认是NV_VERNO_MAJ_I,然后从??里读出nv项,也就是mac地址,如果读出为空,那么自动生成,并写到/etc/firmware/nvram.txt里。
------------------------------------------------------------------------------------------------
什么是 WPS(Wi-Fi Protected Setup) WPS(Wi-Fi Protected Setup,Wi-Fi保护设置)是由Wi-Fi联盟()组织实施的认证项目,主要致力于简化无线局域网的安装及安全性能配置工作。在传统方式下,用户新建一个无线网络时,必须在接入点手动设置网络名(SSID)和安全密钥,然后在客户端验证密钥以阻止“不速之客”的闯入。这整个过程需要用户具备Wi-Fi设备的背景知识和修改必要配置的能力。Wi- Fi Protected Setup能帮助用户自动设置网络名(SSID)、配置强大的WPA数据编码及认证功能,用户只需输入个人信息码(PIN方法)或按下按钮(按钮设置,或称PBC),即能安全地连入WLAN。
------------------------------------------------------------------------------------------------
| <---------- D-Bus Application API
+--------------------+
| connection manager |
| or p2p control app |
+--------------------+
| <---------- D-Bus supplicant API
| or socket control interface
+--------------------+
| wpa_supplicant |
+--------------------+
| <---------- nl80211
+--------------------+
| cfg80211 |
+--------------------+
| <---------- struct API
+--------------------+
| mac80211 |
+--------------------+
| <---------- mac80211's driver API
+--------------------+
| driver |
+--------------------+
[Wireless Card]
|
[Linux Kernel]
| |
[udev][libnl]-[iw]
| / \
[crda] \
| \
[ Wireless |
Regulatory |
Database ] |
|
|
[ hostapd ]
无线网卡:操作接收/发送无线包。
linux内核:linux内核包涵了无线网尗的驱动,mac80211子系统处理包的产生与时序安排。nl80211处理在用户空间配置无线接口cfg80211。
libnl:通过netlink与内核对话的传输层。
udev:udev是内核通过events/calls到crda的设施。
iw:是我们用来测试libnl是否正确工作,以及在无线网卡上创建额外的虚拟无线接口的用户空间工具。
crda:是内核通过udev来查找什么频段/频率是有效的,在什么强度的用户空间程序。这个从内核维护的静态表中移到用户空间,它可以不需要重载驱动和重启的情况下更新。
无线控制数据库:crda使用允许的频率和传输强度等级的数据库。
hostapd:这是个用来操作信号的产生和其它无线包,以及wpa-psk, wpa2等加密的守护进程。
------------------------------------------------------------------------------------------------
frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java目录里:
mInterfaceName = SystemProperties.get("wifi.interface", "wlan0");
sDnsPropNames = new String[] {
"dhcp." + mInterfaceName + ".dns1",
"dhcp." + mInterfaceName + ".dns2"
};
执行过程:
当wpa_supplicant起来以后:
守护进程会产生一个/data/system/wpa_supplicant/wlan0接口
根据wpa_cupplicant.conf得来:
ctrl_interface=DIR=/data/system/wpa_supplicant
同时在/data/misc/wifi/下创建一个sockets目录,下面会有二个socket
一个是控制接口,一个是监控接口(这个接口用于监测从wpa_supplicant发出的event事件。)。
Wifi.c会通过这二个接口和守护进程通信。
wpa_supplicant是核心程序,它和wpa_cli的关系就是服务和客户端的关系:后台运行wpa_supplicant,使用wpa_cli来搜索、设置、和连接网络。
------------------------------------------------------------------------------------------------
关闭wifi的过程:
在wifi连接成功后,logcat会一直打印:
V/WifiStateTracker( 962): handleMessage(): msg.what= 8 //EVENT_POLL_INTERVAL = 8
也就是WifiStateTracker会一直轮询wifi的状态。
点击关闭wifi后,执行流程是这样的(Log中很清楚,可自行看代码跟踪):
V/WifiStateTracker( 962): handleMessage(): msg.what= 8
I/wpa_supplicant( 896): CTRL-EVENT-TERMINATING - signal 15 received
V/WifiMonitor( 962): Event [CTRL-EVENT-TERMINATING - signal 15 received]
V/WifiStateTracker( 962): handleMessage(): msg.what= 2
V/DATA ( 1051): [DCT(0) ] intent received :android.net.wifi.WIFI_STATE_CHANGED
V/WifiStateTracker( 962): Connection to supplicant lost
V/WifiStateTracker( 962): *** reset mP2pState to IDLE
V/WifiStateTracker( 962): clearP2pNotification enter
V/WifiStateTracker( 962): clearP2pNotification exit
I/ActivityManager( 962): Start proc com.android.settings for broadcast com.android.settings/.widget.SettingsAppWidgetProvider: pid=1495 uid=1000 gids={3002, 3001, 3003}
D/ConnectivityService( 962): ConnectivityChange for WIFI: DISCONNECTED/DISCONNECTED
D/ConnectivityService( 962): Got Network Disconnected from Driver nwtype=1
D/WifiStateTracker( 962): P2P Reset connections and stopping DHCP
D/WifiStateTracker( 962): Reset connections and stopping DHCP
D/WifiStateTracker( 962): requestConnectionInfo
D/WifiStateTracker( 962): requestConnectionStatus
I/wpa_supplicant( 896): CTRL-EVENT-STATE-CHANGE id=0 state=0 BSSID=00:00:00:00:00:00
I/wpa_supplicant( 896): CTRL_IFACE monitor[0]: 2 - No such file or directory
I/dun_service( 110): process rmnet event
I/dun_service( 102): process rmnet event
------------------------------------------------------------------------------------------------
Porting WiFi drivers to Android:(好详细的说)
http://blog.linuxconsulting.ro/2010/04/porting-wifi-drivers-to-android.html
------------------------------------------------------------------------------------------------
Wifi-Direct Porting[SDK Layer]:
加入一个方法要改的文件:
frameworks/base/core/java/android/net/ConnectivityManager.java
frameworks/base/core/java/android/net/IConnectivityManager.aidl
有关Wifi-Direct的一些宏定义:
frameworks/base/core/java/android/provider/Settings.java
对新加入命令的处理函数族:
frameworks/base/core/jni/android_net_wifi_Wifi.cpp
配置Wifi-Direct iface/netmask:
frameworks/base/services/java/com/android/server/connectivity/Tethering.java
在这几个文件中分别加入控制和查询WIFI连接状态的函数族:
packages/apps/Settings/src/com/android/settings/wifi/WifiDirectSettings.java
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
frameworks/base/wifi/java/android/net/wifi/WifiStateTracker.java
frameworks/base/services/java/com/android/server/WifiService.java
frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
frameworks/base/wifi/java/android/net/wifi/WifiNative.java
比方说在这几个文件中分别有一个名称为findP2p()函数。
public boolean findP2p(int p2pTimeout) /* Request the supplicant to find P2P devices. p2pTimeout timeout in seconds, 0 means indefinite time */
调用流程是这样的:
WifiDirectSettings-->WifiManager通过Binder机制(IWifiManager.aidl)-->WifiService-->WifiStateTracker通过JNI接口(WifiNative.java)-->android_net_wifi_Wifi-->doBooleanCommand-->doCommand-->wifi_command-->wifi_send_command-->wpa_ctrl_request
另外,WifiManager定义WIFI相关的状态宏,例如P2P_STATE_XXX、WIFI_AP_STATE_XXX等;WifiStateTracker定义WIFI相关的事件宏,例如EVENT_DHCP_START、EVENT_P2P_DHCP_START、EVENT_SUPPLICANT_CONNECTION等;WifiService定义消息类型,例如MESSAGE_ENABLE_WIFI、MESSAGE_DISABLE_WIFI等。
WifiMonitor:
frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java
看注释,写的很清楚:
/** Events we receive from the supplicant daemon */
private static final int CONNECTED = 1;
private static final int DISCONNECTED = 2;
private static final int STATE_CHANGE = 3;
private static final int SCAN_RESULTS = 4;
private static final int LINK_SPEED = 5;
private static final int TERMINATING = 6;
private static final int DRIVER_STATE = 7;
private static final int UNKNOWN = 8;
在Porting的过程中,对WifiMonitor这个文件只修改了这些地方:
1).
/** Adding P2P prefix */
private static final String p2pEventPrefix = "P2P-";
private static final String apStaEventPrefix = "AP-STA-";
2).
在MonitorThread类中加入对P2P事件的判断:
// Parsing P2P event
if (eventStr.startsWith(p2pEventPrefix)
......
3).
对P2P事件的处理函数:
private void handleP2pEvent(String data) {
if (Config.LOGD) Log.d(TAG, "Received P2P event");
mWifiStateTracker.notifyP2pEvent(data);
}
定义supplicant的状态是否是合法的:
frameworks/base/wifi/java/android/net/wifi/SupplicantState.java
界面上的一些修改:
packages/apps/Settings/src/com/android/settings/wifi/*
packages/apps/Settings/AndroidManifest.xml
packages/apps/Settings/res/drawable-* //显示图片
packages/apps/Settings/res/layout/
packages/apps/Settings/res/values/
packages/apps/Settings/res/xml/
------------------------------------------------------------------------------------------------
kernel/arch/arm/mach-msm/board-msm7x30-xxx.c
bcm_wlan_power_on
|
V
bcm_detect_card(1) // kernel/drivers/mmc/core/host.c
|
V
mmc_detect_change(sdio_host, n)-->mmc_schedule_delayed_work(&host->detect, delay)-->mmc_rescan() //kernel/drivers/mmc/core/core.c
|
V
附:
1.下面说下sdio_host是怎么初始化的。
在msmsdcc_probe函数里初始化一个struct mmc_host *mmc,然后调用mmc_add_host(mmc) // kernel/drivers/mmc/host/msm_sdcc.c
|
V
接着在mmc_add_host函数里调用select_sdio_host(host, 1),这里的host就是上面传来的mmc。 // kernel/drivers/mmc/core/host.c
在select_sdio_host函数中给host.c文件中的变量struct mmc_host *sdio_host = NULL; 赋值sdio_host = host。
2.host->detect
是在msmsdcc_probe时调用mmc_alloc_host函数初始化的。INIT_DELAYED_WORK(&host->detect, mmc_rescan)。
mmc流程可参考金明SD资料,不再叙述。
------------------------------------------------------------------------------------------------
下面分析命令到驱动层的流程:
sock_ioctl // net/socket.c
|
V
dev_ioctl // net/core/dev.c
|
V
wext_handle_ioctl-->wext_ioctl_dispatch-->wireless_process_ioctl // net/wireless/wext-core.c
------------------------------------------------------------------------------------------------
wlan 调试纪要: 1: make kernelconfig打开以下选项: CONFIG_WIRELESS_EXT=y CONFIG_WIRELESS_EXT_SYSFS=y EMBEDED_SDIO=y MMC2_SUPPORT=y 可参考: kernel/arch/arm/configs/msm7630-xxx-perf_defconfig
2: 实现上电函数: bcm_wlan_power_on(int) bcm_wlan_power_off(int) kernel/arch/arm/mach-msm/board-msm7X30-xxx.c
3: 驱动编译: cd open-src/src/dhd/linux make LINUXDIR=/home/pengly/btg/xxx/kernel ARCH=arm CROSS_COMPILE=/home/pengly/btg/xxx/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi- dhd-cdc-sdmmc-gpl 生成dhd.ko
4: 命令行验证: echo 1 > /sys/devices/platform/msm_sdcc.3/polling insmod /system/lib/modules/dhd.ko "firmware_path=/etc/firmware/sdio.bin nvram_path=/etc/firmware/nvram.txt iface_name=wlan" 加载成功后: wl up wl scan wl results 输出ssid信息则正常
5:上层移植涉及文件: hardware/libhardware_legacy/wifi/wifi.c frameworks/base/wifi/ external/wpa_supplicant_6/ system/core/rootdir/etc/init.qcom.rc /hardware/broadcom
BT 调试纪要: 1: make kernelconfig打开以下选项: CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=y CONFIG_BT_HCIUART=y CONFIG_BT_HCIUART_H4=y CONFIG_BT_HCIUART_LL=y CONFIG_RFKILL=y
2:上电部分驱动注册 kernel/arch/arm/mach-msm/board-msm7X30-xxx.c
3:驱动调试 echo 1 > /sys/devices/platform/bt_power.0/rfkill/rfkill0/state brcm_patchram_plus --enable_hci --patchram /etc/firmware/brcm4330.hcd /dev/ttyHS0 -d hciconfig hci0 up hciconfig hci0 piscan hcitool dev hcitool scan 能搜索到蓝牙设备则正常
4: pcm调试 system/bluetooth/brcm_patchram_plus/brcm_patchram_plus.c 通过hcitool对hci0初始化等
5:其他涉及修改代码: /kernel/driver/bluesleep/bluesleep.c /system/bluetooth/bluedroid/bluetooth.c /system/bluetooth/brcm_patchram_plus/brcm_patchram_plus.c system/core/rootdir/etc/init.qcom.rc
wlan 调试纪要:
上电:
echo 1 > sys/class/rfkill/rfkill0/state
加载模块:
cd system/lib/modules/ath6kl/
insmod cfg80211.ko //80211协议相关
insmod ath6kl_sdio.ko //驱动相关
查看效果:
dmesg
cat /proc/net/wireless
wifi/bt调试好以后,要验证下供电,分别打开wifi/bt,再关闭,看是否供电真正关掉了,以防漏电
wifi有三路电,数字供电(DVDD),基带电(VDD_BB),功放电(VDD33_PA).
数字供电是管IC的,数字供电OK,那么IC才能工作,基带和功放当然是射频这一块的.
要保证这三路电都OK,器件才能完全工作正常.