`
java_cofi
  • 浏览: 48783 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

andorid wifi 模块分析

阅读更多
一.启动wifi服务
1.在 SystemServer 启动的时候,会生成一个 ConnectivityService 的实例
路径为:\frameworks\base\services\java\com\android\server\SystemServer.java
try {
             Slog.i(TAG, "Connectivity Service");
             connectivity = ConnectivityService.getInstance(context);
             ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
            } catch (Throwable e) {
                Slog.e(TAG, "Failure starting Connectivity Service", e);
            }
2.ConnectivityService 类中private ConnectivityService(Context context) 构造函数创建
    WifiService和WifiStateTracker对象
\frameworks\base\services\java\com\android\server\ConnectivityService.java
for (int netType : mPriorityList) {
            switch (mNetAttributes[netType].mRadio) {
            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;
}
}
3.创建WifiStateTracker和WifiService对象用来启动wifi管理服务WifiStateTracker 会创建  
    WifiMonitor 用来接收来自底层的事件,WifiService 和 WifiMonitor 是整个模块的核心。
4.WifiService 负责启动关闭 wpa_supplicant、启动关闭 WifiMonitor 监视线程和把命令下发
               给 wpa_supplicant
     5. WifiMonitor
               开始运行线程,会请求连接wpa_supplicant,通过调用WifiStateTracker函数connectToSupplicant然后通过wifi.c的wifi_connect_to_supplicant,接着向wpa_ctrl的wpa_ctrl_open。然后通过CreateFile函数向wpa_supplicant读取数据。连接成功后会发送EVENT_SUPPLICANT_CONNECTION消息启动获取DHCP地址线程阻塞调用(当连接上AP的时候,该线程会被执行起来获取IP地址),并记录自己的MAC地址(因为MAC地址不会改变
所以请求一次即可) 接着开启一个死循环处理wpa_supplicant发送的事件。


当用户点击Wi-Fi按钮 的时候WifiEnabler中的onPreferenceChange函数会被调用,再由该函数调用WifiManager的setWifiEnabled函数,它先引用AIDL经由IWifiManager通过Binder机制调用WifiService的 setWifiEnabled设置Wifi开启状态。同时WifiService会发送MESSAGE_ENABLE_WIFI消息,由WifiService的
setWifiEnabledBlocking函数响应该消息,负责Wifi可用的需要工作。首先他会加载驱动
loadDriver(),然后开启wpa_supplicant( 配 置 文 件 硬 编 码 为
"/data/misc/wifi/wpa_supplicant.conf") 再注册广播消息,而后通过 WifiStateTracker 来启动 WifiMonitor 中的监视线程。以上工作使能成功后,会调用setWifiEnabledState最后广播WIFI_STATE_CHANGED_ACTION 这个Intent,至此Wifi能动开启。
接下来是扫描AP。
WifiSettings和WifiEnabler 创 建 的 时 候 就 会 向 Android 注 册 接 收
WIFI_STATE_CHANGED_ACTION,因此他们都会收到WIFI_STATE_CHANGED_ACTION 这个Intent,WifiEnabler负责使得图标加亮,WifiSettings负责使得开启扫描AP。经由
WifiService 的 startScan,再通过JNI由android_net_wifi_scanCommand函数向wpa_supplicant发送扫描命令.当 wpa_supplicant 处理完 SCAN 命令后,它会向控制通道发送事件通知扫描完成,从而wifi_wait_for_event 函数会接收到该事件,由此 WifiMonitor 中的 MonitorThread 会被执行来处理接扫描结果事件。此线程通过WifiStateTracker 广播 SCAN_RESULTS_AVAILABLE_ACTION这个Intent。而WifiSettings注册了接收此Intent,最终由其相应函数updateAccessPoints将AP列表,以GUI的形式列出来。




  Wifi 连接部分

当用户选择一个AP时会弹出一个AP参数配置对话框,此对话框会显示当前选择的AP信号强度,若此AP设置了密码则需要用户输入密码才能登录。WifiSettings中的 onPreferenceTreeClick会被调用          @Override
    public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
         //点击AP响应函数
        if (preference instanceof AccessPoint) {
            mSelected = (AccessPoint) preference;
            showDialog(mSelected, false);
        } else if (preference == mAddNetwork) {
            mSelected = null;
            showDialog(null, true);
        } else if (preference == mNotifyOpenNetworks) {
            Secure.putInt(getContentResolver(),
                    Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
                    mNotifyOpenNetworks.isChecked() ? 1 : 0);
        } else {
            return super.onPreferenceTreeClick(screen, preference);
        }
        return true;
    }

用户配置好之后点击连接按钮,onClick函数会被调用。
public void onClick(DialogInterface dialogInterface, int button) {
          //点击连接按钮的响应函数
        if (button == WifiDialog.BUTTON_FORGET && mSelected != null) {
            forget(mSelected.networkId);
        } else if (button == WifiDialog.BUTTON_SUBMIT && mDialog != null) {
            WifiConfiguration config = mDialog.getConfig();

            if (config == null) {
                if (mSelected != null && !requireKeyStore(mSelected.getConfig())) {
                    connect(mSelected.networkId);
                }
            } else if (config.networkId != -1) {
                if (mSelected != null) {
                    mWifiManager.updateNetwork(config);
                    saveNetworks();
                }
            } else {
                int networkId = mWifiManager.addNetwork(config);
                if (networkId != -1) {
                    mWifiManager.enableNetwork(networkId, false);
                    config.networkId = networkId;
                    if (mDialog.edit || requireKeyStore(config)) {
                        saveNetworks();
                    } else {
                        connect(networkId);
                    }
                }
            }
        }

连接请求部分
一.Settings的connect函数响应连接,更新网络保存配置,更新设置当前选择的优先级最高,并
    保存。然后通过enableNetwork使得其他网络不可用来进行连接。最后调用WifiManager的
      reconnect函数连接当前选择的网络。
二.WifiManager的reconnect函数通过AIDL的Binder机制,调用WifiService的reconnect函数
三.然后会调用 WifiStateTracker的reconnectCommand函数,通过JNI(android_net_wifi_Wifi)的            
      android_net_wifi_reconnectCommand 函数向WPA_WPASUPPLICANT发送 RECONNECT命令。
四. android_net_wifi_Wifi通过 doCommand(命令名,响应缓冲,响应缓存大小)调用wifi.c中的
      wifi_command函数来发送命令。
五.最后通过 wpa_ctrl的wpa_ctrl_request函数向控制通道发送连接命令。
返回请求部分
六.当连接上之后WPA_SUPPLICANT会向控制通道发送连接成功命令。wifi.c的
      wifi_wait_for_event函数阻塞调用并返回这个命令的字符串(CONNECTED).
七.而后WifiMonitor会被执行来处理这个事件,WifiMonitor 再调用 WifiStateTracker的
     notifyStateChange,WifiStateTracker 则接着会往自身发送 EVENT_DHCP_START 消息来启动
    DHCP 去获取 IP 地址,然后广播NETWORK_STATE_CHANGED_ACTION消息,最后由
    WifiSettings类来响应,改变状态和界面信息。
关键函数功能介绍
一.connect函数功能
  1.updateNetwork:updateNetwork(config)会将当前选择连接的AP配置信息
   信息传递进去,配置信息有(网络ID等)。如果网络ID为-1则重新添加网络配置,然后向
   wpa_supplicant 发送SET_NETWORK命令(即通过这个网络ID设置其他一些相关信息,设置
   SSID,密码等)如果网络配置不为-1则直接执行后面步骤即发送SET_NETWORK命令。
  2.saveNetwork:告诉supplicant保存当前网络配置并更新列表。SaveNetwork会调用WifiService的
     saveConfiguration向wpa_supplicant发送SAVE_CONFIG命令保存当前网络配置信息,
    如果返回false,则向wpa_supplicant重新发送RECONFIGURE命令获取配置信息,如果获取信

    息成功后,会Intent一个  NETWORK_IDS_CHANGED_ACTION事件WifiSettings会注册接受
    这个 时间并更新列表。
  3.enableNetwork函数,向系统获取接口名并使得该接口有效。由于之前传递的disableOthers
    为true则向wpa_supplicant发送SELECT_NETWORK(如果传递的为false则发送               
     ENABLE_NETWORK命令),
  4.reconnect函数:连接AP

二.reconnect函数功能:connect函数会调用WifiManager的reconnect然后通过Binder机制调用
   WifiService的reconnect,再由WifiStateTracke调用WifiNative向wpa_supplicant发送
   RECONNECT命令去连接网络,当连接上wpa_supplicant之后会向控制通道发送连接成功的命 
   令,
   wifi_wait_for_event函数阻塞等待该事件的发生,并返回这个命令的字符串(CONNECTED)
 
三.android_net_wifi_Wifi函数的doCommand函数会调用wifi.c的wifi_command函数将上层的命
   令向wpa_supplicant发送。
 
四.wifi_wait_for_event函数以阻塞的方式,等待控制通道传递的事件。当有事件传递过来的时候
   该函数会通过wpa_ctrl的wpa_ctrl_recv函数读取该事件,并以字符串形式返回该事件名。
   int wifi_wait_for_event(char *buf, size_t buflen)
{
                       .......
    result = wpa_ctrl_recv(monitor_conn, buf, &nread);
    if (result < 0) {
        LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
        strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
        buf[buflen-1] = '\0';
        return strlen(buf);
    }
    buf[nread] = '\0';
    /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
    /* Check for EOF on the socket */
    if (result == 0 && nread == 0) {
        /* Fabricate an event to pass up */
        LOGD("Received EOF on supplicant socket\n");
        strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
        buf[buflen-1] = '\0';
        return strlen(buf);
    }
    /*
     * Events strings are in the format
     *
     *     <N>CTRL-EVENT-XXX
     *
     * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
     * etc.) and XXX is the event name. The level information is not useful
     * to us, so strip it off.
     */
    if (buf[0] == '<') {
        char *match = strchr(buf, '>');
        if (match != NULL) {
            nread -= (match+1-buf);
            memmove(buf, match+1, nread+1);
        }
    }
    return nread;
}

五.wpa_ctrl_request,通过socket方式向wpa_supplicant发送命令,以select模式阻塞在
   wpa_supplicant发送和接收。
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,char *reply, size_t *reply_len,void (*msg_cb)(char *msg, size_t len))
{
         .......
                   res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
                   if (FD_ISSET(ctrl->s, &rfds)) {
                            res = recv(ctrl->s, reply, *reply_len, 0);
                            if (res < 0)
                                     return res;
                            if (res > 0 && reply[0] == '<') {
                                     /* This is an unsolicited message from
                                      * wpa_supplicant, not the reply to the
                                      * request. Use msg_cb to report this to the
                                      * caller. */
                                     if (msg_cb) {
                                               /* Make sure the message is nul
                                                * terminated. */
                                               if ((size_t) res == *reply_len)
                                                        res = (*reply_len) - 1;
                                               reply[res] = '\0';
                                               msg_cb(reply, res);
                                     }
                                     continue;
                            }
                            *reply_len = res;
                            break;
                   } else {
                            return -2;
                   }
         }
         return 0;
}

六.WifiMonitor 维护一个监视线程分发处理底层返回上来的事件
void handleEvent(int event, String remainder) {
            switch (event) {
                case DISCONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
                    break;
                case CONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
                    break;
                case SCAN_RESULTS:
                    mWifiStateTracker.notifyScanResultsAvailable();
                    break;
                case UNKNOWN:
                    break;
            }
        }
此时返回的事件是CONNECTED因此 handleNetworkStateChange会被调用,验证一下BSSID,重新获得networkId
,然后调用WifiStateTracke的notifyStateChange通知状态改变了的消息(EVENT_NETWORK_STATE_CHANGED)
接着处理这个消息,会移除可用网络通告,然后通过 configureInterface()的动态获取IP地址。最后
发送一个NETWORK_STATE_CHANGED_ACTION Intent,WifiSetings注册了此Intent因此会响应该它。由updateConnectionState函数响应。
七.updateConnectionState 获取连接信息,更新列表状态,设置为Connected,然后设置当前网络为可用状态
 
   private void updateConnectionState(DetailedState state) {
        /* sticky broadcasts can call this when wifi is disabled */
        if (!mWifiManager.isWifiEnabled()) {
            mScanner.pause();
            return;
        }

        if (state == DetailedState.OBTAINING_IPADDR) {
            mScanner.pause();
        } else {
            mScanner.resume();
        }

        mLastInfo = mWifiManager.getConnectionInfo();
        if (state != null) {
            mLastState = state;
        }

        for (int i = mAccessPoints.getPreferenceCount() - 1; i >= 0; --i) {
            ((AccessPoint) mAccessPoints.getPreference(i)).update(mLastInfo, mLastState);
        }

        if (mResetNetworks && (state == DetailedState.CONNECTED ||
                state == DetailedState.DISCONNECTED || state == DetailedState.FAILED)) {
            updateAccessPoints();
            enableNetworks();
        }
    }


流程图对应的源代码路径为:
WifiEnabler,WifiSettings对应的路径如下:
froyo/packages/apps/Settings/src/com/android/settings/

WifiManager,WifiMonitor,WifiStateTracker,WifiNative.对应的源代码路径如下:
froyo\frameworrks\base\wifi\java\android\net\wifi\

WifiService 对应代码的位置
froyo/frameworks/base/services/java/com/android/server/

android_net_wifi_Wifi源代码路径如下:
froyo\frameworks\base\core\jni\

wifi_command,wifi_wait_for_envent源代码路径如下:
\hardware\libhardware_legacy\wifi\wifi.c

wpa_ctrl_源代码路径如下:
\external\wpa_supplicant\wpa_ctrl.c

wpa_supplicant源代码路径如下:
froyo\external\wpa_supplicant\


本文转载自http://www.devdiv.com/home.php?mod=space&uid=83792&do=blog&id=3906
分享到:
评论

相关推荐

    Android WIFI模块分析

    以下是对Android WIFI模块的深入分析: **WIFI模块框图** WIFI模块通常包括以下几个层次:应用程序层、框架层、JNI(Java Native Interface)层、硬件抽象层和内核驱动层。在框图中,我们可以看到WirelessSettings...

    Android Wifi模块分析

    本文将深入探讨Android Wi-Fi源码分析,特别是如何连接到一个接入点(Access Point,简称AP)的过程。 首先,当用户在AcessPointDialog中选择加密方式并点击连接按钮后,Android系统会执行连接操作。关键代码在于`...

    Android__WIFI模块分析

    Android WIFI模块分析 Wifi 模块框图 Wifi核心模块 Wifi工作步骤 Wifi模块代码总结

    Android__WIFI模块分析.ppt

    Android WIFI 模块分析 Android WIFI 模块分析是 Android 操作系统中负责 WIFI 连接的模块。该模块主要由 WifiService、WifiMonitor、Wpa_supplicant、Wifi 驱动模块、Wifi 电源管理模块等组件组成。 Wifi 模块...

    android与WIFI模块的数据传输 数据透传

    在Android平台上,与WIFI模块进行数据传输是一个常见的任务,特别是在物联网(IoT)设备的交互中。本项目中,开发者被要求创建一个Android应用程序,用于配置HLK-RM04 WIFI模块,进行数据读取、参数设置以及系统时间...

    深入理解Android:WiFi模块 NFC和GPS卷.邓凡平(文字版).pdf

    《深入理解Android:WiFi模块 NFC和GPS卷》是由邓凡平编著的一本技术书籍,主要探讨了Android系统中三个重要的无线通信技术:WiFi、NFC(近场通信)和GPS(全球定位系统)。这本书以文字版的形式,深入浅出地讲解了...

    Android studio的WiFi模块连接和搜索

    在这个特定的主题中,我们聚焦于Android Studio中的WiFi模块,包括如何连接到WiFi网络以及如何进行WiFi热点搜索。这些功能涉及到Android系统的网络权限管理,这对于构建具有网络功能的应用至关重要。 1. **WiFi连接...

    android wifi应用层框架分析

    Android WIFI 应用层框架分析是从应用程序的角度描述 Android WIFI 的工作流程,主要介绍了各个控制接收模块的数据走向,具体数据传输流程和所调用到的方法介绍。本文将从 WIFI 初始化、WIFI 启动、开始扫描 AP、...

    【Android 11】【WiFi模块】WiFi打开函数调用流程图

    Android 11 WiFi 模块 WiFi 打开函数调用流程图 Android 11 中的 WiFi 模块是如何打开的?下面是 WiFi 打开函数调用流程图的详细解释。 首先,用户打开 WiFi 时,系统会调用 WifiServiceImpl.java 中的 ...

    Android-WIFI.rar_WiFi模块程序_android wifi_android wifi slam_android

    在Android系统中,WiFi模块是实现无线网络连接的关键部分,对于开发者来说,理解和掌握如何进行Android WiFi开发至关重要。本文将深入探讨Android WiFi的模块程序、初始化过程、连接AP的步骤,以及WiFi SLAM...

    android wifi模块代码

    首先,Android Wi-Fi模块的核心代码主要位于Android源码树的`frameworks/base/services/core/java/com/android/server/wifi`目录下。这部分代码包含了Wi-Fi服务(WifiService)的实现,它是系统服务,负责管理Wi-Fi...

    Android wifi display功能优化

    其中,WiFi模块负责WiFi连接和数据传输,WiFi Display模块负责WiFi Display功能的控制和数据传输,而显示模块负责显示 WiFi Display的内容。 二、代码分析 WiFi Display功能的代码分析可以参考博客...

    T507 AndroidQ WIFI模块移植说明.pdf

    Android Q WIFI 模块移植指南 随着 Android 系统的不断发展和更新,WIFI 模块的移植成为 Android 设备开发中一个非常重要的步骤。T507 Android Q WIFI 模块移植说明文档提供了将 WIFI 模块移植到 Android Q 系统上...

    Android8.0平台实现双wifi模块STA+AP模式

    在Android 8.0平台上实现双Wi-Fi模块的STA(Station)+AP(Access Point)模式,是一项技术挑战,涉及到Android系统的网络堆栈、Wi-Fi驱动以及框架层的深度定制。这种模式允许设备同时作为Wi-Fi客户端连接到一个网络...

    android环境下wifi模块编程

    在Android环境下进行WiFi模块编程,主要是利用Android系统提供的API来操控设备的WiFi功能,包括开启/关闭WiFi,扫描可用的WiFi网络,连接指定的网络,以及处理WiFi状态变化等。以下将详细介绍相关知识点: 1. **...

    深入理解Android WiFi模块 NFC和GPS卷

    总结来说,本资料“深入理解Android WiFi模块 NFC和GPS卷”将涵盖这些关键领域的基本概念、API使用、以及实践应用案例,是初学者学习Android开发中不可或缺的一部分。通过阅读这份文档,你将能够建立起对这些技术的...

Global site tag (gtag.js) - Google Analytics