Android捕获Wi-Fi信道利用率,但总是返回过时的缓存值
如何在具备运营商特权且同时拥有前台服务的系统应用中捕获Wi‑Fi信道利用率?
AOSP参考: AOSP Wi‑Fi信道利用率
下面是捕获Wi‑Fi信道利用率的步骤
Step-1 : 注册Wi‑Fi扫描结果更新广播动作,并监听扫描结果更新
Step-2 : 使用API每隔2 秒启动一次Wi‑Fi扫描(注:测试时从开发者选项关闭Wi‑Fi扫描节流)
Step-3 : 一旦扫描完成并收到成功广播,使用API获取最近的Wi‑Fi扫描列表,并将扫描结果传递给计算Wi‑Fi信道利用率
Step-4 : 使用API获取扫描结果列表中可用的信息元素对象,并仅在id为 "11" 时遍历信息元素对象并调用相应方法
根据文档,信道利用率值将来自ID为 11的 BSS_LOAD
BSS Load: 显示当前网络拥塞情况(终端数量和信道利用率)。
Step -5 : 使用下述逻辑从ByteBuffer中提取Wi‑Fi信道利用率值(0到 255)
Observed behaviour :
当我通过执行速度测试、下载大文件来进行网络负载时,每次获得的利用率值都是相同的“9”,没有变化。
(左)三星Wi‑Fi设置 (右)来自Wi‑Fi Man应用的截图
解决方案
你记录的值几乎肯定不是信道利用率,而是站点数量的低字节。其实我也不确定为什么你在问题中编辑了代码,删去了相关部分。你在初始文本中的代码是:
ByteBuffer data = bytes.order(ByteOrder.LITTLE_ENDIAN);
// Extract Utilization (3rd byte)
int utilizationRaw = data.get() & 0xFF;
它甚至指示读取第3 个字节,但你读的是第一个字节。要仅纠正这一行,应该使用这段代码:
int utilizationRaw = data.get(2) & 0xFF;
下面的代码在:
展示了如何正确解析ByteBuffer。与AOSP所使用的公开API等效:
ByteBuffer data = ie.getBytes().order(ByteOrder.LITTLE_ENDIAN);
int stationCount = data.getShort() & 0xFFFF; // bytes 0-1 <- your "9" came from here
int channelUtilization = data.get() & 0xFF; // byte 2 <- the real value
int capacity = data.getShort() & 0xFFFF; // bytes 3-4
float busyPercent = channelUtilization * 100f / 255f;
你也可以看看AOSP自身如何通过链路层统计而非信标来衡量利用率:
该类是wifi服务的内部实现,但具备特权的系统应用可以通过
@SystemApi WifiManager.addOnWifiUsabilityStatsListener().使用:WifiUsabilityStatsEntry.getTotalCcaBusyFreqTimeMillis() / getTotalRadioOnFreqTimeMillis(),需要具备特权权限WIFI_UPDATE_USABILITY_STATS_SCORE。
参见这里:
https://android.googlesource.com/platform/packages/modules/Wifi/+/refs/heads/android16-qpr2-release/framework/java/android/net/wifi/WifiManager.java https://android.googlesource.com/platform/packages/modules/Wifi/+/refs/heads/main/framework/java/android/net/wifi/WifiUsabilityStatsEntry.java

