拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Android WiFi框架深度解析:从WifiManager到wpa_supplicant全链路机制

Android WiFi框架深度解析:从WifiManager到wpa_supplicant全链路机制

1. 这不是“背概念”,而是搞懂Android里WiFi怎么真正跑起来的

如果你翻过Android源码里的frameworks/base/wifi/目录,或者在Android Studio里点进WifiManager类看到满屏的@SystemApi、@hide、@RequiresPermission注解,第一反应可能是:这哪是API文档,分明是加密电报。但其实,Android的WiFi框架从来就不是靠死记硬背能掌握的——它是一套有明确分层、有清晰职责边界、有严格权限约束、且和Linux内核深度耦合的运行时系统。我带过三届Android底层开发实习生,发现90%的人卡在同一个地方:以为调用wifiManager.enableNetwork()就等于“连上了WiFi”,结果真机一跑,日志里全是SupplicantState.INACTIVE、WifiStateMachine: CMD_START_SCAN failed,连个扫描都扫不出来。问题不在代码写错,而在根本没理解WiFi框架里“谁在管什么”、“状态怎么流转”、“错误从哪来又该往哪查”。这篇内容不讲API列表,不列方法签名,只拆解真实项目中你每天都在打交道却始终没看清全貌的那套机制:从Java层的WifiManager到JNI桥接,从wpa_supplicant守护进程到nl80211内核接口,再到HAL层如何把驱动指令翻译成射频动作。它解决的是“为什么我的WiFi开关点不动”、“为什么热点创建后手机搜不到”、“为什么企业级WPA3连接总失败”这类问题背后的根因。适合正在做WiFi相关功能(比如IoT设备配网、车载WiFi管理、教育终端网络策略控制)的Android开发者,也适合想从应用层深入到底层通信链路的中级工程师。你不需要会写驱动,但必须知道WifiService启动时加载了几个Binder服务、WifiStateMachine的状态图为什么有17个节点、ScanResult里的level值怎么换算成dBm、以及为什么getConfiguredNetworks()返回空列表——哪怕你明明刚用addNetwork()加过一个配置。

2. 整体架构设计:四层模型与数据流向的真实逻辑

2.1 四层不是教科书画的示意图,而是真实进程隔离与权限边界的体现

