首页 > 技术知识 > 正文

1. 前言

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

2. Android系统中的WIFI架构

wifi在Android中的架构如下所示。 Android系统中的WIFI架构&工作流程分析

其中涉及到的代码:

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的流程就分析完了。

猜你喜欢