android系统学习八

来源:互联网 发布:如何打开usb端口 编辑:程序博客网 时间:2024/05/17 04:19

Android的联接部分

 

Wifi部分

Wifi的基本架构

 自上而下包括的一些内容:

  Linux 内核的标准wifi驱动程序和协议

  Wap_supplicant可执行程序(WAP应用层认证客户端)

  WifiHAL

  WIFIJNI接口

Wifijava框架

 Wifi的相关应用

 

Wifi的结构图如下:

Wifi的本地实现  (主要包括wap_supplicantwap_supplicant适配层)

WAPwifi protected Access

 Wap_supplicantWAP 应用层认证客户端负责认证完成相关的登陆和加密工作,他是一个开源的

代码路径为: \external\wpa_supplicant     文件名为:wpq_ctrl.c

 部分代码如下:

      

 最终生成动态库libwap_client.so

Wap_supplicant是一个独立的守护进程 ,其通信是通过socket协议定完成

Wap_supplicantwext驱动接口的联系

driver.h头文件中,部分代码如下:

//该结构体是扫描结果的通用格式

struct wpa_scan_result {

u8 bssid[ETH_ALEN];

u8 ssid[32];

size_t ssid_len;

u8 wpa_ie[SSID_MAX_WPA_IE_LEN];

size_t wpa_ie_len;

u8 rsn_ie[SSID_MAX_WPA_IE_LEN];

size_t rsn_ie_len;

int freq;

u16 caps;

int qual;

int noise;

int level;

int maxrate;

};

//操作函数集合,所有驱动类型的一个接口封装包

struct wpa_driver_ops {

const char *name;

const char *desc;

int (*get_bssid)(void *priv, u8 *bssid);

}

Driver_wext.h : 声明了该驱动的一些对应驱动API接口的函数

Driver_wext.c:  最后 初始化了一个wpa_drv_pos 变量

Drivers.c 文件  主要定义了不同驱动操作接口的集合

Driver_xxx.h: 是不同驱动接口头文件 声明了操作接口

Driver_xxx.c: 实现操作接口

Wpq_supplicant守护进程是为不同驱动和操作系统具有更好的移植性而设计的,以便在wpa_supplicant层不用实现驱动的具体接口就可以添加新的驱动程序

 Wpa_supplicant_xxx函数传递wpa_supplicant实例指针wpa_s参数给wpa_drv_xxx来调用他,

 Wpa_drv_xx会通过wpa_s->driver->xxx()来调用通用驱动接口

 Wpa_ctrl.h: 声明了几个用于socket通信的函数接口

 Wpq_ctrl.c:  定义了一个wpa_ctrl结构

//根据UDP   UNIX和命名管道三种domain类型来定义通信实体

struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)

{

struct wpa_ctrl *ctrl;

static int counter = 0;

ctrl = os_malloc(sizeof(*ctrl));

if (ctrl == NULL)

return NULL;

os_memset(ctrl, 0, sizeof(*ctrl));

ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);

if (ctrl->s < 0) {

os_free(ctrl);

return NULL;

}

ctrl->local.sun_family = AF_UNIX;

os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),

#ifdef ANDROID

    "%s/%s%d-%d", local_socket_dir, local_socket_prefix,

                    getpid(), counter++);

#else /* ANDROID */

    "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);

#endif     

if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,

    sizeof(ctrl->local)) < 0) {

close(ctrl->s);

os_free(ctrl);

return NULL;

}

Wpa_supplicant.h : 

 部分代码如下:

   //wpa 的事件类型

   typedef enum wpa_event_type {}

Wpa_supplicant_i.h:

   Wpq_suppliant.c文件中定义的很多函数是在该头文件中声明的,而不是在wpa_supplicant.h

Wap_supplicant的结构如下:

    

     Wpa-_supplicant 适配层

     在android 中作为wifi部分的硬件抽像层来使用,主要用于封装与wpa_supplicant守护进程的通信(加载、控制、消息监控)

 

      Wpa_supplicant适配层的头文件路径为:

       \hardware\libhardware_legacy\include\hardware_legacy\wifi.h

        头文件中定义了以下几个重要的方法:

        //事件的进入通道,这个函数被阻塞,直到收到一个wifi事件,并以字符串的形式返回

       int wifi_wait_for_event(char *buf, size_t len);

       //将命令发送到wifi系统下层的功能,

       int wifi_command(const char *command, char *reply, size_t *reply_len);

     实现文件路径为:\hardware\libhardware_legacy\wifi

      在实现文件中