Android WiFi框架的分层,常被简化为“应用层→Framework层→HAL层→Driver层”,但这掩盖了关键事实:每一层都运行在独立的Linux进程或用户空间上下文中,且通过明确的IPC机制通信,而非函数调用。这种设计不是为了炫技,而是源于Android对安全与稳定性的硬性要求——WiFi涉及射频操作、密码存储、网络访问等高危行为,必须将不可信的应用代码与核心网络栈彻底隔离。

  • 应用层(App Process):运行在Zygote fork出的独立进程中,UID为应用专属。调用WifiManager时,实际是通过Binder向system_server进程发起跨进程请求。这里的关键限制是:所有WiFi操作都受Manifest权限约束,且部分API(如removeNetwork())要求CHANGE_WIFI_STATE+ACCESS_WIFI_STATE双权限,而setWifiEnabled()还需android.permission.WRITE_SETTINGS(Android 10+需用户手动授予)。我见过太多团队在Android 12上因漏配WRITE_SETTINGS导致WiFi开关失效,日志里只显示SecurityException,却找不到权限声明位置。

  • Framework层(system_server进程):这是整个WiFi框架的“大脑中枢”,包含WifiService、WifiStateMachine、WifiNative等核心组件。WifiService作为Binder服务端,接收来自各App的请求并分发;WifiStateMachine则是一个庞大而精密的状态机,管理从“关闭”到“已连接”的全部17个状态(InitialState→SupplicantStartingState→DriverStartedState→ScanModeState→ConnectModeState→ConnectedState…),每个状态切换都触发特定动作(如进入ConnectModeState会调用supplicant.connect())。状态机不是静态图,而是动态响应事件(Event)的实体——比如收到CMD_START_SCAN事件,当前状态决定是否执行扫描、是否更新扫描结果缓存、是否触发SCAN_RESULTS_AVAILABLE广播。很多问题源于状态机卡在某个中间态(如SupplicantStoppingState),而开发者只盯着API调用,忽略了状态流转的上下文。

  • HAL层(hal_wifi@1.0-service进程):Android 8.0引入的HIDL HAL将WiFi硬件抽象标准化。WifiHal通过IWifi接口与Framework通信,再通过libwifi-hal库调用厂商提供的libwifi-hal-qca.so(高通)或libwifi-hal-brcm.so(博通)等专有实现。HAL层的核心价值在于解耦——Framework无需关心芯片差异,只需发送startScan()指令;而厂商可自由实现扫描逻辑(如是否支持PNO扫描、是否启用DFS信道),只要遵循HIDL接口契约即可。实测某国产SoC在HAL层对getFirmwareVersion()返回空字符串,导致Framework误判驱动未加载,最终WifiManager.isWifiEnabled()永远返回false——这种问题只能通过adb shell dumpsys wifi查看HAL状态定位。

  • Driver/Native层(wpa_supplicant + kernel nl80211):wpa_supplicant是Linux标准WiFi守护进程,负责EAP认证、密钥协商、关联管理等协议栈逻辑;它通过netlink socket与内核nl80211子系统通信,后者直接控制无线网卡驱动(如ath9k、mt76)。Framework层的所有操作,最终都转化为wpa_supplicant的控制命令(如SELECT_NETWORK 0)或nl80211的ioctl调用(如NL80211_CMD_TRIGGER_SCAN)。这也是为什么adb shell wpa_cli status能直接看到当前连接状态,而cat /proc/net/wireless可读取实时信号强度——它们绕过了Framework,直击底层真相。

提示:不要试图在应用层“绕过Framework”直接调用wpa_cli,这违反Android沙箱模型。曾有团队为解决扫描延迟问题,在App里Runtime.getRuntime().exec("wpa_cli scan"),结果在Android 11上因SELinux策略被拒绝,且无法获取扫描结果。

2.2 数据流向不是单向管道,而是带反馈闭环的协同链路

以“连接一个WPA2-PSK网络”为例,完整数据流如下:

  1. App发起请求:wifiManager.enableNetwork(configId)→WifiManager通过Binder向WifiService发送ENABLE_NETWORK指令;
  2. Framework处理:WifiService将请求转发给WifiStateMachine,状态机从DisconnectedState切换至ConnectModeState,并调用WifiNative.enableNetwork();
  3. JNI桥接:WifiNative通过JNI调用com_android_server_wifi_WifiNative.cpp中的enableNetworkNative(),生成对应wpa_supplicant命令;
  4. HAL执行:WifiHal接收命令,调用厂商HAL实现,最终通过ioctl(SIOCSIWENCODE)等系统调用配置驱动密钥;
  5. Driver响应:驱动完成关联后,通过nl80211事件通知wpa_supplicant,后者更新内部状态并向Framework发送CTRL-EVENT-CONNECTED;
  6. Framework同步:WifiNative监听到事件,回调WifiMonitor,触发WifiStateMachine进入ConnectedState,并广播NETWORK_STATE_CHANGED_ACTION;
  7. App感知结果:注册了该广播的Activity收到EXTRA_WIFI_STATE为WIFI_STATE_ENABLED,且getDhcpInfo()可获取IP地址。

这个流程中,任何一环中断都会导致连接失败,但错误表现截然不同:

  • 若HAL层调用失败(如wifiStartScan()返回-1),WifiStateMachine会停留在ScanModeState,日志显示Failed to start scan;
  • 若wpa_supplicant认证超时(如PSK错误),会触发CTRL-EVENT-DISCONNECTED事件,状态机退回DisconnectedState,广播SUPPLICANT_CONNECTION_FAILED;
  • 若内核驱动未响应(如nl80211事件丢失),wpa_supplicant日志出现Timeout waiting for NL80211 event,Framework层则无任何回调。

注意:adb logcat -s WifiStateMachine:V WifiMonitor:V是定位问题的黄金组合。我习惯先过滤这两标签,比盲目刷logcat *:S高效十倍。

2.3 权限与SELinux:看不见的墙如何决定WiFi功能生死

Android的WiFi功能受三重权限控制,缺一不可:

控制层级权限名称作用范围Android版本变化
Manifest权限ACCESS_WIFI_STATE读取WiFi状态、扫描结果始终需要
CHANGE_WIFI_STATE开关WiFi、连接网络始终需要
WRITE_SETTINGS修改WiFi开关状态(Android 10+)Android 10起强制要求
Runtime权限ACCESS_FINE_LOCATION获取扫描结果(因WiFi可定位)Android 6.0+需动态申请
SELinux域wifi_halHAL进程访问/dev/wlan等设备节点系统级策略,App无法干预

最易踩坑的是WRITE_SETTINGS。在Android 10+,即使Manifest声明了该权限,setWifiEnabled(true)仍会抛SecurityException,因为系统要求用户在设置中手动开启“修改系统设置”开关。解决方案不是放弃,而是引导用户跳转:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.System.canWrite(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); intent.setData(Uri.parse("package:" + context.getPackageName())); startActivity(intent); } }

而SELinux问题更隐蔽。某次调试车载系统WiFi热点功能,WifiManager.createWifiApConfiguration()成功,但setWifiApEnabled()始终返回false。adb shell dmesg | grep avc显示:

avc: denied { write } for name="wlan" dev="tmpfs" ino=12345 scontext=u:r:wifi_hal:s0 tcontext=u:object_r:device:s0 tclass=chr_file

这意味着wifi_hal进程无权写入/dev/wlan设备节点。需修改device/qcom/common/sepolicy/vendor/wifi.te,添加:

allow wifi_hal device:chr_file { read write };

这种问题只能通过dmesg和sepolicy分析解决,绝非代码层面能修复。

3. 核心模块解析:从WifiManager到wpa_supplicant的逐层深挖

3.1 WifiManager:API表象下的真实能力边界

WifiManager是开发者接触最多的类,但它的方法名极具误导性。例如pingSupplicant()看似测试wpa_supplicant连通性,实则只是向WifiNative发送一个PING命令并等待响应,不验证wpa_supplicant是否真正工作。我曾用此方法判断WiFi服务是否可用,结果pingSupplicant()返回true,但startScan()却失败——因为wpa_supplicant进程虽存活,但配置文件损坏导致无法初始化。

关键API的真实行为解析:

  • getConfiguredNetworks():返回List<WifiConfiguration>,但仅包含当前用户Profile下的网络配置。多用户场景下(如企业MDM),其他用户配置不可见。且Android 10+默认隐藏密码字段(WifiConfiguration.preSharedKey为null),需通过WifiManager.getConfiguredNetworks()配合WifiManager.saveConfiguration()才能获取完整信息。

  • addNetwork(WifiConfiguration):返回int networkId,但该ID仅在本次Framework会话中有效。若wpa_supplicant重启(如adb shell killall wpa_supplicant),所有网络配置丢失,networkId失效。生产环境务必在WifiManager.enableNetwork()前确认配置已持久化。

  • getScanResults():返回List<ScanResult>,但结果缓存有效期仅12秒(Android 12)。频繁调用startScan()会导致ScanResult为空,因Framework层有防抖机制。正确做法是注册SCAN_RESULTS_AVAILABLE_ACTION广播,在广播接收器中调用getScanResults()。

  • getDhcpInfo():返回DhcpInfo对象,但仅当设备处于ConnectedState且DHCP成功时才有意义。若网络使用静态IP,ipAddress字段为0,需改用LinkProperties(通过ConnectivityManager.getLinkProperties()获取)。

