From d64e3b4235c5c55239553bfbd4dfde36bdd34d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 12 Mar 2026 22:27:48 +0800 Subject: [PATCH] Fix ParceledListSlice ClassLoader and RootClient service binding - Use proper ClassLoader in ParceledListSlice.createFromParcel instead of null - Add early root permission check in RootClient.bindService - Migrate RootService.bind to bindOrTask for proper error propagation --- .../nekohasekai/sfa/bg/ParceledListSlice.java | 2 +- .../java/io/nekohasekai/sfa/bg/RootClient.kt | 32 ++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/ParceledListSlice.java b/app/src/main/java/io/nekohasekai/sfa/bg/ParceledListSlice.java index 9840067..60c824f 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/ParceledListSlice.java +++ b/app/src/main/java/io/nekohasekai/sfa/bg/ParceledListSlice.java @@ -136,7 +136,7 @@ public class ParceledListSlice implements Parcelable { new Parcelable.ClassLoaderCreator() { @Override public ParceledListSlice createFromParcel(Parcel in) { - return new ParceledListSlice(in, null); + return new ParceledListSlice(in, ParceledListSlice.class.getClassLoader()); } @Override diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/RootClient.kt b/app/src/main/java/io/nekohasekai/sfa/bg/RootClient.kt index ab33003..735c7cd 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/RootClient.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/RootClient.kt @@ -6,6 +6,7 @@ import android.content.ServiceConnection import android.content.pm.PackageInfo import android.os.IBinder import android.os.RemoteException +import androidx.core.content.ContextCompat import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ipc.RootService import io.nekohasekai.sfa.Application @@ -17,7 +18,9 @@ import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import java.io.IOException import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException object RootClient { init { @@ -53,6 +56,10 @@ object RootClient { suspend fun bindService(): IRootService = connectionMutex.withLock { service?.let { return it } + if (Shell.isAppGrantedRoot() == false) { + throw IOException("permission denied") + } + return withContext(Dispatchers.Main) { suspendCancellableCoroutine { continuation -> val conn = object : ServiceConnection { @@ -72,7 +79,30 @@ object RootClient { } val intent = Intent(Application.application, RootServer::class.java) - RootService.bind(intent, conn) + val task = RootService.bindOrTask( + intent, + ContextCompat.getMainExecutor(Application.application), + conn, + ) + + if (task == null) { + // Already connected, onServiceConnected will fire + } else { + Shell.EXECUTOR.execute { + try { + val shell = Shell.getShell() + if (shell.isRoot) { + shell.execTask(task) + } else { + continuation.resumeWithException( + IOException("permission denied") + ) + } + } catch (e: Exception) { + continuation.resumeWithException(e) + } + } + } continuation.invokeOnCancellation { RootService.unbind(conn)