和菜鸟一起学android4.0.3源码之US…

来源:互联网 发布:html2fpdf.php下载 编辑:程序博客网 时间:2024/04/28 16:09
一天又过去了,台风也走了有些时候了。想了想,自己还是冲动了一把,不该发那个邮件的,既然发了,也不后悔了。知道了所有也未必不是一件好事。恩,剩下的就好好做自己要做的事情吧。对于usbwifi,老早就在调试了,只是碰到了很多问题,加上其他的事情也迎面而来,从而导致很多的困难,也就搁置着了。上上周,工作计划一周内要搞定,郁闷着了,这个涉及到的太多太多了,不好移植啊。只能加班了,天天看代码了。在移植完bluetooth后,马上开始wifi的移植。终于,功夫不负有心人,前天晚上解决了可恶的权限问题导致不能socket通信。可以连上路由器,但是分配IP地址还是要命令的。还有就是nfs挂载的时候,网络貌似只是通过本地连接的,而不是从wifi来的,所以只能ping通路由和本地的连接,至于外网,要用SD卡启动才可以连接。下面对于整个移植过程做下简单的记录。

        首先那肯定是要在linuxkernel下选上相应的选项了,在此之前要有wifi的驱动。

 

Networkingsupport下选上

上面主要是选上相关的通信的协议,802.11啊什么的。

然后wifi的设备也要选上

选上自己的wifi设备驱动,我是选择编译进内核的,不是编译成模块的,而按照android源码中可以知道,其实是要编译成模块,不断去加载什么的。不过编译进内核后,修改下android下的源码也是可以解决问题的。

       好了,准备好了linuxkernel后,那么基本上如果跑linux的话,用wireless-tools这个工具就可以测试了

[html] view plaincopy
  1. ./iwlist wlan0 scanning  
  2.   
  3. ./iwconfig wlan0 mode managed  
  4.   
  5. ./iwconfig wlan0 essid “你要连接的路由”  
  6.   
  7. ./ifconfig wlan0 要为wifi设置的静态IP netmask 255.255.255.0 up  


       然后就可以ping通你的路由了,如果成功了,那么说明wifi的驱动没多大的问题,接着就可以上android去调试了。

       现在想想,其实androidwifi适配其实也算简单的,只是对于网络不是很懂,所以才觉得有难度。先讲讲androidwifi的一些代码主要的目录吧。

1、 wpa_supplicant: 这个最最纠结了,主要也就是这个东东了,这个好了,那基本上就没什么问题了。Wpa就是应

      用层认证客户端,负责完成认证相关登陆,加密等工作。

       external/wpa_supplicant_8/下,通过mm后可以生成动态库libwpa_client.so和可执行的程序wpa_supplicantwpa_cli

2、 wpa_supplicant适配层:封装与wpa_supplicant守护进程的通信,以提供给android框架使用,实现加载,控制和消

      息监控等功能。

      hardware/libhardware_legacy/wifi/下,而我用的是厂家提供的,所以是修改过的,其实都一样的。

3、 wifi的JNI    frameworks//base/core/jni/android_net_wifi_wifi.cpp

      wifi的服务层: frameworks/base/services/java/com/android/server/WifiService.java

      wifi的部分接口:frameworks/base/wifi/java/android/net/wifi

      对于android层,本人没有做任何修改,上层基本上是好的,只要wpa_supplicant和底层通信好了,那么整个适配就没什么问题了。

      接下来就开始真正的移植吧。

       主要是android有那个什么破权限,搞得我很是郁闷。其实还是自己经验不足啊,刚刚毕业也在所难免啊。先改下权限吧,在init.rc

[html] view plaincopy
  1. mkdir /data/misc/wifi 0777 wifi wifi  
  2.   
  3. chmod 0777 /data/misc/wifi/wpa_supplicant.conf  
  4.   
  5. mkdir /wlan0 0777 wifi wifi   

 

       因为编译进内核的,所以加上下面两句

[html] view plaincopy
  1. #prepare for wifi  
  2.   
  3.        setprop wifi.interface “wlan0”  
  4.   
  5.         setprop wlan.driver.status “ok”  


 

init.xxx.rc中添加下面的

  

[html] view plaincopy
  1. mkdir /data/misc/wifi/sockets 0777 wifi wifi  
  2.   
  3.   mkdir /data/misc/dhcp 0777 dhcp dhcp  
  4.   
  5.   chmod 0777  /dev/rfkill  