实操心得:不要依赖WifiManager的返回值做业务逻辑判断。例如connect()返回true不代表连接成功,只是请求已提交;真正的连接结果需监听NETWORK_STATE_CHANGED_ACTION广播,并检查WifiManager.getConnectionInfo().getNetworkId()是否大于0。

3.2 WifiStateMachine:状态机才是WiFi功能的真正控制器

WifiStateMachine是Framework层最复杂的组件,其状态图包含17个状态节点和数十个事件转换。理解它,等于掌握了WiFi生命周期的全部脉络。

核心状态流转逻辑(以连接为例):

InitialState → SupplicantStoppingState (停止wpa_supplicant) → DriverStoppingState (卸载驱动) → DriverStartedState (加载驱动) → SupplicantStartingState (启动wpa_supplicant) → ScanModeState (准备扫描) → ConnectModeState (尝试连接) → ConnectedState (连接成功)

每个状态都有明确职责:

  • SupplicantStartingState:调用WifiNative.startSupplicant()启动wpa_supplicant进程,并等待其通过ctrl_iface建立通信。若超时(默认30秒),状态机转入SupplicantStoppingState并报错。
  • ScanModeState:维护扫描结果缓存,处理CMD_START_SCAN事件。关键细节:扫描并非立即执行,而是加入队列,Framework按优先级调度(如热点扫描优先级高于普通扫描)。
  • ConnectModeState:执行WifiNative.enableNetwork(),触发wpa_supplicant的SELECT_NETWORK命令。若认证失败,会触发CMD_DISCONNECT事件,状态机退回DisconnectedState。

状态机调试技巧:

  • adb shell dumpsys wifi输出中,Current State:行明确显示当前状态;
  • adb logcat -b events | grep wifi可捕获状态切换事件(如wifistatemachine: ConnectedState);
  • 在WifiStateMachine.java中添加Log.d("WIFI_SM", "Enter " + getCurrentState().getName()),编译定制ROM验证流转路径。

踩过的坑:某次OTA升级后WiFi无法连接,dumpsys wifi显示卡在SupplicantStartingState。排查发现wpa_supplicant.conf中ctrl_interface路径被改为/data/misc/wifi/sockets,但Framework仍尝试连接/data/misc/wifi/sockets/wpa_ctrl_XXXXX-1。手动修正配置文件后恢复正常——这说明状态机依赖外部配置,而非完全自洽。

3.3 wpa_supplicant:协议栈的黑盒与可控入口

wpa_supplicant是WiFi连接的协议栈核心,其配置文件/data/misc/wifi/wpa_supplicant.conf和日志是诊断连接问题的终极依据。

典型配置文件结构:

ctrl_interface=DIR=/data/misc/wifi/sockets GROUP=wifi update_config=1 ap_scan=1 network={ ssid="MyNetwork" psk="abc123456" key_mgmt=WPA-PSK priority=1 }

关键参数解析:

  • ap_scan:控制扫描模式。ap_scan=1(默认)表示由wpa_supplicant管理扫描;ap_scan=2则由驱动直接关联,适用于某些嵌入式场景。设错会导致扫描失败。
  • key_mgmt:指定密钥管理协议。WPA-PSK用于家庭WiFi,WPA-EAP用于企业网络,NONE用于开放网络。Android Framework在WifiConfiguration中设置allowedKeyManagement.set(KeyMgmt.WPA_PSK),最终映射为此字段。
  • priority:网络优先级,数值越大越优先连接。Framework层WifiConfiguration.priority与此一一对应。

日志分析实战:

  • CTRL-EVENT-CONNECTED:成功关联,后续应有CTRL-EVENT-SUBNET-STATUS-UPDATE;
  • CTRL-EVENT-DISCONNECTED reason=3:reason=3表示DEAUTH_LEAVING,即主动断开;
  • CTRL-EVENT-SSID-TEMP-DISABLED:因多次认证失败,临时禁用该SSID(默认5分钟);
  • WPS-FAIL msg=7:WPS推送按钮失败,msg=7表示WPS_ERR_NO_AP_FOUND。