// 

int wifi_wait_for_event(char *buf, size_t buflen)

{

    size_t nread = buflen - 1;

    int fd;

    fd_set rfds;

    int result;

    struct timeval tval;

    struct timeval *tptr;

    

    if (monitor_conn == NULL) {

        LOGD("Connection closed\n");

        strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);

        buf[buflen-1] = '\0';

        return strlen(buf);

    }

    //调用此方法来接收一次wpa_supplication

    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;

}

//wifi_commandwifi_send_command的封装

int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)

{

    int ret;

    if (ctrl_conn == NULL) {

        LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);

        return -1;

}

// 通过此方法发送命令给wpa_supplicant

    ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);

    if (ret == -2) {

        LOGD("'%s' command timed out.\n", cmd);

        return -2;

    } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {

        return -1;

    }

    if (strncmp(cmd, "PING", 4) == 0) {

        reply[*reply_len] = '\0';

    }

    return 0;

}

        

      WIFI的适配层是libhardware_legacy.so的一部分

  

 Wifijava部分jni部分

   JNI部分的源程代码路径为下:

\frameworks\base\core\jni\android_net_wifi_wifi.cpp

 在这里实现的本地函数,都是通过调用wpa_supplicant适配层的接口实现的

 

  

Java部分实现代码路径为: 

\frameworks\base\services\java\com\android\server    //wifi服务层的内容
    \frameworks\base\wifi\java\android\net\wifi         //wifi服务的接口

 

     

由上图可以看出:  wifiNative.java 类提供  wifiService类、wifiStateTracker类和wifiMonitor类的底层操作支持

Wifi系统的核心部分是根据IWifiManager接口所创建的Binder服务器端(wifiService)和客户端(wifiManager)

 IWifiManager.aidl编译后生成IWifiManager.java 。并生成IWifiManager.Stub( 服务器端抽象类)IWifiManager.Stub.Proxy(客户端代理类)

 wifiService通过继承IWifiManager.Stub实现,
 客户端通过getService()取得IWifiManager.Stub.Proxy ,将其作为参数传递给wifiManager

  

 wifiManager wifi部分与外界的接口   wifiwatchDogService也是使用wifiManager来进行具体操作

 wifiService 是服务器端的实现,处理实际的驱动加载\、扫描,连接,断开

 根据客户端的不同命令,调用相应的nativeWifi底层实现 当接收到客户端消息命令后,转换成对应的自身消息加入消息队列,方便客户端调用,在wifiHandlerhandlerMessage中来处理对应的消息

 

对于底层上报的事件 ,wifiService一般调用wifiStateTracker

 

wifiStateTracker负责电源控制,设置电源管理模式,其核心是wifiMonitor所实现的事件轮询机制关键函数是wifiNative..waitForEvent阻塞式函数),该 类也是与外部的接口通过发送广播来完成消息的传递

 wifiMontor的通知机制是将底层事件转换成wifistateTracker能识别的消息

wifiWatchDogService connectivityService启动的服务它的作用是监控同一网络内的接入点(Access Point),如果当前接入点的DNS无法 ping通,就自动切入到下一个接入点

在初始化时,通过registerForWifiBroadcasts注册广播接收,捕获wifiStateTracker发出的通知,

开启一个wifiWatchdogThread线程来处理消息

Settings 中的wifi设置

原代码的路径为:\packages\apps\Settings\src\com\android\settings\wifi

 网络设置的实际功能还是调用wifiManager来实现的,  同样注册一个广播接收者来接收wifistateTracker发出的消息

 wifiEnable是用来设置 wifi的开关

 

Wifi工作流程实例

  例; 一个AP的联接流程

  1 开启wifi

      在wifiEnable中调用wifiManagersetwifiEnagled(null, true);

      wifimanager.setwifiEnable()通过Binder机制调用wifiService.setWifiEnabled

      wifiService.setWifiService.setWifiEnabledMESSAGE_ENABLE_WIFI消息发送到自已的消息队列

      wifiService 通过wifHandlerhandleMessage处理MESSAGE_ENABLE_WIFI

        调用setWifiEnableBlocking 

        setWifiEnableBlocking调用setWifiEnabledState,向外发送WIFI_STATE_CHANGED_ACTIONT通知消息

另外一些初始化工作

  设置当前状态、加载wifi驱动、开启wpa_supplicant、开启wifiStateTracker、注册广播接收者 接收wifiStateTracker的消息

 wifiService.java的代码路径为:\frameworks\base\services\java\com\android\server

