基于rk3288平台android5.1系统的wifi流程分析 ---- 打开wifi,扫描热点
来源:互联网 发布:手机不能连接数据网络 编辑:程序博客网 时间:2024/05/16 12:43
这里从安卓应用层开始着手分析:
// -------------- packages/apps/settings/src/com/android/settings/wifi/WifiSettings.java -------------- //private WifiEnabler mWifiEnabler;// 以下为WifiSettings界面处在Active的状态下创建的!!@Overridepublic void onStart() { super.onStart(); // 创建了 WifiEnabler 对象,用于打开/关闭 wifi mWifiEnabler = createWifiEnabler();}
// -------------- packages/apps/settings/src/com/android/settings/wifi/WifiEnabler.java -------------- //private final WifiManager mWifiManager;public void onSwitchChanged(Switch switchView, boolean isChecked) { mSwitchBar.setEnabled(false); // 这里就调用WifiManager的打开/关闭wifi功能 if (!mWifiManager.setWifiEnabled(isChecked)) { // Error mSwitchBar.setEnabled(true); Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show(); }}
// ---------------- frameworks/base/wifi/java/android/net/wifi/WifiManager.java ------------------ //IWifiManager mService;public boolean setWifiEnabled(boolean enabled) { return mService.setWifiEnabled(enabled);}
// --------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java --------- //public final class WifiServiceImpl extends IWifiManager.Stub { public synchronized boolean setWifiEnabled(boolean enable) { mWifiController.sendMessage(CMD_WIFI_TOGGLED); }}默认情况下,在WifiController类的构造函数中已经将状态机的初始状态设置为mApStaDisabledState, 故上面发送的CMD_WIFI_TOGGLED应该由mApStaDisabledState类来接收!
// --------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java --------- //class ApStaDisabledState extends State { class ApStaDisabledState extends State { public boolean processMessage(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: case CMD_AIRPLANE_TOGGLED: if (mDeviceIdle == false) { transitionTo(mDeviceActiveState); } else { checkLocksAndTransitionWhenDeviceIdle(); } } } }}
由于之前WifiController构造函数中有如下定义:addState(mDeviceActiveState, mStaEnabledState); 根据状态机原理,transitionTo(mDeviceActiveState);会先调用父类mStaEnabledState的Enter函数。
class StaEnabledState extends State { public void enter() { mWifiStateMachine.setSupplicantRunning(true); }}setSupplicantRunning定义如下:
// ---------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java ---------- //public void setSupplicantRunning(boolean enable) { if (enable) sendMessage(CMD_START_SUPPLICANT); } else { sendMessage(CMD_STOP_SUPPLICANT); }}WifiStateMachine状态机的初始化状态是InitialState, 则此时的由InitialState状态来接收CMD_START_SUPPLICANT命令:
// ---------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java ---------- //class InitialState extends State { public boolean processMessage(Message message) { switch (message.what) { case CMD_START_SUPPLICANT: // 在这里insmod 对应的ko文件 if (mWifiNative.loadDriver()) { 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!"); } } } }}
// ---------- frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp ---------- //static JNINativeMethod gWifiMethods[] = { { "loadDriver", "()Z", (void *)android_net_wifi_loadDriver },}static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject){ return (::wifi_load_driver() == 0);}
// ---------------------- hardware/libhardware_legacy/wifi/Wifi.c ------------------------ //int wifi_load_driver() { if (rk_wifi_load_driver(1) < 0) return -1;}
// -------------- hardware/libhardware_legacy/wifi/Rk_wifi_ctrl.c ----------------- //#define WIFI_DRIVER_INF "/sys/class/rkwifi/driver"int rk_wifi_load_driver(int enable) { switch(enable) { case 0: buffer = '0'; break; case 1: buffer = '1'; break; } fd = open(WIFI_DRIVER_INF, O_WRONLY); sz = write(fd, &buffer, 1); }上面使用的"/sys/class/rkwifi/driver"是Rkwifi_sys_iface.c定义的:
// ------------- drivers/net/wireless/rockchip_wlan/wifi_sys/Rkwifi_sys_iface.c --------------- //static CLASS_ATTR(driver, 0660, NULL, wifi_driver_write);int rkwifi_sysif_init(void) { rkwifi_class = class_create(THIS_MODULE, "rkwifi"); ret = class_create_file(rkwifi_class, &class_attr_driver);}所以上面调用write函数, 其实就是调用wifi_driver_write函数:
static ssize_t wifi_driver_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count) { if(enable > 0) { ret = wifi_init_exit_module(enable); if (ret >= 0) wifi_driver_insmod = enable; } else { wifi_init_exit_module(enable); wifi_driver_insmod = enable; } }static int wifi_init_exit_module(int enable) { int type = get_wifi_chip_type(); if (enable > 0) ret = rockchip_wifi_init_module_rkwifi(); else rockchip_wifi_exit_module_rkwifi();}
// ----------- drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Dhd_linux.c ----------- // int rockchip_wifi_init_module_rkwifi(void) { return dhd_module_init();}这样就加载了wifi驱动 !!!
继续来看上面执行loadDriver之后的动作: mWifiNative.startSupplicant(mP2pSupported) , 启动 wpa_supplicant
// ------------------- hardware/libhardware_legacy/wifi/Wifi.c ---------------------- //static const char BCM_SUPPLICANT_NAME[] = "wpa_supplicant";static const char BCM_PROP_NAME[] = "init.svc.wpa_supplicant";int wifi_start_supplicant(int p2p_supported) { property_set("ctl.start", supplicant_name); // 这里就会启动init.connectivity.rc中的wpa_supplicant服务 while(count-- > 0) { if (property_get(supplicant_prop_name, supp_status, NULL)) { // 判断是否init.svc.wpa_supplicant处于running状态 if (strcmp(supp_status, "running") == 0) return 0; // 正常则返回0 } } return -1; // 其他情况返回-1}wpa_supplicant 服务定义:
// -------------------- device/rockchip/common/init.connectivity.rc -------------------- //########## kernel version >= 3.10.x ##########service wpa_supplicant /system/bin/wpa_supplicant / -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf / -I/system/etc/wifi/wpa_supplicant_overlay.conf / -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0 class main socket wpa_wlan0 dgram 660 wifi wifi disabled oneshot回到上面的函数调用:
mWifiMonitor.startMonitoring();
其中mWifiMonitor是在WifiStateMachine类中的构造函数中定义的:
mWifiMonitor = new WifiMonitor(this, mWifiNative);
来看看WifiMonitor类:
// --------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java -------- //public synchronized void startMonitoring(String iface) { while (true) { if (mWifiNative.connectToSupplicant()) { m.mMonitoring = true; m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT); // 连接成功后就会向WifiStateMachine发送SUP_CONNECT_EVENT new MonitorThread(mWifiNative, this).start(); // 启动MonitorThread线程监听底层的消息 mConnected = true; break; } if (connectTries++ < 5) { try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } else { //mIfaceMap.remove(iface); m.mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT); Log.e(TAG, "startMonitoring(" + iface + ") failed!"); break; } }}private static class MonitorThread extends Thread { private final WifiNative mWifiNative; private final WifiMonitorSingleton mWifiMonitorSingleton; public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) { super("WifiMonitor"); mWifiNative = wifiNative; mWifiMonitorSingleton = wifiMonitorSingleton; } public void run() { for (;;) { String eventStr = mWifiNative.waitForEvent(); // Skip logging the common but mostly uninteresting scan-results event if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) { Log.d(TAG, "Event [" + eventStr + "]"); } if (mWifiMonitorSingleton.dispatchEvent(eventStr)) { if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events"); break; } } }}可以看到, 上面首先调用connectToSupplicant 和 wpa_supplicant 建立联系,并创建了一个Monitor Thread, 调用 waiForEvent 用于接收wpa_supplicant 上发的消息, 并调用dispatchEvent分发处理消息!!
// ------------ hardware/libhardware_legacy/wifi/Wifi.c ----------- //int wifi_connect_to_supplicant(){ static char path[PATH_MAX]; if (access(IFACE_DIR, F_OK) == 0) { snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface); } else { snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface); } ALOGD("open connection to supplicant on /"%s/"", path); // @android:wpa_wlan0 return wifi_connect_on_socket_path(path);}int wifi_connect_on_socket_path(const char *path) { ctrl_conn = wpa_ctrl_open(path); // 创建了两个套接字,ctrl_conn用于发送,monitor_conn用于接收 monitor_conn = wpa_ctrl_open(path); wpa_ctrl_attach(monitor_conn);}上面讲到startMonitoring调用wifi_connect_to_supplicant之后, 紧接着会发送一个SUP_CONNECTION_EVENT的消息给到WifiStateMachine:
m.mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
同时状态切换到transitionTo(mSupplicantStartingState);
// --------- frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java--------- //class SupplicantStartingState extends State { public boolean processMessage(Message message) { switch(message.what) { case WifiMonitor.SUP_CONNECTION_EVENT: sendSupplicantConnectionChangedBroadcast(true); transitionTo(mDriverStartedState); break; case CMD_START_DRIVER: case CMD_SET_OPERATIONAL_MODE: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED; deferMessage(message); // 上面发送的这两个命令,都延迟处理!!! break; } }}
class DriverStartedState extends State { public void enter() { if (mOperationalMode != CONNECT_MODE) transitionTo(mScanModeState); else transitionTo(mDisconnectedState); if (mP2pSupported) { //注意这里, 如果是支持wifi direct的话会在这里发送CMD_ENABLE_P2P命令!! if (mOperationalMode == CONNECT_MODE) { mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); } } }}
class DisconnectedState extends State { public void enter() { startDelayedScan(mDisconnectedScanPeriodMs, null, null); // 开始扫描 } public boolean processMessage(Message message) { switch (message.what) { case WifiMonitor.SCAN_RESULTS_EVENT: ret = NOT_HANDLED; // 不处理,抛给父类 break; case CMD_START_SCAN: handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); break; case CMD_SET_OPERATIONAL_MODE: // 在这里处理CMD_SET_OPERATIONAL_MODE消息 if (message.arg1 != CONNECT_MODE) { mOperationalMode = message.arg1; mWifiConfigStore.disableAllNetworks(); if (mOperationalMode == SCAN_ONLY_WITH_WIFI_OFF_MODE) { mWifiP2pChannel.sendMessage(CMD_DISABLE_P2P_REQ); setWifiState(WIFI_STATE_DISABLED); } transitionTo(mScanModeState); } break; } }}private void handleScanRequest(int type, Message message) { startScanNative(type, freqs);}private boolean startScanNative(int type, String freqs) { mWifiNative.scan(type, freqs);}
startScanNative会向wpa_supplicant发送SCAN的命令:
// ------------ frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java ------------ //public boolean scan(int type, String freqList) { if (type == SCAN_WITHOUT_CONNECTION_SETUP) { if (freqList == null) return doBooleanCommand("SCAN TYPE=ONLY"); else return doBooleanCommand("SCAN TYPE=ONLY freq=" + freqList); } else if (type == SCAN_WITH_CONNECTION_SETUP) { if (freqList == null) return doBooleanCommand("SCAN"); else return doBooleanCommand("SCAN freq=" + freqList); } }private boolean doBooleanCommand(String command) { synchronized (mLock) { int cmdId = getNewCmdIdLocked(); String toLog = Integer.toString(cmdId) + ":" + mInterfacePrefix + command; boolean result = doBooleanCommandNative(mInterfacePrefix + command); localLog(toLog + " -> " + result); if (DBG) Log.d(mTAG, command + ": returned " + result); return result; }}
// ------------ frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp ---------------- //static JNINativeMethod gWifiMethods[] = { { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },}static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring javaCommand) { return doBooleanCommand(env, javaCommand);}static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) { char reply[REPLY_BUF_SIZE]; if (!doCommand(env, javaCommand, reply, sizeof(reply))) { return JNI_FALSE; } return (strcmp(reply, "OK") == 0);}static bool doCommand(JNIEnv* env, jstring javaCommand, char* reply, size_t reply_len) { ScopedUtfChars command(env, javaCommand); if (command.c_str() == NULL) { return false; // ScopedUtfChars already threw on error. } if (DBG) { ALOGD("doCommand: %s", command.c_str()); } --reply_len; // Ensure we have room to add NUL termination. if (::wifi_command(command.c_str(), reply, &reply_len) != 0) { return false; } // Strip off trailing newline. if (reply_len > 0 && reply[reply_len-1] == '/n') { reply[reply_len-1] = '/0'; } else { reply[reply_len] = '/0'; } return true;}最终就会调用wifi.c的wifi_command函数,从而通过ctrl_conn给wpa_supplicant发送SCAN TYPE=ONLY命令。
当wpa_suppliant执行完SCAN并成功找到一些AP后,就会给WifiMonitor发送CTRL-EVENT-SCAN-RESULTS的event,
WifiMonitor会parse出这个event,并向WifiStateMachine发送SCAN_RESULTS_EVENT消息,
由于DisconnectedState类不处理, 一直往上抛到父类,
WifiStateMachine的SupplicantStartedState会处理这个消息,如下:class SupplicantStartedState extends State { public boolean processMessage(Message message) { switch(message.what) { // 这里主要做了两件事,一是去获取scanResults,另外会发送一个广播信息出去, // 如果有检测这个广播的receive收到这个广播后,就可以调用函数去获取到scanResults并显示到listview上面,例如WifiSettings case WifiMonitor.SCAN_RESULTS_EVENT: setScanResults(); sendScanResultsAvailableBroadcast(); } }}private void setScanResults() { /* 这个函数看起来比较复杂,其实仔细分析,它只是循环的parse从WifiNative获取到AP列表信息, WifiNative.scanResut的返回结果如下,每个AP之间用"===="分割,末尾以“####”来表示结束。 id=1 bssid=68:7f:76:d7:1a:6e freq=2412 level=-44 tsf=1344626243700342 flags=[WPA2-PSK-CCMP][WPS][ESS] ssid=zfdy ==== id=2 bssid=68:5f:74:d7:1a:6f req=5180 level=-73 tsf=1344626243700373 flags=[WPA2-PSK-CCMP][WPS][ESS] ssid=zuby #### 当所有的结果都被parse出来后,会被存到mScanResults这个ArrayList当中, 另外会用bssid+ssid做key值,将这个scanResult存到mScanResultCache这个LRU(最近最少使用) cache当中。 当然随着wifi driver不断的scan,发现新的AP,mScanResults和mScanResultCache中的数据也在不断的变化。 当应用程序收到sendScanResultsAvailableBroadcast发送的WifiManager.SCAN_RESULTS_AVAILABLE_ACTION这个broadcast后, 就可以去获取上面提供的mScanResults信息了,获取过程很简单,直接复制mScanResults这个ArrayList里面的成员,然后返回。 值得注意的是!!!sendScanResultsAvailableBroadcast设置了Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT这个属性, 所以只有动态注册的broadcastReceive才会收到这个broadcast。 */}
阅读全文
0 0
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 打开wifi,扫描热点
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 打开热点,作为AP
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 连接热点
- WIFI扫描流程分析
- WIFI扫描流程分析
- WIFI扫描流程分析
- WIFI扫描流程分析
- Android -- Wifi热点的打开与关闭流程简介
- Android -- Wifi热点的打开与关闭流程简介
- Android -- Wifi热点的打开与关闭流程简介
- Android -- Wifi扫描流程分析
- Android -- Wifi扫描流程分析
- 扫描wifi热点
- ios扫描wifi热点
- WIFI开启扫描热点
- [android]WIFI热点启动流程分析
- [android]WIFI热点启动流程分析
- rk3288 ap6335 linux下的wifi 热点功能使用
- 火狐浏览器禁用js
- Java多线程系列--“JUC锁”07之 LockSupport
- 鼠标拖拽事件实现
- 分享几个前端工具--制作加载中小图标
- reboot系统调用的时候会调用shutdown函数
- 基于rk3288平台android5.1系统的wifi流程分析 ---- 打开wifi,扫描热点
- druid读取clob字段问题
- java.lang.OutOfMemoryError: PermGen space解决方法
- 将jar包安装到本地仓库
- 下拉菜单
- Redis入门
- 教你搭建vs2013+Qt5的开发环境
- webuploader 多文件上传
- <android> 手机适配 ——适配 “老年机”