实操技巧:通过adb shell wpa_cli交互式调试。连接后执行:

wpa_cli list_networks # 查看网络列表 wpa_cli select_network 0 # 选择网络0 wpa_cli get_status # 查看当前状态 wpa_cli log_level 2 # 提升日志级别

这比看Framework日志更直接,尤其适合验证驱动层问题。

3.4 HAL与Driver:硬件差异如何影响上层行为

不同芯片平台的HAL实现差异巨大,直接影响Framework层API行为:

厂商典型HAL实现关键差异点影响的API
Qualcommlibwifi-hal-qca.so支持QCA_WLAN_VENDOR_ATTR_GET_WIFI_INFO扩展属性WifiManager.getWifiApConfiguration()返回完整热点信息
Broadcomlibwifi-hal-brcm.sostartScan()支持scan_type=2(PNO扫描)WifiManager.startScan()可传ScanSettings指定扫描类型
MediaTeklibwifi-hal-mtk.sogetFirmwareVersion()返回固件版本号WifiManager.getWifiApConfiguration()需固件支持才返回apBand字段

案例:热点创建失败的根源
某MTK平台设备调用WifiManager.setWifiApEnabled(config, true)后,getWifiApState()始终返回WIFI_AP_STATE_FAILED。dumpsys wifi显示HAL: Failed to start softap。进一步adb shell cat /proc/kmsg | grep mtk_wlan发现:

[ 1234.567890] mtk_wlan: ERROR: AP mode not supported in current firmware

原来该固件版本未启用AP模式。解决方案是升级固件,而非修改Framework代码——这印证了HAL层对硬件能力的强依赖。

注意:HAL层调试需厂商支持。通用方法是adb shell dumpsys wifi查看HAL state,或adb shell ls -l /vendor/lib/hw/确认HAL库存在性。

4. 实操过程:从零构建可调试的WiFi功能验证环境

4.1 环境准备:避开Android Studio的默认陷阱

Android Studio默认配置会掩盖底层问题,需主动调整:

  1. 禁用Instant Run(Android 10+为Apply Changes):
    File → Settings → Build → Instant Run→ 取消勾选。原因:热替换可能破坏WifiManager的Binder连接,导致getWifiState()返回WIFI_STATE_UNKNOWN。

  2. 启用ADB over Network(避免USB干扰):

    adb tcpip 5555 adb connect 192.168.1.100:5555 # 设备IP

    USB连接时,部分设备会因供电不足导致WiFi模块异常,网络ADB更稳定。

  3. 配置Logcat过滤器:
    在Android Studio Logcat窗口右上角,点击Edit Filter Configuration,添加:

    • Log Tag:WifiStateMachine|WifiMonitor|WifiNative|wpa_supplicant
    • Log Level:Verbose
    • PID:留空(监控所有进程) 这样可聚焦WiFi核心日志,避免被ViewRootImpl等无关日志淹没。

4.2 扫描功能验证:从触发到结果的全链路检查

完整扫描流程代码与验证点:

// 1. 动态申请位置权限(Android 6.0+) if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1); } // 2. 注册扫描结果广播 IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); registerReceiver(scanReceiver, filter); // 3. 触发扫描 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); if (wifiManager.startScan()) { Log.d("WIFI", "Scan triggered successfully"); } else { Log.e("WIFI", "Scan failed - check wifi enabled & location permission"); } // 广播接收器 private BroadcastReceiver scanReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { List<ScanResult> results = wifiManager.getScanResults(); Log.d("WIFI", "Scan count: " + results.size()); for (ScanResult result : results) { // signalLevel: -50 ~ -100 dBm, 转换公式:level = 100 + (result.level / 2) int level = 100 + result.level / 2; // Android 12+推荐算法 Log.d("WIFI", "SSID: " + result.SSID + ", Level: " + level + "dBm"); } } } };

