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:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user