本文轉載自:http://blog.csdn.net/DKBDKBDKB/article/details/38490201
對wifi部分的代碼流程已經看了段時間,前兩天終於解決了工作中遇到的一個wifi問題,問題描述及解決過程如下:
硬件平台:iMx53
軟件平台:Android2.3
bug描述:1,選中熱點,輸入密碼之后,會顯示“正在獲取ip地址。。。”,之后變為已保存而沒有連接。
2,系統在wifi連接的前提下,重新上電,無法自動連接已保存的wifi熱點。
3,系統wifi連接后,過一段時間自動斷開,wifi圖標變暗。
首先,感覺wifi連接后自動斷開這種情況,Android上層應該還算是比較智能的,已連接的wifi在斷開后肯定會有嘗試自動重連的邏輯實現,但是從log看,connection是有reset和reconnect但是均失敗了,沒有重連成功。所以開始繼續向下分析重連失敗的原因,最終發現了dhcp的疑點很大:
DHCP request error:Timed out waiting for dhcpcd to start
這是出問題的時候log中通常出現的部分:dhcp start 失敗。代碼在/system/core/libnetutils/dhcp_utils.c 里邊實現。start失敗的原因是由於在指定的時間內,init.svc.dhcpcd_wlan0這個prop沒有變為“running”態,於是,我在wait_for_property函數中做了重新開啟的改動,添加代碼如下:
- if (strcmp(name, "init.svc.dhcpcd_wlan0") == 0 && \
- strcmp(desired_value, "running") == 0) {
- if (maxnaps == 7) {
- property_set("ctl.start", "dhcpcd_wlan0");
- LOGD("kevin 1st set init.svc.dhcpcd_wlan0");
- } else if (maxnaps == 4) {
- property_set("ctl.start", "dhcpcd_wlan0");
- LOGD("kevin 2nd set init.svc.dhcpcd_wlan0");
- }
- }
問題有了很大改善,此后不會再出現start失敗的問題,但隨之而來的問題出現了:系統重新上電之后,wifi圖標顯示已連接,但是點擊連接上的wifi熱點,在彈出的的窗口里邊沒有ip地址,而此時上層的app確實不能上網,因為點擊熱點的彈窗是通過get_property接口獲取的一系列屬性信息,所以分析是兩種可能:1,上層沒捕獲到property;2,底層沒有把相應的property set進去。第一種可能性很低,所以直接從第二種情況入手分析,發現這些屬性是在dhcp_start接近尾聲的時候,通過dhcp的一些腳本執行set進去(/external/dhcpcd/dhcpcd-hooks 腳本路徑),設置成功會將property “dhcp.wlan0.result” 設置為“OK”, 此時才能保證上層可獲取相應的property, 鑒於此,分析還是dhcp start沒有正常啟動,因此在/system/core/libnetutils/dhcp_utils.c 里實現的自己的新接口:dhcp_reset(),具體實現如下
- static const char DHCP_SERVER[] ="dhcpcd_wlan0";
- static const char DHCP_PROP[] ="init.svc.dhcpcd_wlan0";
- static const char DHCP_RES[] ="dhcp.wlan0.result";
- static int dhcp_reset()
- {
- int stop_wait = 5;
- int start_wait = 10;
- int result_wait = 20;
- char kvalue[PROPERTY_VALUE_MAX] = {'\0'};
- LOGD("kevin start dhcp_reset");
- property_set("ctl.stop", DHCP_SERVER);
- while (stop_wait-- > 0) {
- usleep(500000);
- if (property_get(DHCP_PROP, kvalue, NULL)) {
- if (strcmp(kvalue, "stopped") == 0) {
- LOGD("kevin: property name is %s get_Value \
- is %s and desired_value is stopped", DHCP_PROP, kvalue);
- break;
- }
- }
- }
- property_set("ctl.start", DHCP_SERVER);
- while (start_wait-- > 0) {
- usleep(500000);
- if (property_get(DHCP_PROP, kvalue, NULL)) {
- if (strcmp(kvalue, "running") == 0) {
- LOGD("kevin: property name is %s get_Value \
- is %s and desired_value is running", DHCP_PROP, kvalue);
- break;
- }
- }
- }
- while (result_wait-- > 0) {
- usleep(500000);
- if (property_get(DHCP_RES, kvalue, NULL)) {
- if (strcmp(kvalue, "ok") == 0) {
- LOGD("kevin: property name is %s get_Value \
- is %s and desired_value is ok", DHCP_RES, kvalue);
- return 0;
- }
- }
- }
- return -1; /* failure */
- }
此外,wait_for_property()函數需要增加如下代碼:
- if (strcmp(name, "dhcp.wlan0.result") == 0 \
- && (maxnaps == 12|| maxnaps == 8)) {
- if (maxnaps == 12)
- LOGD("kevin 1st reset_dhcp");
- else
- LOGD("kevin 2nd reset_dhcp");
- if (dhcp_reset() == 0)
- LOGD("kevin dhcp_reset success");
- else
- LOGD("kevin dhcp_reset failed");
- }
實現機制是在等待dhcp.wlan0.result最終有沒有正常set的過程中,伺機dhcp_reset,判斷依據是,超出了正常啟動並設置屬性的時間段后,則調用dhcp_reset重新啟動dhcp服務,注意此時不能盲目的直接利用“ctl.start”開啟dhcp,因為可能會導致系統中同時運行多個dhcp進程,因此需要先stop,然后在start(這是我的個人理解)。
至此,dhcp導致的wifi一系列問題告一段落,宣布解決!
如有任何問題,歡迎討論,如有錯誤,還望高人指點。