zoukankan      html  css  js  c++  java
  • 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
    ssid=%s
    channel=6
    hw_mode=g
    ieee80211n=1
    "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)
    ", strerror(errno));      
      54             exit(4);                                                          
      55         }                                                                     
      56     } else {                                                                  
      57         if (argc < 3) usage(argv[0]);                                         
      58         printf("Using alt socket %s
    ", 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
    driver=nl80211
    ctrl_interface="           
     140             "/data/misc/wifi/hostapd
    ssid=%s
    channel=%d
    ieee80211n=1
    "    
     141             "hw_mode=g
    ignore_broadcast_ssid=%d
    ",                          
     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
    wpa_pairwise=TKIP CCMP
    wpa_psk=%s
    ", wbuf, psk_str);
     148         } else if (!strcmp(argv[6], "wpa2-psk")) {                            
     149             generatePsk(argv[3], argv[7], psk_str);                           
     150             asprintf(&fbuf, "%swpa=2
    rsn_pairwise=CCMP
    wpa_psk=%s
    ", 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

  • 相关阅读:
    POJ 1300 Open Door
    POJ 2230 Watchcow
    codevs 1028 花店橱窗布置
    codevs 1021 玛丽卡
    codevs 1519 过路费
    codevs 3287 货车运输
    codevs 3305 水果姐逛水果街二
    codevs 1036 商务旅行
    codevs 4605 LCA
    POJ 1330 Nearest Common Ancestors
  • 原文地址:https://www.cnblogs.com/tid-think/p/10938805.html
Copyright © 2011-2022 走看看