调试WIFI时的一些札记

15367阅读 0评论2012-08-31 wibnmo
分类:Android平台

------------------------------------------------------------------------------------------------------
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,器件才能完全工作正常.

上一篇:Linux常用命令
下一篇:I2C基本原理及对I2C Adapter的理解