Android系统中的WIFI架构&工作流程分析

free-jdx 2021-04-12 15:49:26 4851
1. 前言

记录个人最近对Android wifi的了解和使用感受,并为想入门、学习Android wifi的人员提供一定的参考

2. Android系统中的WIFI架构

wifi在Android中的架构如下所示。

其中涉及到的代码:

Java应用层
----Settings应用
Java Framework层
----frameworks/base/wifi/java/android/net/wifi/
----frameworks/base/services/java/com/android/server/wifi/

JNI层
---frameworks/base/core/jni/android_net_wifi_WifiNative.cpp
HAL层
---hardware/libhardware_legacy/wifi/wifi.c
wpa_supplicant层
---external/wpa_supplicant_8/
Linux Kernel层(驱动、电源管理部分)
---linux-3.3/drivers/net/wireless/rtl8188eu/

---linux-3.3/arch/arm/mach-sun6i/rf/wifi_pm_rtl8188eu.c
---linux-3.3/arch/arm/mach-sun6i/rf/wifi_pm.c

3. wifi工作流程分析

下面以wifi toggle on为例对wifi的工作流程进行分析。
wifi toggle的工作是使能/失能wifi的,当在Settings应用里点击wifi的打开/关闭按钮时会触发packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java里的onCheckedChanged()函数执行,所以这个文件是分析的入口点,首先看onCheckedChanged()函数:

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
        if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI))   {
            Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
            // Reset switch to off. No infinite check/listenenr loop.
            buttonView.setChecked(false);
            return;
        }

        // Disable tethering if enabling Wifi
        int wifiApState = mWifiManager.getWifiApState();
        if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
                (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
            mWifiManager.setWifiApEnabled(null, false);
        }

        mSwitch.setEnabled(false);
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitch.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
    }

首先判断是否处于飞行模式,飞行模式下是不可以打开wifi的;
接着判断是否使能了softAP,如果是则关闭softAP;
最后调用mWifiManager.setWifiEnabled()函数。mWifiManager.setWifiEnabled()函数在frameworks/base/wifi/java/android/net/wifi/WifiManager.java中定义:

/**
     * Enable or disable Wi-Fi.
     * @param enabled {@code true} to enable, {@code false} to disable.
     * @return {@code true} if the operation succeeds (or if the existing state
     *         is the same as the requested state).
     */
    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(enabled);
        } catch (RemoteException e) {
            return false;
        }
    }

可以看到,实际上是调用WifiService类里的setWifiEnabled()函数,WifiManager类对WifiService类进行了大部分封装,WifiService.setWifiEnabled()函数在frameworks/base/services/java/com/android/server/wifi/WifiService.java中定义:

public synchronized boolean setWifiEnabled(boolean enable) {
        enforceChangePermission();
        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid());
        if (DBG) {
            Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
        }

        /*
        * Caller might not have WRITE_SECURE_SETTINGS,
        * only CHANGE_WIFI_STATE is enforced
        */

        long ident = Binder.clearCallingIdentity();
        try {
            if (! mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        return true;
    }

在processMessage()函数里首先判断是否已经使能了wifi,接着判断两次使能的时间间隔,如果太短则跳出switch,否则执行transitionTo(mDeviceActiveState),将状态切换到mDeviceActiveState,而mDeviceActiveState的父状态是mStaEnabledState,由状态机的知识可以知道首先会调用mStaEnabledState的enter()函数:

class StaEnabledState extends State {
        @Override
        public void enter() {
            mWifiStateMachine.setSupplicantRunning(true);
        }

可以看到,调用的是frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java里的setSupplicantRunning()函数:

public void setSupplicantRunning(boolean enable) {
        if (enable) {
            sendMessage(CMD_START_SUPPLICANT);
        } else {
            sendMessage(CMD_STOP_SUPPLICANT);
        }
    }

在setSupplicantRunning()函数里发送CMD_START_SUPPLICANT消息。因为在WifiStateMachine构造函数里已经将状态设置为mInitialState,因此此消息由InitialState类处理,定义如下:

        public boolean processMessage(Message message) {
            switch (message.what) {
                case CMD_START_SUPPLICANT:
                    if (mWifiNative.loadDriver()) {
                        try {
                            mNwService.wifiFirmwareReload(mInterfaceName, "STA");
                        } catch (Exception e) {
                            loge("Failed to reload STA firmware " + e);
                            // continue
                        }

                        try {
                            // A runtime crash can leave the interface up and
                            // this affects connectivity when supplicant starts up.
                            // Ensure interface is down before a supplicant start.
                            mNwService.setInterfaceDown(mInterfaceName);
                            // Set privacy extensions
                            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);

                           // IPv6 is enabled only as long as access point is connected since:
                           // - IPv6 addresses and routes stick around after disconnection
                           // - kernel is unaware when connected and fails to start IPv6 negotiation
                           // - kernel can start autoconfiguration when 802.1x is not complete
                            mNwService.disableIpv6(mInterfaceName);
                        } catch (RemoteException re) {
                            loge("Unable to change interface settings: " + re);
                        } catch (IllegalStateException ie) {
                            loge("Unable to change interface settings: " + ie);
                        }

                       /* Stop a running supplicant after a runtime restart
                        * Avoids issues with drivers that do not handle interface down
                        * on a running supplicant properly.
                        */
                        mWifiMonitor.killSupplicant(mP2pSupported);
                        if(mWifiNative.startSupplicant(mP2pSupported)) {
                            setWifiState(WIFI_STATE_ENABLING);
                            if (DBG) log("Supplicant start successful");
                            mWifiMonitor.startMonitoring();
                            transitionTo(mSupplicantStartingState);
                        } else {
                            loge("Failed to start supplicant!");
                        }
                    } else {
                        loge("Failed to load driver");
                    }
                    break;

首先调用frameworks/base/wifi/java/android/net/wifi/WifiNative.java里定义的loadDriver()函数:

public native static boolean loadDriver();

loadDriver()是一个定义为本地实现的函数,在frameworks/base/core/jni/android_net_wifi_WifiNative.cpp里定义:

static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
{
    return (::wifi_load_driver() == 0);
}

这里实际上调用的是wifi_load_driver()函数,它在hardware/libhardware_legacy/wifi/wifi.c中定义:

#define TIME_COUNT 20 // 200ms*20 = 4 seconds for completion
#if defined(RTL_WIFI_VENDOR)
int wifi_load_driver()
{
    char driver_status[PROPERTY_VALUE_MAX];
    int  count = 0;

    char tmp_buf[512] = {0};
    char *p_strstr_wlan  = NULL;
    char *p_strstr_p2p   = NULL;
    int  ret        = 0;
    FILE *fp        = NULL;

    ALOGD("Start to insmod %s.ko\n", WIFI_DRIVER_MODULE_NAME);

    if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) {
        ALOGE("insmod %s ko failed!", WIFI_DRIVER_MODULE_NAME);
        rmmod(DRIVER_MODULE_NAME); //it may be load driver already,try remove it.
        return -1;
    }

    do{
       fp=fopen("/proc/net/wireless", "r");
       if (!fp) {
           ALOGE("failed to fopen file: /proc/net/wireless\n");
           property_set(DRIVER_PROP_NAME, "failed");
           rmmod(DRIVER_MODULE_NAME); //try remove it.
           return -1;
       }
       ret = fread(tmp_buf, sizeof(tmp_buf), 1, fp);
       if (ret==0){
           ALOGD("faied to read proc/net/wireless");
       }
       fclose(fp);

       ALOGD("loading wifi driver...");
       p_strstr_wlan = strstr(tmp_buf, "wlan0");
       p_strstr_p2p  = strstr(tmp_buf, "p2p0");
       if (p_strstr_wlan != NULL && p_strstr_p2p != NULL) {
           property_set(DRIVER_PROP_NAME, "ok");
           break;
       }
       usleep(200000);// 200ms

   } while (count++ <= TIME_COUNT);

   if(count > TIME_COUNT) {
       ALOGE("timeout, register netdevice wlan0 failed.");
       property_set(DRIVER_PROP_NAME, "timeout");
       rmmod(DRIVER_MODULE_NAME);
       return -1;
   }
   return 0;
}

首先调用insmod()函数加载驱动模块,然后读取/proc/net/wireless文件,判断驱动是否已经加载成功,在while循环里每隔200ms读取一次该文件,如果超时则退出循环。至此,mWifiNative.loadDriver()函数分析完毕。由于这里没有用到固件,因此mNwService.wifiFirmwareReload()函数就不分析了。继续看InitialState的processMessage()函数,

                      mWifiMonitor.killSupplicant(mP2pSupported);
                        if(mWifiNative.startSupplicant(mP2pSupported)) {
                            setWifiState(WIFI_STATE_ENABLING);
                            if (DBG) log("Supplicant start successful");
                            mWifiMonitor.startMonitoring();
                            transitionTo(mSupplicantStartingState);
                        } else {
                            loge("Failed to start supplicant!");
                        }
                    } else {
                        loge("Failed to load driver");
                    }
                    break;

在启动wap_supplicant之前先停止,然后再启动。
在mWifiMonitor.startMonitoring()函数里会调用JNI中的connectToSupplicant()函数,进而调用wifi.c里的wifi_connect_to_supplicant()函数建立了两个socket连接,一个用于向内核发送消息,一个用于接收内核消息,并开启一个线程不断地接收内核传来的消息,在这里也可以知道wap_supplicant充当的是内核与android之间桥梁的作用,并且会发送一个SUP_CONNECTION_EVENT消息。最后将状态转换到mSupplicantStartingState。
然后再调用mDeviceActiveStat的enter()函数:

/* Parent: StaEnabledState */
    class DeviceActiveState extends State {
        @Override
        public void enter() {
            mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
            mWifiStateMachine.setDriverStart(true);
            mWifiStateMachine.setHighPerfModeEnabled(false);
        }
这三个函数分别在WifiStateMachine里发送三个消息:CMD_SET_OPERATIONAL_MODE、CMD_START_DRIVER和CMD_SET_HIGH_PERF_MODE。其中CMD_SET_OPERATIONAL_MODE和CMD_START_DRIVER消息会被SupplicantStartingState延迟处理,CMD_SET_HIGH_PERF_MODE消息会被DefaultState处理,此处不分析了。下面是SupplicantStartingState对SUP_CONNECTION_EVENT消息的处理:
   public boolean processMessage(Message message) {
            switch(message.what) {
                case WifiMonitor.SUP_CONNECTION_EVENT:
                    if (DBG) log("Supplicant connection established");
                    setWifiState(WIFI_STATE_ENABLED);
                    mSupplicantRestartCount = 0;
                    /* Reset the supplicant state to indicate the supplicant
                     * state is not known at this time */
                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
                    /* Initialize data structures */
                    mLastBssid = null;
                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;
                    mLastSignalLevel = -1;

                    mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
                    mWifiConfigStore.loadAndEnableAllNetworks();
                    initializeWpsDetails();

                    sendSupplicantConnectionChangedBroadcast(true);
                    transitionTo(mDriverStartedState);
                    break;

setWifiState()函数里做的其中一件事情就是在状态栏里显示wifi信号图标。在SUP_CONNECTION_EVENT的处理流程中,主要是调用WifiConfigStore的loadAndEnableAllNetworks函数来加载并enable用户之前连接过并保存的AP,然后会初始化一些Wps相关的信息,最后transition到DriverStartedState。下面看DriverStartedState的enter()函数,由于此函数代码较长,因此省略了后面一部分:

      public void enter() {
            mIsRunning = true;
            mInDelayedStop = false;
            mDelayedStopCounter++;
            updateBatteryWorkSource(null);
            /**
             * Enable bluetooth coexistence scan mode when bluetooth connection is active.
             * When this mode is on, some of the low-level scan parameters used by the
             * driver are changed to reduce interference with bluetooth
             */
            mWifiNative.setBluetoothCoexistenceScanMode(mBluetoothConnectionActive);
            /* set country code */
            setCountryCode();
            /* set frequency band of operation */
            setFrequencyBand();
            /* initialize network state */
            setNetworkDetailedState(DetailedState.DISCONNECTED);

            /* Remove any filtering on Multicast v6 at start */
            mWifiNative.stopFilteringMulticastV6Packets();

            /* Reset Multicast v4 filtering state */
            if (mFilteringMulticastV4Packets.get()) {
                mWifiNative.startFilteringMulticastV4Packets();
            } else {
                mWifiNative.stopFilteringMulticastV4Packets();
            }

            mDhcpActive = false;

            startBatchedScan();

            if (mOperationalMode != CONNECT_MODE) {
                mWifiNative.disconnect();
                mWifiConfigStore.disableAllNetworks();
                if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) {
                    setWifiState(WIFI_STATE_DISABLED);
                }
                transitionTo(mScanModeState);
            } else {
                /* Driver stop may have disabled networks, enable right after start */
                mWifiConfigStore.enableAllNetworks();

                if (DBG) log("Attempting to reconnect to wifi network ..");
                mWifiNative.reconnect();

                // Status pulls in the current supplicant state and network connection state
                // events over the monitor connection. This helps framework sync up with
                // current supplicant state
                mWifiNative.status();
                transitionTo(mDisconnectedState);
            }

从注释上可以看出,主要是设置country code、工作频率和网络状态等。看mOperationalMode == CONNECT_MODE的分支,重新连接网络并将状态转换到mDisconnectedState。到这里,wifi toggle on的流程就分析完了。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
free-jdx
红包 97 7 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
free-jdx
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区