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>() { new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
@Override @Override
public ParceledListSlice createFromParcel(Parcel in) { public ParceledListSlice createFromParcel(Parcel in) {
return new ParceledListSlice(in, null); return new ParceledListSlice(in, ParceledListSlice.class.getClassLoader());
} }
@Override @Override

View File

@@ -6,6 +6,7 @@ import android.content.ServiceConnection
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.os.IBinder import android.os.IBinder
import android.os.RemoteException import android.os.RemoteException
import androidx.core.content.ContextCompat
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ipc.RootService import com.topjohnwu.superuser.ipc.RootService
import io.nekohasekai.sfa.Application import io.nekohasekai.sfa.Application
@@ -17,7 +18,9 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.IOException
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
object RootClient { object RootClient {
init { init {
@@ -53,6 +56,10 @@ object RootClient {
suspend fun bindService(): IRootService = connectionMutex.withLock { suspend fun bindService(): IRootService = connectionMutex.withLock {
service?.let { return it } service?.let { return it }
if (Shell.isAppGrantedRoot() == false) {
throw IOException("permission denied")
}
return withContext(Dispatchers.Main) { return withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation -> suspendCancellableCoroutine { continuation ->
val conn = object : ServiceConnection { val conn = object : ServiceConnection {
@@ -72,7 +79,30 @@ object RootClient {
} }
val intent = Intent(Application.application, RootServer::class.java) 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 { continuation.invokeOnCancellation {
RootService.unbind(conn) RootService.unbind(conn)