WiFiAp探究实录--功能实现与源码分析

这篇博客深入探讨了Android系统中WiFi热点(WiFiAp)的功能实现与源码分析。内容涵盖WiFiAp的IP配置、config管理、设备连接列表的读取和更新、连接限制以及源码流程。文章详细阐述了从UI到源码层面的实现过程,涉及多个关键类如WifiApConfigStore、WifiServiceImpl和WifiStateMachine等。
摘要由CSDN通过智能技术生成

接下来要更新的博文是WiFi热点相关的,更新时间为8月1号–8月30号之间。看到此博文的开发者们,如果有关于WiFi热点的任何疑问可留言,最终会将值得研究的问题以及我已经研究出来的问题更新在博文上。
Android虐我千百遍,我待Android如初恋。

转载注明出处 本文出自fanfanWiFi热点探究实录



——————编辑于2017-08-02———————
wifi热点说的是wifiAp相关,所以如果源码开发的话,这个WifiAp算是一个搜索代码的关键字,含义是Wifi Access point,wifi接入点。所以下文中的wifi热点统一用WifiAp代替

  1. wifiAp打开方式:设置->更多->移动网络共享->便携式wlan热点。
  2. wifiAp打开条件:任何情况下均可。只是有内网外网之分。造成内外网之分的影响条件有sim卡和wifi的连接状态。注意,这里所说的是wifi的连接状态,而不是wifi热点的连接状态
  3. wifiAp开发中用处:可用于局域网内的通信
  4. wifiAp开发中相关问题
    • 第一,跟WiFiAp相关的有wifiAp的网关Ip,以及ip范围
    • 第二,wifiAp的config:包括初始创建时的defaultvalue:名字(ssid)和密码(preSharedKey),以及后续修改config
    • 第三,wifiAp的enable状态
    • 第四,wifiAp的设备连接列表:一是保证能获取到当前连接设备列表,二是当有设备连接时能够实时的更新
    • 第五,wifiAp的连接限制:包括最大连接数限制,以及黑白名单机制

先就wifiAp的ip进行说明:

既然是要局域网内通信,那就要用到ip地址和端口号了(关于端口号的设定属于开发通信时的问题,是用户自定义的可变的,在我的程序里我规定端口号为80。而ip地址是有规定的,所以只讲关于ip的问题)。ip地址是在Android源码中规定好的,平常所买的路由器的ip地址一般都是192.168.0.1。Android源码中所规定的手机的wifiAp的ip地址为192.168.43.1,这个代码中可以看到


  • 创建wifiAp时的ip:在创建wifiAp时相当于网关ip,/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java中开启wifiAp时规定了ip地址(Android7.0中在该文件中,如果是其他Android系统可以在WifiStateMachine),具体方法为startThering中
  • wifiAp的ip地址的分配区间:在/frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java中有规定
    //usb网络共享的网关是192.168.42.1 
    // USB is 192.168.42.1 and 255.255.255.0
    //wifi便携式热点网关是192.168.43.1
    // Wifi is 192.168.43.1 and 255.255.255.0
    //蓝牙共享(个人局域网)限制5个
    // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
    // with 255.255.255.0
    private String[] mDhcpRange;
    private static final int TETHER_RETRY_UPSTREAM_LIMIT = 5;
    private static final String[] DHCP_DEFAULT_RANGE = {
    "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
    "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
    "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254", "192.168.48.2", "192.168.48.254",
    }


——————编辑于2017-08-03———————

WifiAp的config分析:

默认的config:

  • 代码位置

    在恢复出厂设置后打开WifiAp,初始的wifiAp的名称是一定的,但是wifiAp的密码是随机,这个可以自行测试,实现代码位于一个叫做 WifiApConfigStore.java的文件中,文件路径为/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiApConfigStore.java
  • 代码实现

     /**
      * 构建一个默认的wifiAp,加密类型是WPA2,密码随机
      * 
      * We are changing the Wifi Ap configuration storage from secure settings to a
      * flat file accessible only by the system. A WPA2 based default configuration
      * will keep the device secure after the update.
      */
      private WifiConfiguration getDefaultApConfiguration() {
            WifiConfiguration config = new WifiConfiguration();
            //wifiAp的ssid
            config.SSID = mContext.getResources().getString(
                    R.string.wifi_tether_configure_ssid_default);
              //wifiAp的加密方式
            config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
            //随机生成uuid
            String randomUUID = UUID.randomUUID().toString();
            //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
            config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
            return config;
        }
    }
    

