lollipop_softap启动wifi ap失败
最近一直在调试lollipop,翻译成中文好像是棒棒糖的意思,就是个wifi控制管理工具,比如设置DLNA或者WFD模式等,其原理是通过本地通信工具sockets控制其他接口来启动wpa_suplicant或者hostapd,从而实现功能,所以这里面涉及的还有wpa_supplicant工具包,以及netd,netd就是个服务器,接受ndc(客户端)的指令来执行动作,比如设置hostapd需要的参数,生成hostapd.conf文件,最后启动hostapd应用等。。
lollipop里面包含好几个bin工具
lollipop lollipop_ota lollipop_p2p lollipop_reset lollipop_softap
然后在init.rc里面配置了相应的服务,其中只有lollipop是开机启动的,其他几个服务都是由lollipop接收到指令来切换不同模式的时候去start对应的服务。
service lollipop /system/bin/lollipop
disabled
oneshot
#class main service lollipop_p2p /system/bin/lollipop_p2p
disabled
oneshot service lollipop_softap /system/bin/lollipop_softap
disabled
oneshot service lollipop_ota /system/bin/lollipop_ota
disabled
oneshot service lollipop_reset /system/bin/lollipop_reset
disabled
oneshot
我的sdk是从andorid高度裁剪过的,砍掉了jni以上部分,只有c、c++部分以下,编译完成后img总共12m左右,烧录在16M的nor_flash的板子上。
拿到手的时候sdk中wpa_suplicant没有被包含编译,lollipop也没有源码包含,于是千辛万苦从别的sdk上挪了一个过来,加入各种mk文件中,还有各种依赖库,搞了两天终于编译完能在板子上跑起来了。
但是测试DLNA模式的手发现hostapd没有起来,所以根本不会有wifi热点出来。
查看了log,lollipop中没有打印什么错误信息。
要启动wifi热点一定要跑hostapd起来,有两种方式可以实现。
方式一:
在init.rc(或者类似xxx.rc)配置一个hostapd的service,然后在源代码中start这个服务
方式二:
直接在源代码中调用system或者用execl一类的函数来执行hostapd。
下面开始排查
第一步:
查看是否有配置调用hostapd的服务
果然在init.rc中看到一个hostapd服务,开机不运行,需要有人专门去start才行
service hostapd /system/bin/hostapd /data/misc/wifi/hostapd.conf
class main
disabled
oneshot
第二步
查看sdk中的源码,看下睡会去启动这个服务
第一个要找的就是lollipop部分,去里面cgrep一下
cgrep "hostapd"
./wifi/lollipop_softap.c:28:#define HOSTAPD_CONF_FILE "/data/misc/wifi/hostapd.conf"
./wifi/lollipop_softap.c:71: ALOGD("start hostapd ...");
./wifi/lollipop_softap.c:72: if(execl("/system/bin/hostapd", "/system/bin/hostapd",
./wifi/lollipop_softap.c:155: "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nhw_mode=g\nieee80211n=1\n"HT_CAPAB,
./wifi/lollipop_softap.c:268: /* TODO: implement over hostapd */
./socket_ipc/lollipop_socket_ipc.c:193: // chmod so hostapd which is wifi permission can send info to softap
这里没人启动hostapd服务,但是有人在调用hostapd执行档,进去
wifi/lollipop_softap.c
找到这个函数
int startSoftap(void)
50 int startSoftap(void) {
51 pid_t pid = 1;
52 int ret = 0;
53
54 if (mPid) {
55 ALOGE("Softap already started");
56 return 0;
57 }
58 #if NEED_SOCK
59 if (mSock < 0) {
60 ALOGE("Softap startap - failed to open socket");
61 return -1;
62 }
63 #endif
64 if ((pid = fork()) < 0) {
65 ALOGE("fork failed (%s)", strerror(errno));
66 return -1;
67 }
68
69 if (!pid) {
70 ensure_entropy_file_exists();
71 ALOGD("start rtl_hostapd ...");
72 if(execl("/system/bin/rtl_hostapd", "/system/bin/rtl_hostapd",
73 "-e", WIFI_ENTROPY_FILE,
74 HOSTAPD_CONF_FILE, (char *) NULL)) {
75 ALOGE("execl failed (%s)", strerror(errno));
76 }
77 ALOGE("Should never get here!");
78 return -1;
79 } else {
80 mPid = pid;
81 ALOGD("Softap startap - Ok");
82 usleep(AP_BSS_START_DELAY);
83 }
84 return ret;
85
86 }
接下来再去找谁会调用这个函数
cgrep "startSoftap"
./wifi/lollipop_softap.c:50:int startSoftap(void) {
./wifi/lollipop_softap.h:15:extern int startSoftap(void);
在lollipop里面是没人调用,croot回到android根目录查找
cgrep "startSoftap"
./system/netd/CommandListener.cpp:918: rc = sSoftapCtrl->startSoftap();
./system/netd/SoftapController.cpp:54:int SoftapController::startSoftap() {
./system/netd/SoftapController.h:51: int startSoftap();
./system/netd/SoftapController.h:58: virtual int startSoftap();
./system/netd/SoftapController.h:85: int startSoftap();
./system/netd/SoftapController.h:102: int startSoftap();
./external/lollipop_wifi/wifi/lollipop_softap.c:50:int startSoftap(void) {
./external/lollipop_wifi/wifi/lollipop_softap.h:15:extern int startSoftap(void);
发现至少有两个地方有可能调用,最后进去跟踪源码,确认了一下,里面是有调用hostapd,但是不是调用了lollipop里面的startSoftap函数而是自己用execl执行了hostapd,
system/netd/SoftapController.cpp
int SoftapController::startSoftap() {
55 pid_t pid = 1;
56
57 if (mPid) {
58 ALOGE("SoftAP is already running");
59 return ResponseCode::SoftapStatusResult;
60 }
61
62 if ((pid = fork()) < 0) {
63 ALOGE("fork failed (%s)", strerror(errno));
64 return ResponseCode::ServiceStartFailed;
65 }
66
67 if (!pid) {
68 ensure_entropy_file_exists();
69 if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE,
70 "-e", WIFI_ENTROPY_FILE,
71 HOSTAPD_CONF_FILE, (char *) NULL)) {
72 ALOGE("execl failed (%s)", strerror(errno));
73 }
74 ALOGE("SoftAP failed to start");
75 return ResponseCode::ServiceStartFailed;
76 } else {
77 mPid = pid;
78 ALOGD("SoftAP started successfully");
79 usleep(AP_BSS_START_DELAY);
80 }
81 return ResponseCode::SoftapStatusResult;
82 }
这部分接口是netd源码包里面的,netd也是一个wifi服务,可以通过ndc客户端给netd发送指令叫他干活,netd就可以实现wifi热点。
现在的线索又转移到了查找谁会调用ndc来发送指令,首先还是回去lollipop查找
cgrep "bin\/ndc"
./p2p_main.c:171: sprintf(cmd, "/system/bin/ndc softap fwreload %s STA", P2P_IFACE);
./softap_main.c:114: system("/system/bin/ndc ipfwd disable");
./softap_main.c:115: system("/system/bin/ndc softap stopap");
./softap_main.c:318: sprintf(cmd, "/system/bin/ndc softap fwreload %s AP", SOFTAP_IFACE);
./softap_main.c:354: sprintf(cmd, "/system/bin/ndc softap fwreload %s AP", SOFTAP_IFACE);
./softap_main.c:358: sprintf(cmd, "/system/bin/ndc softap set %s %s open", SOFTAP_IFACE, deviceName);
./softap_main.c:360: sprintf(cmd, "/system/bin/ndc softap set %s %s broadcast 6 wpa2-psk %s", SOFTAP_IFACE, deviceName, passwd);
./softap_main.c:381: system("/system/bin/ndc softap startap");
./softap_main.c:417: system("/system/bin/ndc ipfwd enable");
./wifi/lollipop_wifiMonitor.c:429: sprintf(buf, "/system/bin/ndc interface clearaddrs %s", wlan_iface);
./wifi/lollipop_wifiMonitor.c:495: sprintf(buf, "/system/bin/ndc nat enable %s %s 1 192.168.49.1/24", softap_iface, wlan_iface);
./wifi/lollipop_wifiMonitor.c:521: sprintf(buf, "/system/bin/ndc interface clearaddrs %s", wlan_iface);
./wifi/lollipop_wifiMonitor.c:527: sprintf(buf, "/system/bin/ndc nat disable %s %s", softap_iface, wlan_iface);
果然还是lollipop调用了ndc而且是用system去运行的,进去看了下源码,发现每次调用system执行没有检查返回值报错,所以没有调用成功根本不会有报错的log。
最大的坑还是板子上根本没有ndc和netd的执行档,sdk源码中没有包含netd的编译。
又回去检查了一下lollipop里面的Android.mk里面没有写ndc的依赖,源码里面又是调用system执行,所有这种依赖错误也是检查不出来的。
下面开始修正
第一步:
编译net源码,并在init.rc中配置netd的启动服务
service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
第二步:
修改lollipop中的源码在调用system的地方检查返回值报错
重新编译pack,烧录。
本以为这次热点应该起来了,结果大失所望,依然没有热点出来。
ps看了下netd在运行但是hostapd没有。但是log上看到了hostapd打印出了几条有用的错误信息,说明hostapd曾经来过,但是异常退出来了。
E/hostapd ( 1414): Configuration file: /data/misc/wifi/hostapd.conf
E/hostapd ( 1414): Could not select hw_mode and channel. (-3)
E/hostapd ( 1414): p2p0: Unable to setup interface.
E/hostapd ( 1414): Failed to initialize interface
拿着log跟踪了一下hostapd的源码,错误是从第二条开始的,第一条是个提示信息。
现在最早报错的是在操作hw_mod和channel的时候,这两个参数是从hostap.conf获取的,现在检查一下hostapd.conf
interface=p2p0
driver=nl80211
ctrl_interface=/data/misc/wifi/hostapd
ssid=LOLLIPOP-ECF21E
channel=12345678
ieee80211n=1
hw_mode=g
ignore_broadcast_ssid=0
很明显这个conf是有问题的,至少channel是错误的,12345678是设置给hostapd的明文密码, 在增加的log的可以看到调用ndc设置的,而且conf中psk等信息也没配置完全。
接下来就去查找hostapd.conf是在哪里配置的,找到异常的地方
D/lollipop_softap( 1517): 248 run /system/bin/ndc softap fwreload p2p0 AP ok
D/lollipop_softap( 1517): 292 run /system/bin/ndc softap set p2p0 LOLLIPOP-ECF21E wpa2-psk 12345678 ok
D/lollipop_softap( 1517): 352 run /system/bin/ndc ipfwd enable ok
设置的最初入口是ndc,现在就去找ndc的入口函数
int main(int argc, char **argv) {
39 int sock;
40 int cmdOffset = 0;
41
42 if (argc < 2)
43 usage(argv[0]);
44
45 // try interpreting the first arg as the socket name - if it fails go back to netd
46
47 if ((sock = socket_local_client(argv[1],
48 ANDROID_SOCKET_NAMESPACE_RESERVED,
49 SOCK_STREAM)) < 0) {
50 if ((sock = socket_local_client("netd",
51 ANDROID_SOCKET_NAMESPACE_RESERVED,
52 SOCK_STREAM)) < 0) {
53 fprintf(stderr, "Error connecting (%s)\n", strerror(errno));
54 exit(4);
55 }
56 } else {
57 if (argc < 3) usage(argv[0]);
58 printf("Using alt socket %s\n", argv[1]);
59 cmdOffset = 1;
60 }
61
62 if (!strcmp(argv[1+cmdOffset], "monitor"))
63 exit(do_monitor(sock, 0));
64 exit(do_cmd(sock, argc-cmdOffset, &(argv[cmdOffset])));
65 }
这里是第一个参数当做一个socket本地通信文件,去连接服务器(自己是客户端),如果连接失败了就走默认的netd通信连接,然后把后面的参数以此解析发送给netd服务器。
很明显第一次用socket_local_client连接argv[1]肯定会失败,因为lollipop调用ndc softap的时候自己并没有去启动(可以调用socket_local_server)一个基于softap文件的本地socket服务,所以每次都是连接到了netd,这样才能连接到netd。
现在参数已经传递给netd了,就得去跟踪netd里面是怎么样配置hostapd.conf。
执行/system/bin/ndc softap set p2p0 LOLLIPOP-ECF21E wpa2-psk 12345678的时候netd最后扔给了下面这个
setSoftap
函数
int SoftapController::setSoftap(int argc, char *argv[]) {
115 char psk_str[2*SHA256_DIGEST_LENGTH+1];
116 int ret = ResponseCode::SoftapStatusResult;
117 int i = 0;
118 int fd;
119 int hidden = 0;
120 int channel = AP_CHANNEL_DEFAULT;
121 char *wbuf = NULL;
122 char *fbuf = NULL;
123
124 if (argc < 5) {
125 ALOGE("Softap set is missing arguments. Please use:");
126 ALOGE("softap <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");
127 return ResponseCode::CommandSyntaxError;
128 }
129
130 if (!strcasecmp(argv[4], "hidden"))
131 hidden = 1;
132
133 if (argc >= 5) {
134 channel = atoi(argv[5]);
135 if (channel <= 0)
136 channel = AP_CHANNEL_DEFAULT;
137 }
138
139 asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
140 "/data/misc/wifi/hostapd\nssid=%s\nchannel=%d\nieee80211n=1\n"
141 "hw_mode=g\nignore_broadcast_ssid=%d\n",
142 argv[2], argv[3], channel, hidden);
143
144 if (argc > 7) {
145 if (!strcmp(argv[6], "wpa-psk")) {
146 generatePsk(argv[3], argv[7], psk_str);
147 asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
148 } else if (!strcmp(argv[6], "wpa2-psk")) {
149 generatePsk(argv[3], argv[7], psk_str);
150 asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
151 } else if (!strcmp(argv[6], "open")) {
152 asprintf(&fbuf, "%s", wbuf);
153 }
从126行代码示例使用demo
ALOGE("softap <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");
以及133-137行代码获取channel来看这个参数解析并不是很智能的,只是根据第几个参数来设置
而lollipop调用
/system/bin/ndc softap set p2p0 LOLLIPOP-ECF21E wpa2-psk 12345678
省略掉了broadcast和channel参数,导致解析出现错位了,把psk当做channel,后面需要解析psk的时候已经没有参数可用了,所以conf文件中没有psk
所以问题的根本原因是lollipop调用ndc的时候参数设置错乱。
找到出错的源码
if (strlen(passwd) == 0) {
286 sprintf(cmd, "/system/bin/ndc softap set %s %s Broadcast %d open", SOFTAP_IFACE, deviceName, channel);
287 } else {
288 sprintf(cmd, "/system/bin/ndc softap set %s %s wpa2-psk %s",
289 SOFTAP_IFACE, deviceName, passwd);
290 }
291
292 if(system(cmd)){
293 ALOGE("%d run %s failed:%s",__LINE__, cmd, strerror(errno));
294 }
295 else
296 ALOGD("%d run %s ok",__LINE__, cmd);
改成如下
if (strlen(passwd) == 0) {
286 sprintf(cmd, "/system/bin/ndc softap set %s %s Broadcast %d open", SOFTAP_IFACE, deviceName, channel);
287 } else {
288 sprintf(cmd, "/system/bin/ndc softap set %s %s Broadcast %d wpa2-psk %s",
289 SOFTAP_IFACE, deviceName, channel, passwd);
290 }
291
292 if(system(cmd)){
293 ALOGE("%d run %s failed:%s",__LINE__, cmd, strerror(errno));
294 }
295 else
296 ALOGD("%d run %s ok",__LINE__, cmd);
其中channel可以设置一个默认的或者从其他地方获取。
重新编译打包烧录
这次热点已经起来了
查看hostapd.conf
interface=p2p0
driver=nl80211
ctrl_interface=/data/misc/wifi/hostapd
ssid=LOLLIPOP-ECF21E
channel=6
ieee80211n=1
hw_mode=g
ignore_broadcast_ssid=0
wpa=2
rsn_pairwise=CCMP
wpa_psk=164934815f6e071f26f8bb59db883daf3ef09bb7df3c6903c082a881370a5d42
这次是ok的了
E/hostapd ( 1538): Configuration file: /data/misc/wifi/hostapd.conf
E/hostapd ( 1538): Using interface p2p0 with hwaddr 7e:dd:90:ec:f2:1e and ssid "LOLLIPOP-ECF21E"
I/hostapd ( 1538): random: Only 15/20 bytes of strong random data available from /dev/random
I/hostapd ( 1538): random: Allow operation to proceed based on internal entropy
这次热点LOLLIPOP-ECF21E已经出来了,可以连接ok。
-----------------------------------------------------------------------------------
现在总结一下调用的流程
首先是lollipop解析lollipop.conf文件获取到DLNA的模式
然后启动了lollipop_softap服务(执行lollipop_softap)
lollipop_softap调用ndc执行档发送了设置和启动指令,设置了hostapd启动参数,并启动softap。
ndc将接收到的指令解析完通过本地socket netd发送参数及命令给netd服务。
netd服务配置生成了hostapd.conf,并调用/system/bin/hostapd启动了hostapd。
lollipop ---> lollipop_softap ---> ndc --> netd --->hostapd
lollipop_softap启动wifi ap失败的更多相关文章
- win7下设置 WiFi AP
开启windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP),就可以让计算机变成无线路由器.实现共享上网. 1.以管理员身份运行命令提示符: “开始”---在搜索栏输入“cmd”-- ...
- Arduino IDE for ESP8266教程(二) 创建WIFI AP模式
创建WIFI热点 #include <ESP8266WiFi.h> void setup() { Serial.begin ( 115200 ); Serial.println(" ...
- vs2015启动iis express失败
vs2015启动web项目失败,查看日志 IIS Express\aspnetcore.dll 未能加载 ,解决方法 下载 VSorVWDASPNETCore.exe (https://www.asp ...
- selenium webdriver启动IE浏览器失败的解决办法
通过selenium webdriver启动IE浏览器失败,报错:selenium.common.exceptions.WebDriverException: Message: Unexpected ...
- WebSphere服务器已启动但是初始化失败问题
--WebSphere服务器已启动但是初始化失败问题 -----------------------------------------------2014/03/06 经常有开发同事反映,环境用着用 ...
- 树莓派3启动wifi并且配置wifi
概述 树莓派3内置了wifi和蓝牙模块,我们不用像以前的版本那样,再去购买一个外接的模块练到raspberry上. 当我们第一次启动了树莓派的时候,必然使用了网线,但是之后的每一次使用,我们当然更希望 ...
- 安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details"错误.原因是启动"VisualSVN Server"失败
安装VisualSVN Server 报"Service 'VisualSVN Server' failed to start. Please check VisualSVN Server ...
- Activiti启动某个流程失败,页面报500
现象:Activiti启动某个流程失败,页面报500,错误日志如下. 2017-06-19 10:50:09 [org.activiti.engine.impl.interceptor.Command ...
- “一键制作启动u盘失败”的主要原因是什么?
一键制作启动u盘失败的主要原因是什么?今天u启动小编就和大家一起来分析原因并寻求答案吧! 原因分析: 1.u盘内有文件正在运行或者是打开: 2.u盘自身的质量问题: 3.最主要的原 ...
随机推荐
- 为什么要设置GOROOT/GOPATH
设置GOROOT的原因 编译器的位置指定的时候,需要指定GO开发包的安装位置,然后设置环境变量PATH的时候,需要指定到安装包下的bin目录,其中就有以下的编译/执行器.所以GOROOT指定了前面的路 ...
- dede调用文章内第一张原始图片(非缩略图)的实现方法
第一步,修改include/extend.func.php文件,最下面插入函数,查询的是文章附加表,如需查询图片集什么的,改表名即可 //取原图地址 function GetFirstImg($arc ...
- 哪5种IO模型?什么是select/poll/epoll?同步异步阻塞非阻塞有啥区别?全在这讲明白了!
系统中有哪5种IO模型?什么是 select/poll/epoll?同步异步阻塞非阻塞有啥区别? 本文地址http://yangjianyong.cn/?p=84转载无需经过作者本人授权 先解开第一个 ...
- 超详细的VMware安装ubuntu教程
确定,然后重启.
- WireShark基础用法
特点 免费 开源 跨平台 抓包原理 内部原理 抓取网卡 抓包环境 抓取本地数据 抓取外部数据 利用hub 流量镜像span.rspan.erspan 界面介绍.首选项.抓包选项 界面介绍 菜单栏 帮助 ...
- django 如何在HMTL中使用媒体media_url
django 如何在HMTL中使用媒体media_url中指定的路径 第一种: 一. setting.py里,一般图片或者文件上传路径都是是以下设置, MEDIA_URL = '/media/' ...
- 『Python』列表生成式、生成器与迭代器
1. 迭代 在 Python中, 迭代是通过 for ... in 来完成的, 而很多语言比如 C 语言, 迭代 list 是通过下标完成的. Python 的 for 循环抽象程度要高于 C 的 f ...
- P6847-[CEOI2019]Magic Tree【dp,线段树合并】
正题 题目链接:https://www.luogu.com.cn/problem/P6847 题目大意 \(n\)个点的一棵树上,每个时刻可以割掉一些边,一些节点上有果实表示如果在\(d_i\)时刻这 ...
- 1.pytest初尝试
语法规范 pytest命令会默认执行以 -- test_**.py -- 或 -- **_test.py -- 命名文件的测试用例 pytest的测试用例必须以 -- test -- 开头 def t ...
- The art of multipropcessor programming 读书笔记-硬件基础2
本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...