WifiServiceImpl 接口实现:Binder 调用、权限检查、回调注册

好,咱们今天来聊聊 WifiServiceImpl 里最核心的几个机制。说白了,Wi-Fi 服务跑在系统进程里,App 在用户空间,它们怎么通信?靠的就是 Binder。那权限怎么控制?回调怎么注册?这些都是实打实的工程问题。

我个人习惯把 WifiServiceImpl 看作一个「守门人」。它不直接干活,但它负责验证身份、分发任务、通知结果。今天我们就拆开看看,这个守门人是怎么工作的。

Binder 调用的设计思路

WifiServiceImpl 继承自 IWifiManager.Stub,这意味着它天生就是一个 Binder 服务端。App 端拿到的是 IWifiManager 的代理,调用任何方法,最终都会走到 Stub 里的 onTransact,然后分发到对应的实现方法。

举个例子,App 调用 getWifiEnabledState(),流程是这样的:

// App 端
IWifiManager wifiManager = ...;
int state = wifiManager.getWifiEnabledState();

// 底层 Binder 驱动
// -> Binder.onTransact(GET_WIFI_ENABLED_STATE_TRANSACTION, data, reply)
// -> WifiServiceImpl.getWifiEnabledState()

嗯,这里要注意:Binder 调用是同步的。如果服务端处理时间太长,App 端会 ANR。所以耗时操作一定要异步处理。我在项目中就遇到过,某个第三方 App 频繁调用扫描接口,导致系统服务线程阻塞,最后整个 Wi-Fi 设置界面卡死。后来我们加了一层异步队列,才解决这个问题。

核心原则:Binder 调用要快进快出。需要长时间执行的操作,通过 Handler 或 WorkSource 抛到后台线程。

权限检查:三层防护

Wi-Fi 服务涉及用户隐私和系统安全,权限检查必须严格。WifiServiceImpl 的权限检查分三层:

  1. 调用者身份验证——检查调用者的 UID/PID,确认来源合法
  2. 权限声明检查——检查 App 是否声明了对应的权限
  3. 运行时权限检查——Android 6.0+ 需要动态授权

代码里最常见的写法是这样的:

private void enforceChangePermission() {
    mContext.enforceCallingOrSelfPermission(
        android.Manifest.permission.CHANGE_WIFI_STATE,
        "WifiService");
}

private void enforceLocationPermission() {
    mContext.enforceCallingOrSelfPermission(
        android.Manifest.permission.ACCESS_FINE_LOCATION,
        "Need location permission");
}

你想想看,如果某个恶意 App 没有声明 CHANGE_WIFI_STATE 权限,却想调用 setWifiEnabled(),那它会在 enforceChangePermission 这一步直接抛出 SecurityException。系统会把它「请出去」。

我曾经踩过一个坑:在 Android 12 之前,有些系统 App 可以通过反射绕过权限检查。后来 Google 在 WifiServiceImpl 里加了 enforceNetworkStackPermission,专门针对系统级调用做了加固。如果你在做系统开发,记得检查你的 App 是否在 platform.xml 的白名单里。

回调注册机制

回调,说白了就是「你告诉我什么时候 Wi-Fi 开了,我再去干活」。WifiServiceImpl 支持多种回调,最常用的是 WifiManager.WifiLockWifiManager.WifiStateListener

注册回调的流程大致如下:

// App 端注册
WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
WifiManager.WifiStateListener listener = new WifiManager.WifiStateListener() {
    @Override
    public void onWifiStateChanged(int state) {
        // 处理状态变化
    }
};
wifiManager.registerWifiStateListener(listener);

// 服务端实现
public void registerWifiStateListener(IWifiStateListener listener) {
    // 1. 权限检查
    enforceLocationPermission();
    
    // 2. 检查 listener 是否有效
    if (listener == null) return;
    
    // 3. 保存到回调列表
    mWifiStateListeners.add(listener);
    
    // 4. 绑定死亡通知
    listener.asBinder().linkToDeath(new DeathRecipient() {
        @Override
        public void binderDied() {
            mWifiStateListeners.remove(listener);
        }
    }, 0);
}

这里有个细节:死亡通知。如果 App 进程挂了,Binder 代理会收到死亡通知,服务端需要及时清理回调列表。否则会出现「僵尸回调」,浪费系统资源。

我的习惯:在注册回调时,我会同时记录调用者的 UID。这样在分发回调时,可以过滤掉那些已经失去权限的 App。比如某个 App 被用户撤销了位置权限,那它就不应该再收到 Wi-Fi 状态变化通知。

整体架构图

下面这张图展示了 WifiServiceImpl 的核心交互流程:

WifiServiceImpl 核心架构 App 进程 IWifiManager 代理 Binder 驱动 onTransact 分发 WifiServiceImpl Stub 实现 调用 分发 权限检查模块 enforceChangePermission enforceLocationPermission 回调管理模块 注册/注销回调 死亡通知处理 业务逻辑模块 Wi-Fi 开关 扫描/连接 回调通知 onWifiStateChanged 通知 App 接收回调 处理状态变化 App 进程 Binder 驱动 服务实现 权限检查 回调管理

实际开发中的注意事项

讲完了理论,咱们聊聊实战中容易出问题的地方。

场景 问题 解决方案
App 频繁注册/注销回调 回调列表膨胀,内存泄漏 限制注册频率,使用 WeakReference
权限被动态撤销 回调仍在发送,App 收到无效通知 分发前检查 UID 权限状态
Binder 线程池耗尽 所有 Binder 调用阻塞 异步处理,控制并发数
死亡通知未处理 僵尸回调残留 必须实现 linkToDeath/unlinkToDeath
一句话总结:WifiServiceImpl 的接口实现,核心就是三件事——Binder 通信要快、权限检查要严、回调管理要干净。这三件事做好了,Wi-Fi 服务就稳了一半。

嗯,今天的内容就到这里。代码里还有很多细节,比如 WorkSource 的传递、Binder.clearCallingIdentity 的使用,这些我们后面再细聊。你先把 Binder 调用和权限检查的流程理清楚,后面学起来会轻松很多。


公众号:蓝海资料掘金营,微信 deep3321