又和蓝牙一样,有一个rfkill,所以得给他修改下权限。

 

[html] view plaincopy
  1. service  wpa_supplicant /system/bin/wpa_supplicant –dd –Dwext –iwlan0 –c/data/misc/wifi/wpa_supplicant.conf  
  2.   
  3.        class main  
  4.   
  5.        #socket wpa_wpa_wlan0 dgram 0777 wifi wifi   
  6.   
  7.        group system inet  
  8.   
  9.         disabled  
  10.   
  11.         oneshot  


 

[html] view plaincopy
  1. service dhcpcd_wlan0 /system/bin/dhcpcd –d –B wlan0  
  2.   
  3.        class main  
  4.   
  5.        disabled   
  6.   
  7.        oneshot  


 

       好了,主要修改这些,基本上没有什么提示权限问题了。接着要把那个

wpa_supplicant.conf加进去,里面的内容一般可以如下:

[html] view plaincopy
  1. ctrl_interface=wlan0  
  2.   
  3. update_config=1  
  4.   
  5. ap_scan=1  
  6.   
  7. fast_reauth=1  


      接着在修改下wifi.c中的代码

[html] view plaincopy
  1. static const char IFACE_DIR[]           "/data/system/wpa_supplicant";  


这个修改为

[html] view plaincopy
  1. static const char IFACE_DIR[]           "/wlan0";  


[html] view plaincopy
  1. static int insmod(const char *filename, const char *args)  


这个函数第一行就return0。因为编译进内核,没有模块。

[html] view plaincopy
  1. static int rmmod(const char *modname)  

这个函数同上。

       恩,基本上搞定了,还有就是要在相应的平台下把wifi的相关宏定义给选上。举个例子,比如说你的平台是samsungTuna平台,那么在device/Samsung/Tuna/BoardConfig.mk中有几个宏必须选上

      

[html] view plaincopy
  1. BOARD_WIFI_VENDOR :=realtek  
  2.   
  3.        WPA_SUPPLICANT_VERSION :VER_0_8_X  
  4.   
  5.        BOARD_WPA_SUPPLICANT_PRIVATE_LIB :lib_drivercmd_wext  
  6.   
  7.        BOARD_WLAN_DEVICE :rtl8192cu  


 

       好了,然后就到相应的目录下去编译生成相关的.so和可执行应用程序吧

Hardware/libhardware_legacy/mm后得到了libhardware_legacy.so

       然后再到

external/wpa_supplicant_8/mm后得到了wpa_cli,wpa_supplicantlibwpa_client.so

 

       好了,接着可以启动了,在此,还是先用命令行,上面的那两个服务先注释掉,然后开始去启动。

启动后,首先就是查看下底层驱动有没有运行,主要就是cat /proc/net/devwlan0的话,那么就说明ok了。接着就是要连接上wpa_supplicant

[html] view plaincopy
  1. wpa_supplicant –dd –Dwext –iwlan0 –c/data/misc/wifi/wpa_supplicant.conf  


让他后台运行着就好了。

就这就

[html] view plaincopy
  1. wpa_cli –iwlan0 –p/wlan0  


然后再

Scan (搜索网络)

接着scan_res(显示搜索结果,如果可以搜到网络的话,那么几乎就可以说是成功了)

接着就

[html] view plaincopy
  1. add_net  
  2.   
  3. set_net ssid “相应搜到的网络”  
  4.   
  5. set_net key_mgmt NONE  
  6.   
  7. set_net priority  
  8.   
  9. list_net  
  10.   
  11. save_config  
  12.   
  13. enable_net  


这样就可以启动了,然后再

[html] view plaincopy
  1. dhcpcd wlan0  


分配一个ip地址,接着去ping路由,就可以ping的通了,那么一直基本上告一段落。

 

不过这个是命令行的,得让他在UI界面出来,于是还是启动服务吧,可是一直wpa_supplicant的时候就不成功,老是有问题。跟进代码,当上层开关打开后就会调用到下面这个函数去连接wpa_supplicant

