跳到正文

Binder

Priv Kit 可以连接 Binder 服务和系统服务。通过它执行 Binder transaction 时, 原有的调用格式不会改变。应用提供对应的系统接口,并负责实现自己的业务逻辑。

访问系统服务

通过已连接的 Privileged Server,按服务名获取系统服务:

kotlin
val activityBinder = PrivilegeBinderWrapper.fromSystemService("activity")
val activityManager = IActivityManager.Stub.asInterface(activityBinder)

Log.d(
    "activity",
    activityManager.getTasks(1).toString(),
)

部分服务只能在 shell 或 Root 服务端进程中获取:

kotlin
val binder = PrivilegeBinderWrapper.fromSystemService(
    serviceName = "miui.mqsas.IMQSNative",
    source = PrivilegeSystemServiceSource.SERVER_PROCESS,
)

应用需要提供对应的系统接口,并定义每个 transaction 的调用格式和含义。

将资源绑定到服务端生命周期

部分 Binder API 接收 owner 或 death token,以便远端进程在 owner 退出时释放资源。 如果资源应当跟随当前 Privileged Server 进程,可以使用专用的服务端生命周期 Binder:

kotlin
val serverInfo = Privilege.getServerInfo()
val serverLifecycle = serverInfo.lifecycleBinder
serverLifecycle.linkToDeath(
    { Log.d("server", "Privileged Server 已退出") },
    0,
)

这个 token 不提供特权操作或自定义 transaction。同一个服务端进程内,它的 Binder identity 保持不变;服务端被替换后,新服务端会返回不同的 token。它与 PrivilegeServerInfo 的其他字段属于同一个服务端快照。每次 Privilege.serverState 变化后更新这个值。服务端不存在或已经死亡时, Privilege.getServerInfo() 会抛出 PrivilegeServerUnavailableException

处理调用失败

Priv Kit 自己的控制调用在服务端未连接或已经死亡时,都会抛出 PrivilegeServerUnavailableException。通过 PrivilegeBinderWrapper 转发的 调用会保留 Binder 原本的异常。调用失败时,应用可能无法确定是目标 Binder 还是 Privileged Server 已经死亡,需要根据自身情况决定是否改用其他方式。

如果服务端或 UserService 的 Binder 调用失败后可以安全地改用其他方式,可以使用 PrivilegeBinderCall.orElse(...)

  • PrivilegeBinderCallFailure.ServerUnavailable 表示 Privileged Server 不可用。
  • PrivilegeBinderCallFailure.BinderDied 表示直接调用的 Binder 已经死亡。
  • 其他异常保持不变。

orElse(...) 适合原调用结果未知时仍可安全恢复的场景。服务进程可能已经完成修改后 才死亡。