




已阅读5页,还剩23页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android下实现非启动界面Wifi连接Android的网络功能和一般的linux并无太大的区别,我原来以为在Android上连接网络和普通的linux连接网络没有很大区别,事实上区别还是有一些的。由于项目的需要,我的目标是在Android的界面没有启动之前连接wifi,于是本来的期待是直接在init.rc中加入一些脚本调用即可,但研究了一会儿发现没有那么简单。首先要感谢anly_junbaidu贴吧的几篇博文,从/anly_jun/blog/item/8ecb92d593d144cf50da4b6e.html开始,一共有七篇关于Android Wifi模块分析,其中有大量博主自己使用UML工具画的调用讲解,对于理解Android Wifi工作机制还是有很用的。其中最重要的是下面这几幅图。(转自/anly_jun/blog/item/65e26e117e09ebcda6ef3f56.html)在想要对wifi硬件动作之前,需要做两件事情,一是要load wifi的driver,而是要打开wpa_supplicant,其实如果是连接没有加密的wifi,没有必要打开wpa_supplicant,但是为了讲问题化为熟知的问题,此处还是先按照提示调用wifi_load_driver()和wifi_start_supplicant()按照上面的提示写出来的初始化代码如下:int init_stage() / load the wifi driver: insmod .ko int ret = wifi_load_driver(); if(ret 0) LOGE(Failed to load Wi-Fi driver. %s,strerror(errno); return -1; / start wpa_supplicant ret = wifi_start_supplicant(); if(ret 0) LOGE(Failed to start supplicant daemon. %s,strerror(errno); return -1; return 0; 接下来,便是连接的过程了,经过上面的步骤,wifi的driver已经载入,wpa_supplicant也已经打开,那咱们就可以开始连接无线了吧。后来证实这是错误的,因为anly_jun的这篇Android wifi分析的粒度只在Java层面的函数级别,因此有一些细节并没有提到。在下面我会提到这些细节。按照一般的linux中连接wifi的步骤,这时候就可以直接调用一个程序来连接某个ssid的无线网络,然后调用dhcpd来分配ip了,我之前在eeepc上连接wifi就非常简单,调用iwconfig ssid,再调用dhcpd就可以了。但很遗憾,Android上并没有iwconfig这样方便的工具。这下线索似乎就断了,天无绝人之路,既然在Android的Java code中都可以添加一个无线网络并且连接,那我们就去Android的Java源代码中找一找。在Android中,程序员是使用WifiManager这个类来进行Wifi操作的,其中关于添加一个网络的代码如下:/* * Add a new network description to the set of configured networks. * The code networkId field of the supplied configuration object * is ignored. * * The new network will be marked DISABLED by default. To enable it, * called link #enableNetwork. * * param config the set of variables that describe the configuration, * contained in a link WifiConfiguration object. * return the ID of the newly created network description. This is used in * other operations to specified the network to be acted upon. * Returns code -1 on failure. */ public int addNetwork(WifiConfiguration config) if (config = null) return -1; workId = -1; return addOrUpdateNetwork(config); /* * Internal method for doing the RPC that creates a new network description * or updates an existing one. * * param config The possibly sparse object containing the variables that * are to set or updated in the network description. * return the ID of the network on success, code -1 on failure. */ private int addOrUpdateNetwork(WifiConfiguration config) try return mService.addOrUpdateNetwork(config); catch (RemoteException e) return -1; 看其中确实是调用了service的函数,于是又在frameworks/base/services/java/com/android/server/WifiService.java中找到了有关增加一个网络配置的相关代码/* * see link .wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration) * return the supplicant-assigned identifier for the new or updated * network if the operation succeeds, or code -1 if it fails */ public int addOrUpdateNetwork(WifiConfiguration config) enforceChangePermission(); /* * If the supplied networkId is -1, we create a new empty * network configuration. Otherwise, the networkId should * refer to an existing configuration. */ int netId = workId; boolean newNetwork = netId = -1; boolean doReconfig = false; / networkId of -1 means we want to create a new network synchronized (mWifiStateTracker) if (newNetwork) netId = mWifiStateTracker.addNetwork(); if (netId 0 & replybufreply_len-1 = n) replybufreply_len-1 = message; else replybufreply_len = message; return 0; static jint doIntCommand(const char *cmd) char reply256; if (doCommand(cmd, reply, sizeof(reply) != 0) return (jint)-1; else return (jint)atoi(reply); static jboolean doBooleanCommand(const char *cmd, const char *expect) char reply256; if (doCommand(cmd, reply, sizeof(reply) != 0) return (jboolean)JNI_FALSE; else return (jboolean)(strcmp(reply, expect) = 0); static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz) return doIntCommand(ADD_NETWORK); static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env, jobject clazz, jint netId, jstring name, jstring value) char cmdstr256; jboolean isCopy; const char *nameStr = env-GetStringUTFChars(name, &isCopy); const char *valueStr = env-GetStringUTFChars(value, &isCopy); if (nameStr = NULL | valueStr = NULL) return JNI_FALSE; int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), SET_NETWORK %d %s %s, netId, nameStr, valueStr) = (int)sizeof(cmdstr); env-ReleaseStringUTFChars(name, nameStr); env-ReleaseStringUTFChars(value, valueStr); return (jboolean)!cmdTooLong & doBooleanCommand(cmdstr, OK); / - /* * JNI registration. */ static JNINativeMethod gWifiMethods = /* name, signature, funcPtr */ loadDriver, ()Z, (void *)android_net_wifi_loadDriver , unloadDriver, ()Z, (void *)android_net_wifi_unloadDriver , startSupplicant, ()Z, (void *)android_net_wifi_startSupplicant , stopSupplicant, ()Z, (void *)android_net_wifi_stopSupplicant , connectToSupplicant, ()Z, (void *)android_net_wifi_connectToSupplicant , closeSupplicantConnection, ()V, (void *)android_net_wifi_closeSupplicantConnection , listNetworksCommand, ()Ljava/lang/String;, (void*) android_net_wifi_listNetworksCommand , addNetworkCommand, ()I, (void*) android_net_wifi_addNetworkCommand , setNetworkVariableCommand, (ILjava/lang/String;Ljava/lang/String;)Z, (void*) android_net_wifi_setNetworkVariableCommand , getNetworkVariableCommand, (ILjava/lang/String;)Ljava/lang/String;, (void*) android_net_wifi_getNetworkVariableCommand , 看来这下终于找到干活儿的函数了,可喜可贺,于是我们得出结论:在Android中,要连上一个无线网络,首先需要添加一个网络,然后设置这个网络的配置,而这些步骤实际上都是通过向wpa_supplicant发送命令实现的。命令的格式例外的很简单,比如添加一个网络配置是ADD_NETWORK,设置一个网络配置是SET_NETWORK netId varName var。于是根据Java代码我写出了配置环节的代码。int config_stage() / Add a network config to supplicant mode int networkId = doIntCommand(ADD_NETWORK); / Add a new network id if(networkId 0) LOGE(Failed to add a network configuration. %s,strerror(errno); return -1; LOGE(Add a network %d,networkId); / set the ssid of the destination wifi adhoc char cmdstr256; snprintf(cmdstr, sizeof(cmdstr), SET_NETWORK %d %s %s,networkId, SSID_NAME, SSID); if(!doBooleanCommand(cmdstr,OK) LOGE(Failed to set network %d configuration ssid. %s, networkId, strerror(errno); return -1; return networkId; 添加了一个配置的网络之后,选择某个网络配置的命令是SELECT_NETWORK netId。在SELECT_NETWORK之后,wpa_supplicant就尝试和该ssid的AP进行associate操作,在associate之后便调用dhcpd获取ip。SELECT_NETWORK是立即返回的函数,那么何以得知已经和无线AP连接上了呢?Android的界面里面连接/断开Wifi都是可以被接受到的事件,在WifiStateTracker中我们看到是由WifiMonitor来监听由wpa_supplicant发过来的消息的,于是我们来到framework/base/wifi/java/android/net/wifi/WifiMonitor.java,看到其中接受消息的Monitor线程class MonitorThread extends Thread public MonitorThread() super(WifiMonitor); public void run() if (connectToSupplicant() / Send a message indicating that it is now possible to send commands / to the supplicant mWifiStateTracker.notifySupplicantConnection(); else mWifiStateTracker.notifySupplicantLost(); return; /noinspection InfiniteLoopStatement for (;) String eventStr = WifiNative.waitForEvent(); / Skip logging the common but mostly uninteresting scan-results event if (Config.LOGD & eventStr.indexOf(scanResultsEvent) = -1) Log.v(TAG, Event + eventStr + ); if (!eventStr.startsWith(eventPrefix) if (eventStr.startsWith(wpaEventPrefix) & 0 0) LOGE(receive buf:n %sn,buf); if(strstr(buf,CONNECTED) 0) break; / XXX danger of not going out of the loop! continue; return 0; 在WifiStateTracer中我还找到了负责dhcp的DhcpHandler,按照其中的函数写了dhcp阶段的代码int dhcp_stage() int result; in_addr_t ipaddr, gateway, mask, dns1, dns2, server; uint32_t lease; char ifname256; char mDns1Name256; char mDns2Name256; property_get(erface, ifname ,eth0); snprintf(mDns1Name, sizeof(mDns1Name), net.%s.dns1,ifname); snprintf(mDns2Name, sizeof(mDns2Name), net.%s.dns2,ifname); result = dhcp_do_request(ifname, &ipaddr, &gateway, &mask, &dns1, &dns2, &server, &lease); if(result != 0) LOGE(Failed to dhcp on interface %s. %s, ifname, strerror(errno); return -1; struct in_addr dns_struct1, dns_struct2; dns_struct1.s_addr = dns1; dns_struct2.s_addr = dns2; property_set(mDns1Name,inet_ntoa(dns_struct1); property_set(mDns2Name,inet_ntoa(dns_struct2); return 0; 于是我用无线路由器建立了一个最简单的无线网络,ssid=TSever,没有密码,按照上面步骤进行联网。结果在ADD_NETWORK的步骤就出错了,无法获得网络id,这是怎么一回事呢?看到dhcp时的代码要对特定的Network Interface做操作,突然想起来之前在代码中似乎看到有对Interface做使能操作的代码WifiService在调用mWifiStateTracker.enableNetwork之前,还调用了String ifname = mWifiStateTracker.getInterfaceName(); NetworkUtils.enableInterface(ifname);这两句。于是在init阶段,加上了下面这段。 char ifname256; property_get(erface, ifname ,eth0); ret = ifc_enable(ifname); if(ret 0) LOGE(Failed to enable wifi interface %s. %s, ifname ,strerror(errno); return -1; 但是运行起来还是出同样的错误,不过这次busybox ifconfig之后可以发现eth0的端口了 ,至少没有做无用功。倒回去看在WifiMonitor的MonitorThread中有connectToSupplicant()的调用,本以为此调用不是非常关键,然后去hardware/libhardware_legacy/wifi/wifi.c文件里面看到全局有一个static struct wpa_ctrl *ctrl_conn;并且在wifi_command中需要用到这个ctrl_conn,那么如果这个ctrl_conn是NULL的话,所有的wifi_command命令自然都无法完成了,于是又加上了ret = wifi_connect_to_supplicant(); if(ret 0) LOGE(Failed to connect supplicant daemon. %s,strerror(errno); return -1; 这样编译完运行之后,果然顺利的分配到id了。运行一下程序,还是出现了错误,输出的log如下。I/wpa_supplicant( 618): CTRL-EVENT-SCAN-RESULTS ReadyI/wpa_supplicant( 618): Trying to associate with 00:24:b2:c1:16:b6 (SSID=TServer freq=2462 MHz)I/wpa_supplicant( 618): CTRL-EVENT-STATE-CHANGE id=-1 state=3E/ ( 612): Finished init stage.E/ ( 612): Add a network 2E/ ( 612): Finished config stage.I/wpa_supplicant( 618): CTRL-EVENT-STATE-CHANGE id=1 state=0E/ ( 612): receive buf:E/ ( 612): CTRL-EVENT-STATE-CHANGE id=1 state=0I/wpa_supplicant( 618): CTRL-EVENT-STATE-CHANGE id=-1 state=2E/ ( 612): receive buf:E/ ( 612): CTRL-EVENT-STATE-CHANGE id=-1 state=2I/wpa_supplicant( 618): CTRL-EVENT-SCAN-RESULTS ReadyE/ ( 612): receive buf:E/ ( 612): CTRL-EVENT-SCAN-RESULTS ReadyI/wpa_supplicant( 618): CTRL-EVENT-STATE-CHANGE id=-1 state=4E/ ( 612): receive buf:E/ ( 612): CTRL-EVENT-STATE-CHANGE id=-1 state=4I/wpa_supplicant( 618): Associated with 00:24:b2:c1:16:b6E/ ( 612): receive buf:E/ ( 612): Associated with 00:24:b2:c1:16:b6I/wpa_supplicant( 618): CTRL-EVENT-SCAN-RESULTS ReadyE/ ( 612): receive buf:E/ ( 612): CTRL-EVENT-SCAN-RESULTS ReadyD/NetworkLocationProvider( 127): onCellLocationChanged 4517,30785I/wpa_supplicant( 618): Authentication with 00:24:b2:c1:16:b6 timed out.E/ ( 612): receive buf:E/ ( 612): Authentication with 00:24:b2:c1:16:b6 timed out.注意到红色的那句log,我的wifi并没有设置密码,为什么还需要Authentication呢?想一想是不是wpa_supplicant的限制,于是去网上搜了到了这篇wpa_supplicant 工具使用,发现没有密码的情况下应该是这样的配置# 明文连接方式(不使用WPA和IEEE802.1X)network= ssid=plaintext-test key_mgmt=NONE于是在config阶段加上了对key_mgmt的设置,这下就连上了Wifi了,正确的log如下bash-4.1# wificonnectI/wpa_supplicant( 871): CTRL-EVENT-SCAN-RESULTS ReadyI/wpa_supplicant( 871): Trying to associate with 00:24:b2:c1:16:b6 (SSID=TServer freq=2462 MHz)I/wpa_supplicant( 871): CTRL-EVENT-STATE-CHANGE id=-1 state=3E/ ( 865): Finished init stage.E/ ( 865): Add a network 2E/ ( 865): Finished config stage.I/wpa_supplicant( 871): CTRL-EVENT-STATE-CHANGE id=1 state=0E/ ( 865): receive buf:E/ ( 865): CTRL-EVENT-STATE-CHANGE id=1 state=0I/wpa_supplicant( 871): CTRL-EVENT-STATE-CHANGE id=-1 state=2E/ ( 865): receive buf:E/ ( 865): CTRL-EVENT-STATE-CHANGE id=-1 state=2I/wpa_supplicant( 871): CTRL-EVENT-SCAN-RESULTS ReadyE/ ( 865): receive buf:E/ ( 865): CTRL-EVENT-SCAN-RESULTS ReadyI/wpa_supplicant( 871): Trying to associate with 00:24:b2:c1:16:b6 (SSID=TServer freq=2462 MHz)E/ ( 865): receive buf:E/ ( 865): Trying to associate with 00:24:b2:c1:16:b6 (SSID=TServer freq=2462 MHz)I/wpa_supplicant( 871): CTRL-EVENT-STATE-CHANGE id=-1 state=3E/ ( 865): receive buf:E/ ( 865): CTRL-EVENT-STATE-CHANGE id=-1 state=3I/wpa_supplicant( 871): CTRL-EVENT-STATE-CHANGE id=2 state=4E/ ( 865): receive buf:E/ ( 865): CTRL-EVENT-STATE-CHANGE id=2 state=4I/wpa_supplicant(
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 唐山市人民医院肿瘤破裂出血急诊介入考核
- 2025第二人民医院护理流程再造考核
- 忻州市中医院创伤骨科专科护士资格考核
- 长治市中医院产科主任医师资格认证
- 2025年中国木器涂料项目创业计划书
- 唐山市中医院人事管理专业英语与合同翻译试题
- 网咖加盟合同7篇
- 2025第二人民医院质量管理体系考核
- 北京市人民医院脐带血穿刺技术操作准入考核
- 2025年可充电应急灯项目投资分析及可行性报告
- T-HNTI 018-2020 湘西黄金茶 绿茶
- 全民健身场地管理办法
- 雪地足球赛方案
- 保安模拟考试题及答案2025年
- 2025年广东省中考地理试题卷(标准含答案)
- 2025年中国咖喱粉行业市场调查研究及投资前景预测报告
- 高中物理好题集萃:电磁感应(题目版)
- 人工智能偏见与公正性-洞察阐释
- TREM2在小胶质细胞介导帕金森病神经炎症中的核心角色与作用机制研究
- 2025年时事政治考试题及参考答案(100题)
- 妇产医院五年发展规划范文
评论
0/150
提交评论