[html] view plaincopy
  1. /hardware/libhardware_legacy/wifi.c  
  2.   
  3. int wifi_connect_to_supplicant()  
  4.   
  5.  
  6.   
  7.     char ifname[256];  
  8.   
  9.     char supp_status[PROPERTY_VALUE_MAX] {'\0'};  
  10.   
  11.    
  12.   
  13.       
  14.   
  15.     if (!property_get(SUPP_PROP_NAME, supp_status, NULL)  
  16.   
  17.             || strcmp(supp_status, "running") != 0)  
  18.   
  19.         LOGE("Supplicant not running, cannot connect");  
  20.   
  21.         return -1;  
  22.   
  23.      
  24.   
  25.    
  26.   
  27.     if (access(IFACE_DIR, F_OK) == 0)  
  28.   
  29.         snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);  
  30.   
  31.     else  
  32.   
  33.         strlcpy(ifname, iface, sizeof(ifname));  
  34.   
  35.      
  36.   
  37.    
  38.   
  39.     ctrl_conn wpa_ctrl_open(ifname);  
  40.   
  41.     if (ctrl_conn == NULL)  
  42.   
  43.         LOGE("Unable to open connection to supplicant on \"%s\": %s",  
  44.   
  45.              ifname, strerror(errno));  
  46.   
  47.         return -1;  
  48.   
  49.      
  50.   
  51.     monitor_conn wpa_ctrl_open(ifname);  
  52.   
  53.     if (monitor_conn == NULL)  
  54.   
  55.         wpa_ctrl_close(ctrl_conn);  
  56.   
  57.         ctrl_conn NULL 
  58.   
  59.         return -1;  
  60.   
  61.      
  62.   
  63.     if (wpa_ctrl_attach(monitor_conn) != 0)  
  64.   
  65.         wpa_ctrl_close(monitor_conn);  
  66.   
  67.         wpa_ctrl_close(ctrl_conn);  
  68.   
  69.         ctrl_conn monitor_conn NULL;  
  70.   
  71.         return -1;  
  72.   
  73.      
  74.   
  75.    
  76.   
  77.     if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1)  
  78.   
  79.         wpa_ctrl_close(monitor_conn);  
  80.   
  81.         wpa_ctrl_close(ctrl_conn);  
  82.   
  83.         ctrl_conn monitor_conn NULL;  
  84.   
  85.         return -1;  
  86.   
  87.      
  88.   
  89.    
  90.   
  91.     return 0;  
  92.   
  93.  


 

       这里的ifname=/wlan0/wlan0,这样,两个接口ctrl_connmonitor_conn都可以正常打开,可是到了wpa_ctrl_attach(monitor_conn)的时候就一直不可以,而用命令行的时候都是可以的

继续跟进代码