关键验证步骤:

  • adb logcat -s WifiStateMachine:V:确认ScanModeState是否进入,CMD_START_SCAN是否被处理;
  • adb shell wpa_cli list_networks:检查wpa_supplicant是否收到扫描指令;
  • adb shell cat /proc/net/wireless:读取实时信号强度(link字段),验证驱动层是否上报数据;
  • adb shell dumpsys wifi | grep "Scan result":确认Framework层缓存是否更新。

实测发现:某些设备getScanResults()返回空列表,但/proc/net/wireless显示信号正常。原因是Framework层扫描结果缓存未刷新,需等待SCAN_RESULTS_AVAILABLE_ACTION广播,而非立即调用getScanResults()。

4.3 连接功能验证:处理WPA2/WPA3/EAP的差异化逻辑

不同安全协议的连接代码差异显著:

WPA2-PSK(家庭网络):

WifiConfiguration config = new WifiConfiguration(); config.SSID = "\"" + ssid + "\""; config.preSharedKey = "\"" + password + "\""; config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); config.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // WPA2 config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); int netId = wifiManager.addNetwork(config); wifiManager.enableNetwork(netId, true);

WPA3-SAE(新一代安全):

// Android 12+支持 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); config.allowedProtocols.set(WifiConfiguration.Protocol.WPA3); // WPA3标识 config.preSharedKey = "\"" + password + "\""; // SAE密码格式同PSK

EAP-TLS(企业网络):

config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); config.enterpriseConfig = new WifiEnterpriseConfig(); config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS); config.enterpriseConfig.setClientCert("user_cert"); // keystore别名 config.enterpriseConfig.setCaCert("ca_cert"); config.enterpriseConfig.setIdentity("username"); config.enterpriseConfig.setAnonymousIdentity("@realm.com");

连接状态监听:

// 监听网络状态变化 ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkRequest request = new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); connectivityManager.registerNetworkCallback(request, networkCallback); private final ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(@NonNull Network network) { // 网络可用,可获取IP LinkProperties props = connectivityManager.getLinkProperties(network); InetAddress ip = props.getInterfaceAddresses().get(0).getAddress(); Log.d("WIFI", "IP: " + ip.getHostAddress()); } };

注意:EAP连接需提前将证书导入系统keystore,否则setClientCert()失败。可通过adb shell am start -n com.android.settings/.Settings\$SecuritySettingsActivity手动安装。

4.4 热点功能验证:AP模式的硬件兼容性雷区

热点创建代码看似简单,但成功率极低:

// 创建热点配置 WifiConfiguration apConfig = new WifiConfiguration(); apConfig.SSID = "\"" + "MyHotspot" + "\""; apConfig.preSharedKey = "\"" + "12345678" + "\""; apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); apConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN); apConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); apConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); apConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); // 启用热点 WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { wifiManager.setWifiApConfiguration(apConfig); wifiManager.setWifiApEnabled(apConfig, true); } else { // Android 7.1及以下使用反射 Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class); method.invoke(wifiManager, apConfig, true); }

失败排查清单:

  • adb shell dumpsys wifi | grep "Soft AP":确认Soft AP state是否为ENABLED;
  • adb shell ip addr show wlan0:检查wlan0接口是否分配IP(如192.168.43.1);
  • adb shell cat /sys/class/net/wlan0/operstate:返回up表示接口启用;
  • adb shell ps | grep hostapd:确认hostapd进程是否运行;
  • adb shell logcat -s hostapd:V:查看热点守护进程日志。

实操心得:MTK平台需在BoardConfig.mk中启用BOARD_WLAN_DEVICE := mt66xx,否则hostapd无法加载驱动。这属于编译期配置,运行时无法修复。

5. 常见问题与排查技巧实录:真实项目中的21个高频故障

5.1 扫描类问题速查表

