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
This commit is contained in:
世界
2026-03-12 22:27:48 +08:00
parent 0d31ac467f
commit d64e3b4235
2 changed files with 32 additions and 2 deletions

View File

@@ -136,7 +136,7 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable {
new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
@Override
public ParceledListSlice createFromParcel(Parcel in) {
return new ParceledListSlice(in, null);
return new ParceledListSlice(in, ParceledListSlice.class.getClassLoader());
}
@Override

View File

@@ -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)