lollipop_softap啓動wifi ap失敗

最近一直在調試lollipop,翻譯成中文好像是棒棒糖的意思,就是個wifi控制管理工具,好比設置DLNA或者WFD模式等,其原理是經過本地通訊工具sockets控制其餘接口來啓動wpa_suplicant或者hostapd,從而實現功能,因此這裏面涉及的還有wpa_supplicant工具包,以及netd,netd就是個服務器,接受ndc(客戶端)的指令來執行動做,好比設置hostapd須要的參數,生成hostapd.conf文件,最後啓動hostapd應用等。。android

lollipop裏面包含好幾個bin工具c++

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的板子上。dom

拿到手的時候sdk中wpa_suplicant沒有被包含編譯,lollipop也沒有源碼包含,因而千辛萬苦從別的sdk上挪了一個過來,加入各類mk文件中,還有各類依賴庫,搞了兩天終於編譯完能在板子上跑起來了。socket

可是測試DLNA模式的手發現hostapd沒有起來,因此根本不會有wifi熱點出來。函數

查看了log,lollipop中沒有打印什麼錯誤信息。工具

要啓動wifi熱點必定要跑hostapd起來,有兩種方式能夠實現。測試

方式一:spa

在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

相關文章
相關標籤/搜索