[html] view plaincopy
  1. external/wpa_supplicant_8/src/common/wpa_ctrl.c  
  2.   
  3.    
  4.   
  5. #ifdef CTRL_IFACE_SOCKET  
  6.   
  7. int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,  
  8.   
  9.                    char *reply, size_t *reply_len,  
  10.   
  11.                    void (*msg_cb)(char *msg, size_t len))  
  12.   
  13.  
  14.   
  15.        struct timeval tv;  
  16.   
  17.        int res;  
  18.   
  19.        fd_set rfds;  
  20.   
  21.        const char *_cmd;  
  22.   
  23.        char *cmd_buf NULL 
  24.   
  25.        size_t _cmd_len;  
  26.   
  27.    
  28.   
  29. #ifdef CONFIG_CTRL_IFACE_UDP  
  30.   
  31.        if (ctrl->cookie)  
  32.   
  33.               char *pos;  
  34.   
  35.               _cmd_len os_strlen(ctrl->cookie) cmd_len;  
  36.   
  37.               cmd_buf os_malloc(_cmd_len);  
  38.   
  39.               if (cmd_buf == NULL)  
  40.   
  41.                      return -1;  
  42.   
  43.               _cmd cmd_buf 
  44.   
  45.               pos cmd_buf 
  46.   
  47.               os_strlcpy(pos, ctrl->cookie, _cmd_len);  
  48.   
  49.               pos += os_strlen(ctrl->cookie);  
  50.   
  51.               *pos++ ';  
  52.   
  53.               os_memcpy(pos, cmd, cmd_len);  
  54.   
  55.        else  
  56.   
  57. #endif   
  58.   
  59.         
  60.   
  61.               _cmd cmd 
  62.   
  63.               _cmd_len cmd_len 
  64.   
  65.         
  66.   
  67.    
  68.   
  69.        if (send(ctrl->s, _cmd, _cmd_len, 0) <</span> 0 
  70.   
  71.               os_free(cmd_buf);  
  72.   
  73.               return -1;  
  74.   
  75.         
  76.   
  77.        os_free(cmd_buf);  
  78.   
  79.    
  80.   
  81.        for (;;)  
  82.   
  83.               tv.tv_sec 10 
  84.   
  85.               tv.tv_usec 0 
  86.   
  87.               FD_ZERO(&rfds);  
  88.   
  89.               FD_SET(ctrl->s, &rfds);  
  90.   
  91.               res select(ctrl->1, &rfds, NULL, NULL, &tv);  
  92.   
  93.               if (res <</span> 0 
  94.   
  95.                      return res;  
  96.   
  97.               if (FD_ISSET(ctrl->s, &rfds))  
  98.   
  99.                      res recv(ctrl->s, reply, *reply_len, 0);  
  100.   
  101.                      if (res <</span> 0 
  102.   
  103.                             return res;  
  104.   
  105.                      if (res > && reply[0] == '<</span>')  
  106.   
  107.                               
  108.   
  109.                             if (msg_cb)  
  110.   
  111.                                      
  112.   
  113.                                    if ((size_t) res == *reply_len)  
  114.   
  115.                                           res (*reply_len) 1;  
  116.   
  117.                                    reply[res] '\0';  
  118.   
  119.                                    msg_cb(reply, res);  
  120.   
  121.                              
  122.   
  123.                             continue;  
  124.   
  125.                       
  126.   
  127.                      *reply_len res 
  128.   
  129.                      break;  
  130.   
  131.               else  
  132.   
  133.                      return -2;  
  134.   
  135.                
  136.   
  137.         
  138.   
  139.        return 0;  
  140.   
  141.  
  142.   
  143. #endif   
  144.   
  145.    


       也没有什么不同啊,不过在res =select(ctrl->s + 1, &rfds, NULL, NULL,&tv);

         这个函数的时候就出问题了,看传的参数什么的也都没有问题啊,为什么命令行可以,这个服务启动就有问题呢,继续看看,那个wpa_supplicant有收到发的命令吗?怀疑通信有问题。

好吧,那就继续跟进吧。。。

 

[html] view plaincopy
  1. external/wpa_supplicant_8/wpa_supplicant/ctrl_iface_unix.c  
  2.   
  3.    
  4.   
  5. static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,  
  6.   
  7.                                          void *sock_ctx)  
  8.   
  9.  
  10.   
  11.        struct wpa_supplicant *wpa_s eloop_ctx 
  12.   
  13.        struct ctrl_iface_priv *priv sock_ctx 
  14.   
  15.        char buf[4096];  
  16.   
  17.        int res;  
  18.   
  19.        struct sockaddr_un from;  
  20.   
  21.        socklen_t fromlen sizeof(from);  
  22.   
  23.        char *reply NULL 
  24.   
  25.        size_t reply_len 0 
  26.   
  27.        int new_attached 0 
  28.   
  29.    
  30.   
  31.        res recvfrom(sock, buf, sizeof(buf) 1, 0,  
  32.   
  33.                      (struct sockaddr *) &from, &fromlen);  
  34.   
  35.        if (res <</span> 0 
  36.   
  37.               perror("recvfrom(ctrl_iface)");  
  38.   
  39.               return;  
  40.   
  41.         
  42.   
  43.        buf[res] '\0';  
  44.   
  45.    
  46.   
  47.        if (os_strcmp(buf, "ATTACH") == 0)  
  48.   
  49.               if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))  
  50.   
  51.                      reply_len 1 
  52.   
  53.               else  
  54.   
  55.                      new_attached 1 
  56.   
  57.                      reply_len 2 
  58.   
  59.                
  60.   
  61.        else if (os_strcmp(buf, "DETACH") == 0)  
  62.   
  63.               if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))  
  64.   
  65.                      reply_len 1 
  66.   
  67.               else  
  68.   
  69.                      reply_len 2 
  70.   
  71.        else if (os_strncmp(buf, "LEVEL ", 6) == 0)  
  72.   
  73.               if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,  
  74.   
  75.                                               buf 6))  
  76.   
  77.                      reply_len 1 
  78.   
  79.               else  
  80.   
  81.                      reply_len 2 
  82.   
  83.        else  
  84.   
  85.               reply wpa_supplicant_ctrl_iface_process(wpa_s, buf,  
  86.   
  87.                                                    &reply_len);  
  88.   
  89.         
  90.   
  91.    
  92.   
  93.        if (reply)  
  94.   
  95.               sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,  
  96.   
  97.                      fromlen);  
  98.   
  99.               os_free(reply);  
  100.   
  101.        else if (reply_len == 1)  
  102.   
  103.               sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,  
  104.   
  105.                      fromlen);  
  106.   
  107.        else if (reply_len == 2)  
  108.   
  109.               sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,  
  110.   
  111.                      fromlen);  
  112.   
  113.         
  114.   
  115.    
  116.   
  117.        if (new_attached)  
  118.   
  119.               eapol_sm_notify_ctrl_attached(wpa_s->eapol);  
  120.   
  121.  


 

       这回彻底无语了。收到的buf也是"ATTACH",也运行到了sendto(sock, "OK\n", 3, 0, (structsockaddr *) &from,fromlen);为什么呢?明明一模一样的啊,可是命令行可以,android启动个服务就死在这里了。纠结了一天也不知道什么原因。

       想想不对啊,最后看了下生成的那个用来通信的接口,/data/misc/wifi/sockets/下的权限是system,而/wlan0/wlan0这个接口的权限是wifi,难道是这个问题?而命令行的时候/data/misc/wifi/sockets/下的权限是wifi,好吧,看来就是这个问题了,有了定位,那么事情就好办多了,接着想想那个权限到底怎么给设置上去的呢?找了好久发现了一个小问题。

 