修改wifiAp的config配置

如果想要修改wifiAp的config配置需要注意,在修改config时,config会直接设置下去,但是并不会立即生效,必须要重启wifiAp之后才有效。这个可以先拿自己的手机演示确认。

  • 首先获取到wifiManager对象
  • WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    
  • 然后获取到config对象
  •   WifiConfiguration config = wifiManager.getWifiApConfiguration();
    
  • 有了config之后,就可以对参数进行设置了,比如设置用户名和密码
  • if (config != null) {
               config.SSID = mWifiInfoBean.getApSsid();
               config.preSharedKey = mWifiInfoBean.getPskKey();
       }
    
    当然,你还可以做其他设置,具体的可以参考WifiConfiguration.java源码 到这一步,对于wifiAp的用户名和密码已经设置成功了,此时若手动重启wifiAp后config即可生效。如果你想要立刻生效,那就必须要重启wifiAp了。
  • 重启wifiAp,将所设置的config设置进去,并重启热点,流程是首先判断WiFi热点是否处于开启状态,如果是,则重启wifiAp。如果当前wifiAp不处于开启状态,则只需要把config设置下去即可
  • if (wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) {
       //如果wifiAp处于开启状态,则关闭并重启
      wifiManager.setWifiApEnabled(null, false);
      return wifiManager.setWifiApEnabled(config, true);
    } else {
       //如果wifiAp不处于开启状态,则只需要将config设置下去
        return wifiManager.setWifiApConfiguration(config);
     }
    



——————编辑于2017-08-04———————

开启/关闭WifiAp热点状态

在对wifiAp进行config修改时已经涉及到了对于wifiAp的开和关,在进行wifiAp进行开关的过程中需要传入config,如果传入的为null,则沿用上一次的 config,如果上一次的config不存在,则会去加载默认的config。当开启wifiAp时会先去判断wifi的状态,如果wifi处于开启状态则需要关闭WiFi状态,然后开启wifiAp。

  • 获取WiFimanager对象(参考上文)
  • 判断目前wififAp的开关状态,如果处于开启状态,则不进行任何操作。当然,如果你想自己设置config,那么就照着上文中配置config的步骤来
    /**
      * if wifiap is enabled
    */
    if (wifiManager.isWifiApEnabled()) {
           return true;
     }
    
  • 判断wifi的状态,如果处于开启状态,则关闭wifi状态
     /**
     * Disable Wifi if enabling tethering
    */
     int wifiState = wifiManager.getWifiState();
    if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
       (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
        wifiManager.setWifiEnabled(false);
     }
    
  • 接下来就可以调用wifiAp开启的方法了
    wifiManager.setWifiApEnabled(null, enable);
    

已连接设备列表

读取wifiAp的已连接设备列表

这个很纠结,关于wifiAp的这些东西不存在什么jni接口,只能是通过读文件或者是监听广播来和底层通信。Android源码中提供了一个读取已连接设别列表的方法——读取特定文件“/proc/net/arp” 来获取已连接设备信息。
代码如下:

  File file = new File("/proc/net/arp");
     try {
       reader = new BufferedReader(new FileReader(file));
       String line;
       while ((line = reader.readLine()) != null) {
          String[] tokens = line.split("[ ]+");
          if (tokens.length < 6 || tokens[3].length() < 8) {
               continue;
           }
           //角标为3是mac地址,角标为0是ip地址 ,设备名是根据mac来获取
       }
   } catch (IOException e) {
      e.printStackTrace();
   } finally {
      if (reader != null) {
        try {
          reader.close();
       } catch (IOException e) {
          e.printStackTrace();
       }
    }

该文件包含的数据有sscanf(buf, “%s 0x%x 0x%x %s %s %s\n”, ip, &h_type, &flag, hw_addr, mask, dev )
也就是说tokens 长度为6,可以看到包含已连接设备的ip和addr,但是设备名却没有说明,这个需要自己根据mac地址来获取对应的厂商和设备名。当然,方案提供商也许自己会集成这部分工作,所以具体情况具体考虑

设备列表实时更新

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值