现象可能原因排查命令解决方案
startScan()返回falseWiFi未启用或位置权限未授adb shell dumpsys wifi | grep "Wi-Fi"
adb shell pm grant com.yourapp android.permission.ACCESS_FINE_LOCATION
确保wifiManager.setWifiEnabled(true)且权限已授
getScanResults()为空未注册广播或缓存未刷新adb logcat -s WifiStateMachine:V | grep "Scan result"等待SCAN_RESULTS_AVAILABLE_ACTION广播后再调用
扫描结果无2.4G/5G网络驱动不支持双频或固件限制adb shell cat /proc/cpuinfo | grep "Hardware"
adb shell dmesg | grep "wlan"
检查芯片型号,升级固件或更换硬件
扫描速度慢(>30秒)wpa_supplicant扫描超时或信道过多adb shell wpa_cli get_capability freq编辑wpa_supplicant.conf,添加scan_freq=2412,2437,2462限定信道

5.2 连接类问题速查表

现象可能原因排查命令解决方案
enableNetwork()后无反应网络配置ID无效或wpa_supplicant未启动adb shell wpa_cli list_networks
adb shell ps | grep wpa_supplicant
重新addNetwork(),确认wpa_supplicant进程存在
连接后立即断开DHCP失败或DNS配置错误adb shell getprop dhcp.wlan0.ipaddress
adb shell getprop net.dns1
检查路由器DHCP池,或手动设置静态IP
WPA3连接失败Android版本过低或固件不支持adb shell getprop ro.build.version.release
adb shell cat /vendor/etc/wifi/wpa_supplicant.conf | grep "wpa3"
升级Android 12+,更新WiFi固件
EAP-TLS证书错误证书未导入或别名错误adb shell ls /data/misc/keystore/user_0/
adb shell dumpsys wifi | grep "EAP"
使用KeyStoreAPI导入证书,确保setClientCert()别名匹配

5.3 热点类问题速查表

现象可能原因排查命令解决方案
setWifiApEnabled()返回falseHAL不支持AP模式或SELinux阻止adb shell dmesg | grep avc
adb shell dumpsys wifi | grep "HAL"
修改sepolicy,或联系芯片厂商提供AP固件
手机能搜到热点但无法连接密码长度不足或加密协议不匹配adb shell wpa_cli get_capability pairwise设置preSharedKey为8位以上,allowedPairwiseCiphers.set(CCMP)
热点连接后无网络hostapd未配置NAT或DHCP服务adb shell ps | grep dnsmasq
adb shell iptables -t nat -L
在hostapd.conf中启用dhcp_option=3,192.168.43.1,配置iptables规则

5.4 深度避坑技巧:那些文档不会写的真相

  • “WiFi开关点不动”的终极解法:
    不是setWifiEnabled(false)再true,而是adb shell svc wifi disable && adb shell svc wifi enable。svc命令直接操作WifiService,绕过Framework状态机,强制重置。

  • 扫描结果信号强度换算:
    ScanResult.level是RSSI值(-100 ~ -1 dBm),但不同Android版本算法不同:

    • Android 11及以下:level = 100 + (rssi / 2)
    • Android 12+:level = 100 + rssi(更精确)
      统一方案:int level = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? 100 + result.level : 100 + result.level / 2;
  • WifiManager单例失效的修复:
    在Application.onCreate()中缓存WifiManager实例,而非每次getSystemService()。因WifiManager内部持有IBinder引用,频繁获取可能导致Binder泄漏。

  • 企业网络证书吊销检查:
    Android默认不检查CRL,需在WifiEnterpriseConfig中启用:

    config.enterpriseConfig.setDomainSuffixMatch("corp.com"); config.enterpriseConfig.setAnonymousIdentity("@corp.com"); // 添加CRL检查需修改系统属性(需root):`adb shell setprop wifi.crl.check.enabled 1`

最后分享一个小技巧:当所有方法失效时,执行adb shell rm -rf /data/misc/wifi/* && adb reboot。这会重置wpa_supplicant.conf和所有网络配置,相当于“恢复出厂WiFi设置”。我在某次客户现场救急时,30秒解决持续一周的连接问题——它不优雅,但绝对有效。

返回列表