部分代码如下:

    private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {

        final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;

        final int wifiState = mWifiStateTracker.getWifiState();

        if (wifiState == eventualWifiState) {

            return true;

        }

        if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {

            return false;

        }

        /**

         * Multiple calls to unregisterReceiver() cause exception and a system crash.

         * This can happen if a supplicant is lost (or firmware crash occurs) and user indicates

         * disable wifi at the same time.

         * Avoid doing a disable when the current Wifi state is UNKNOWN

         * TODO: Handle driver load fail and supplicant lost as seperate states

         */

        if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {

            return false;

        }

        /**

         * Fail Wifi if AP is enabled

         * TODO: Deprecate WIFI_STATE_UNKNOWN and rename it

         * WIFI_STATE_FAILED

         */

        if ((mWifiApState == WIFI_AP_STATE_ENABLED) && enable) {

            setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

            return false;

        }

        setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid);

        if (enable) {

           //调用JNI,加载wifi驱动

            if (!mWifiStateTracker.loadDriver()) {

                Slog.e(TAG, "Failed to load Wi-Fi driver.");

                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                return false;

            }

            //调用JNI层开启supplicant

            if (!mWifiStateTracker.startSupplicant()) {

                mWifiStateTracker.unloadDriver();

                Slog.e(TAG, "Failed to start supplicant daemon.");

                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                return false;

            }

            registerForBroadcasts();

            mWifiStateTracker.startEventLoop();

        } else {

            mContext.unregisterReceiver(mReceiver);

           // Remove notification (it will no-op if it isn't visible)

            mWifiStateTracker.setNotificationVisible(false, 0, false, 0);

            boolean failedToStopSupplicantOrUnloadDriver = false;

            if (!mWifiStateTracker.stopSupplicant()) {

                Slog.e(TAG, "Failed to stop supplicant daemon.");

                setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                failedToStopSupplicantOrUnloadDriver = true;

            }

            /**

             * Reset connections and disable interface

             * before we unload the driver

             */

            mWifiStateTracker.resetConnections(true);

            if (!mWifiStateTracker.unloadDriver()) {

                Slog.e(TAG, "Failed to unload Wi-Fi driver.");

                if (!failedToStopSupplicantOrUnloadDriver) {

                    setWifiEnabledState(WIFI_STATE_UNKNOWN, uid);

                    failedToStopSupplicantOrUnloadDriver = true;

                }

            }

            if (failedToStopSupplicantOrUnloadDriver) {

                return false;

            }

        }

        // Success!

        if (persist) {

            persistWifiEnabled(enable);

        }

        setWifiEnabledState(eventualWifiState, uid);

        return true;

    }

  

wifi开启完成后,接下就是搜索AP

启动supplient守护进程, 启动MonitorThread开始监听supplient的事件。

****  SettingwifiLayer.attemptScan()调用 wifiManager.startScan();*****

  在wifi2.3之后就没有wifiLayer类了,取而代之的是wifiSetting wifiSetting中有一个扫描类,Scanner, 用于扫搜索AP

  wifimanager.startScan()通过 Binder机制调用wifiService.starScan();

  首先 MonitorThread会收到DRIVER_STATE事件, wifiNative.scanCommand()supplient发送搜索AP的命令给wpa_supplicant,  中间经过JNI实现的doCommand,最终调用wap_supplicant适配层的wifiCommand 来完成发送过程

  命令的最终响应由wpa_supplicant上报"SCAN-RESULT"消息,wifiStateTracker开启的wifiMonitormonitorThread可以获取此消息,

  handlerEvent 的处理方式是调用wifiStateTracker.notifyScanResultsAvailable;

发送广播:mContext.sendBroadcast(new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

wifiSetting中会得到这个消息.作相关的处理操作

连接AP

  在supplient搜索AP结束时,monitorThread会收到SCAN_RESULTS

  接下来会调用wifiNative.setScanResultHandlingCommand(normalMode)来让supplient自行去连接哪个AP,首先会去挑选信号强并没有密码的AP进行联接

 wifiSettings会收到wifiManager.SCAN_RESULTE_AVAILABLE_ACTION广播

supplient联接到一个AP时,monitorThread会收到CONNECTED事件,配置IP地址,

如果配置成功会发送EVENT_STATE_CHANGED, ConnectivityService就会根据网络优先级决定关掉以太网,android 为了省电会将之前的网络设为desable

       mWifiManager.enableNetwork(networkId, false);

原创粉丝点击