跳到正文

UserService

UserService 在特权运行时中执行应用自己的代码,并返回应用自定义 AIDL 接口对应的 Binder。

定义 AIDL 接口

将销毁方法的 transaction code 设为 16777114

java
interface IMyPrivilegeService {
    void destroy() = 16777114;
    String getUid() = 1;
}

实现服务

kotlin
class MyPrivilegeService private constructor(
    private val context: Context?,
) : IMyPrivilegeService.Stub() {
    @Keep
    constructor() : this(context = null)

    @Keep
    constructor(context: Context) : this(context = context)

    override fun getUid(): String {
        return "uid=${android.os.Process.myUid()}"
    }

    override fun destroy() {
        if (!PrivilegeUserServiceEnvironment.isEmbedded) {
            exitProcess(0)
        }
    }
}

运行时支持无参构造器或 Context 构造器。独立进程优先初始化 Application, 失败后改用 package Context。嵌入式服务获得 package Context。

判断运行环境

PrivilegeUserServiceEnvironment.isEmbedded 用来判断 UserService 是否直接运行在 Privileged Server 进程中。直接运行时返回 true,运行在独立的 app_process 子进程时返回 false。该值在进程生命周期内保持不变,并会在首次读取后缓存。

执行进程退出或全局清理前,先检查这个属性。上面的独立子进程会在 destroy() 中 调用 exitProcess(0);嵌入式服务与 Privileged Server 共享进程,只清理自身资源。 应用通过 PrivilegeUserServiceSpec.embedded 选择进程模式。

使用独立进程

这是默认模式。服务运行在单独的 app_process 子进程中:

kotlin
lifecycleScope.launch {
    val spec = PrivilegeUserServiceSpec(
        serviceClassName = MyPrivilegeService::class.java.name,
        tag = "main",
        version = 1,
    )

    Privilege.startUserService(spec)

    val connection = Privilege.bindUserService(spec)
    try {
        val service = IMyPrivilegeService.Stub.asInterface(connection.binder)
        service.getUid()
    } finally {
        connection.unbind()
    }

    Privilege.stopUserService(spec)
}

startUserServicebindUserServicestopUserService 都是可取消的挂起函数。 等待服务锁或启动独立进程期间不会阻塞调用线程。如果协程在操作被接收前取消,运行时 会移除待处理状态,并销毁只为该次已取消操作创建的进程或连接。 connection.unbind() 是幂等的挂起函数。调用一旦进入,就会在不可取消上下文中完成, 避免丢弃必要的资源清理;server 仍通过同一套有界异步协议在 Binder 线程之外执行。

每个实例由 serviceClassName + tag 标识。version 表达同一实例能否复用;实现不再 兼容时修改该值,运行时会替换实例。

使用嵌入式服务

设置 embedded = true,让服务直接运行在 Privileged Server 中:

kotlin
val spec = PrivilegeUserServiceSpec(
    serviceClassName = MyPrivilegeService::class.java.name,
    tag = "embedded",
    version = 1,
    embedded = true,
)

嵌入式模式省去额外进程,适合简单且风险较低的服务。它的 destroy() 清理服务 自身资源并保留共享的 Privileged Server。绑定通常更快,因为省去了子进程启动和认领; 服务构造仍会异步执行,并支持取消。