[html] view plaincopy
  1. external/wpa_supplicant_8/hostapd/src/utrls/os-unix.c  
  2.   
  3.    
  4.   
  5. int os_program_init(void)  
  6.   
  7.  
  8.   
  9. #ifdef ANDROID  
  10.   
  11.          
  12.   
  13.        gid_t groups[] AID_INET, AID_WIFI, AID_KEYSTORE };  
  14.   
  15.        struct __user_cap_header_struct header;  
  16.   
  17.        struct __user_cap_data_struct cap;  
  18.   
  19.    
  20.   
  21.        setgroups(sizeof(groups)/sizeof(groups[0]), groups);  
  22.   
  23.    
  24.   
  25.        prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);  
  26.   
  27.    
  28.   
  29.        setgid(AID_WIFI);  
  30.   
  31.        setuid(AID_WIFI);  
  32.   
  33.    
  34.   
  35.        header.version _LINUX_CAPABILITY_VERSION 
  36.   
  37.        header.pid 0 
  38.   
  39.        cap.effective cap.permitted  
  40.   
  41.               (1 <</span><</span> CAP_NET_ADMIN(1 <</span><</span> CAP_NET_RAW);  
  42.   
  43.        cap.inheritable 0 
  44.   
  45.        capset(&header, &cap);  
  46.   
  47. #endif   
  48.   
  49.    
  50.   
  51. #ifdef WPA_TRACE  
  52.   
  53.        dl_list_init(&alloc_list);  
  54.   
  55. #endif   
  56.   
  57.        return 0;  
  58.   
  59.  


 

       可恶的,应该就是这了   gid_t groups[] = { AID_INET, AID_WIFI,AID_KEYSTORE然后把#ifdef ANDROID改为#if 0重新编译,启动,终于可以在androidUI界面里搜索到网络并且连接上了。OK,调试完成,接着就是整理完善了。

       坎坎坷坷,总算把wifi给适配好了,主要还是经验不足啊,相信通过不断的努力,我可以很快进步,相信把所做的总结下来,记录下来,不仅可以帮到别人,也可以不断提高自己,完善自己。

 

补充:

关于IP的自动获取不成功的问题,下午找了下原因还是那个恶心的权限问题,因为我是用的unix标准的sockets,而不是android内部的sockets,所以出问题了。只要在

External/dhcpcd/dhcpcd.c中头文件的位置加上以下几句,然后再mm生成的dhcpcd就可以了

[html] view plaincopy
  1. #ifdef ANDROID  
  2.   
  3. #undef ANDROID  
  4.   
  5. #endif  


ok,至此,USBwifi的移植就完全成功了。好好回去休息吧,又是周末了。。

0 0
原创粉丝点击