Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async RPC call of Android Binder #1201

Merged
merged 14 commits into from
Nov 16, 2024
Merged

Async RPC call of Android Binder #1201

merged 14 commits into from
Nov 16, 2024

Conversation

StageGuard
Copy link
Member

此 PR 旨在消除 service proxy 的 runBlocking,提高 service 吞吐量

目前问题

例如,IRemoteTorrentDownloader.aidl 中的 startRemoteDownload 接口为

IRemoteTorrentSession startRemoteDownload(in PEncodedTorrentInfo data, in String overrideSaveDir);

这个接口对应了 TorrentDownloaderstartDownload 函数,是一个 suspend 函数

suspend fun startDownload(
    data: EncodedTorrentInfo,
    parentCoroutineContext: CoroutineContext = EmptyCoroutineContext,
    overrideSaveDir: SystemPath? = null,
): TorrentSession

目前在 client 的调用实现为

override suspend fun startDownload(
    data: EncodedTorrentInfo,
    parentCoroutineContext: CoroutineContext,
    overrideSaveDir: SystemPath?
): TorrentSession {
    return remote.startRemoteDownload(data.toParceled(), overrideSaveDir?.absolutePath)
}

在 service 的实现为

override fun startRemoteDownload(data: PEncodedTorrentInfo?, overrideSaveDir: String?): IRemoteTorrentSession? {
    val session = runBlocking { 
        actualServiceTorrentDownloader.startDownload(
            withContext(Dispatchers.IO_) { data.toEncodedTorrentInfo() },
            overrideSaveDir = overrideSaveDir?.run { Path(this).inSystem },
        ) 
    }
    return TorrentSessionProxy(session, this, scope.coroutineContext)
}

client 调用 startRemoteDownload 时需要等待 service 实现中的 runBlocking 执行完成才会返回结果,如果 runBlocking 执行了很长时间,那 client 调用端会一直等待结果而阻塞,service 实现也会因为 runBlocking 而不能使用当前的 binder 线程继续处理其他 client 调用

新变化

此 PR 将 startRemoteDownload AIDL 接口改为如下回调形式

IDisposableHandle startRemoteDownload(in PEncodedTorrentInfo data, in String overrideSaveDir, in RemoteContinuation cont);
interface RemoteContinuation {
    void resume(in IRemoteTorrentSession value);
    void resumeWithException(in RemoteContinuationException exception);
}

其中,IDisposableHandle 用于处理 service 取消协程的动作,client 取消协程后通过 IDisposableHandle 通知 service 同样取消对应处理协程,RemoteContinuation 用于回调结果

如此而来,client 通过 suspendCancellableCoroutine 就可以比较轻易地实现回调 API 的挂起

override suspend fun startDownload(
    data: EncodedTorrentInfo,
    parentCoroutineContext: CoroutineContext,
    overrideSaveDir: SystemPath?
): TorrentSession = suspendCancellableCoroutine { cont ->
    val disposable = remote.startRemoteDownload(
        data.toParceled(), 
        overrideSaveDir?.absolutePath,
        object : ContTorrentDownloaderStartDownload.Stub() {
            override fun resume(value: IRemoteTorrentSession?) {
                cont.resume(value)
            }   

            override fun resumeWithException(exception: RemoteContinuationException?) {
                cont.resumeWithException(exception)
            }

        }
    )
    
    cont.invokeOnCancellation { disposable.dispose() }

service 也可以去除 runBlocking,并且快速返回结果

override fun startRemoteDownload(
    data: PEncodedTorrentInfo?,
    overrideSaveDir: String?,
    cont: RemoteContinuation?
): IDisposableHandle? {
    if (data == null) return null
    if (cont == null) return null

    val job = scope.launch(
        CoroutineExceptionHandler { _, throwable ->
            cont.resumeWithException(throwable.toRemoteContinuationException())
        } + Dispatchers.IO_,
    ) {
        val result = delegate.startDownload(
            withContext(Dispatchers.IO_) { data.toEncodedTorrentInfo() },
            overrideSaveDir = overrideSaveDir?.run { Path(this).inSystem },
        )
        cont.resume(TorrentSessionProxy(result, this@TorrentDownloaderProxy, scope.coroutineContext))
    }

    return DisposableHandleProxy { job.cancel() }
}

@StageGuard
Copy link
Member Author

经测试改了之后大幅度加速了 [resolveDownloadingFile]: Still waiting to get file 的等待时间

@Him188 Him188 self-requested a review November 15, 2024 10:21
@Him188 Him188 added the s: torrent 子系统: BT label Nov 15, 2024
@Him188 Him188 added this to the 4.1.0 milestone Nov 15, 2024
Copy link
Member

@Him188 Him188 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RemoteCall 改名叫 RemoteObject 是不是更好一点

remoteObject.callSuspend { foo() } 听起来更合理.

class RemoteTorrentSession(private val aidl: RemoteObject<IRemoteTorrentSession>)

@StageGuard StageGuard enabled auto-merge (squash) November 16, 2024 14:58
@StageGuard StageGuard merged commit 700bb3b into main Nov 16, 2024
6 checks passed
@StageGuard StageGuard deleted the sg/async-rpc branch November 16, 2024 16:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
s: torrent 子系统: BT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants