mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-01-12 12:13:39 +00:00
Introduce RootServices to the app
This commit is contained in:
parent
de3747d65e
commit
edcf9f1b0c
@ -94,9 +94,10 @@ dependencies {
|
|||||||
implementation("io.noties.markwon:image:${vMarkwon}")
|
implementation("io.noties.markwon:image:${vMarkwon}")
|
||||||
implementation("com.caverock:androidsvg:1.4")
|
implementation("com.caverock:androidsvg:1.4")
|
||||||
|
|
||||||
val vLibsu = "3.2.0"
|
val vLibsu = "3.2.1"
|
||||||
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
|
implementation("com.github.topjohnwu.libsu:core:${vLibsu}")
|
||||||
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
|
implementation("com.github.topjohnwu.libsu:io:${vLibsu}")
|
||||||
|
implementation("com.github.topjohnwu.libsu:service:${vLibsu}")
|
||||||
|
|
||||||
val vRetrofit = "2.9.0"
|
val vRetrofit = "2.9.0"
|
||||||
implementation("com.squareup.retrofit2:retrofit:${vRetrofit}")
|
implementation("com.squareup.retrofit2:retrofit:${vRetrofit}")
|
||||||
|
@ -9,11 +9,9 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
|||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.*
|
||||||
import com.topjohnwu.magisk.core.Const
|
|
||||||
import com.topjohnwu.magisk.core.JobService
|
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||||
|
import com.topjohnwu.magisk.core.utils.RootRegistry
|
||||||
import com.topjohnwu.magisk.di.ServiceLocator
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.ui.theme.Theme
|
import com.topjohnwu.magisk.ui.theme.Theme
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
@ -21,6 +19,7 @@ import com.topjohnwu.magisk.view.Notifications
|
|||||||
import com.topjohnwu.magisk.view.Shortcuts
|
import com.topjohnwu.magisk.view.Shortcuts
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
abstract class BaseMainActivity<VM : BaseViewModel, Binding : ViewDataBinding>
|
abstract class BaseMainActivity<VM : BaseViewModel, Binding : ViewDataBinding>
|
||||||
: BaseUIActivity<VM, Binding>() {
|
: BaseUIActivity<VM, Binding>() {
|
||||||
@ -48,13 +47,15 @@ abstract class BaseMainActivity<VM : BaseViewModel, Binding : ViewDataBinding>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (doPreload) {
|
if (doPreload) {
|
||||||
// Pre-initialize root shell
|
|
||||||
Shell.getShell(null) {
|
Shell.getShell(null) {
|
||||||
if (isRunningAsStub && !Shell.rootAccess()) {
|
if (isRunningAsStub && !it.isRoot) {
|
||||||
showInvalidStateMessage()
|
showInvalidStateMessage()
|
||||||
return@getShell
|
return@getShell
|
||||||
}
|
}
|
||||||
preLoad()
|
preLoad()
|
||||||
|
if (it.isRoot) {
|
||||||
|
RootRegistry.Connection.await(2, TimeUnit.SECONDS)
|
||||||
|
}
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
doPreload = false
|
doPreload = false
|
||||||
if (isRunningAsStub) {
|
if (isRunningAsStub) {
|
||||||
|
@ -7,13 +7,15 @@ import android.content.Context
|
|||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.topjohnwu.magisk.DynAPK
|
import com.topjohnwu.magisk.DynAPK
|
||||||
import com.topjohnwu.magisk.core.utils.AppShellInit
|
|
||||||
import com.topjohnwu.magisk.core.utils.BusyBoxInit
|
|
||||||
import com.topjohnwu.magisk.core.utils.IODispatcherExecutor
|
import com.topjohnwu.magisk.core.utils.IODispatcherExecutor
|
||||||
|
import com.topjohnwu.magisk.core.utils.RootRegistry
|
||||||
|
import com.topjohnwu.magisk.core.utils.ShellInit
|
||||||
import com.topjohnwu.magisk.core.utils.updateConfig
|
import com.topjohnwu.magisk.core.utils.updateConfig
|
||||||
import com.topjohnwu.magisk.di.ServiceLocator
|
import com.topjohnwu.magisk.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.ktx.unwrap
|
import com.topjohnwu.magisk.ktx.unwrap
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
|
import com.topjohnwu.superuser.ipc.RootService
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
@ -26,7 +28,7 @@ open class App() : Application() {
|
|||||||
init {
|
init {
|
||||||
Shell.setDefaultBuilder(Shell.Builder.create()
|
Shell.setDefaultBuilder(Shell.Builder.create()
|
||||||
.setFlags(Shell.FLAG_MOUNT_MASTER)
|
.setFlags(Shell.FLAG_MOUNT_MASTER)
|
||||||
.setInitializers(BusyBoxInit::class.java, AppShellInit::class.java)
|
.setInitializers(ShellInit::class.java)
|
||||||
.setTimeout(2))
|
.setTimeout(2))
|
||||||
Shell.EXECUTOR = IODispatcherExecutor()
|
Shell.EXECUTOR = IODispatcherExecutor()
|
||||||
|
|
||||||
@ -57,6 +59,15 @@ open class App() : Application() {
|
|||||||
app.registerActivityLifecycleCallbacks(ForegroundTracker)
|
app.registerActivityLifecycleCallbacks(ForegroundTracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
RootRegistry.bindTask = RootService.createBindTask(
|
||||||
|
intent<RootRegistry>(),
|
||||||
|
UiThreadHandler.executor,
|
||||||
|
RootRegistry.Connection
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// This is required as some platforms expect ContextImpl
|
// This is required as some platforms expect ContextImpl
|
||||||
override fun getBaseContext(): Context {
|
override fun getBaseContext(): Context {
|
||||||
return super.getBaseContext().unwrap()
|
return super.getBaseContext().unwrap()
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
package com.topjohnwu.magisk.core.utils
|
package com.topjohnwu.magisk.core.utils
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.util.concurrent.*
|
import java.util.concurrent.AbstractExecutorService
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class IODispatcherExecutor : AbstractExecutorService() {
|
class IODispatcherExecutor : AbstractExecutorService() {
|
||||||
|
|
||||||
private val job = SupervisorJob().apply { invokeOnCompletion { future.run() } }
|
private val job = SupervisorJob()
|
||||||
private val scope = CoroutineScope(job + Dispatchers.IO)
|
private val scope = CoroutineScope(job + Dispatchers.IO)
|
||||||
private val future = FutureTask(Callable { true })
|
private val latch = CountDownLatch(1)
|
||||||
|
|
||||||
|
init {
|
||||||
|
job.invokeOnCompletion { latch.countDown() }
|
||||||
|
}
|
||||||
|
|
||||||
override fun execute(command: Runnable) {
|
override fun execute(command: Runnable) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@ -26,11 +32,5 @@ class IODispatcherExecutor : AbstractExecutorService() {
|
|||||||
|
|
||||||
override fun isTerminated() = job.isCancelled && job.isCompleted
|
override fun isTerminated() = job.isCancelled && job.isCompleted
|
||||||
|
|
||||||
override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean {
|
override fun awaitTermination(timeout: Long, unit: TimeUnit) = latch.await(timeout, unit)
|
||||||
return try {
|
|
||||||
future.get(timeout, unit)
|
|
||||||
} catch (e: TimeoutException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package com.topjohnwu.magisk.core.utils
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.IBinder
|
||||||
|
import com.topjohnwu.superuser.ipc.RootService
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
class RootRegistry : RootService() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Always log full stack trace with Timber
|
||||||
|
Timber.plant(Timber.DebugTree())
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler { _, e ->
|
||||||
|
Timber.e(e)
|
||||||
|
exitProcess(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent): IBinder {
|
||||||
|
// TODO: PLACEHOLDER
|
||||||
|
return Binder()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: PLACEHOLDER
|
||||||
|
object Connection : CountDownLatch(1), ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||||
|
Timber.d("onServiceConnected")
|
||||||
|
countDown()
|
||||||
|
}
|
||||||
|
override fun onNullBinding(name: ComponentName) {
|
||||||
|
Timber.d("onServiceConnected")
|
||||||
|
countDown()
|
||||||
|
}
|
||||||
|
override fun onServiceDisconnected(name: ComponentName) {
|
||||||
|
bind(Intent().setComponent(name), this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var bindTask: Runnable? = null
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,10 @@ package com.topjohnwu.magisk.core.utils
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.topjohnwu.magisk.DynAPK
|
import com.topjohnwu.magisk.DynAPK
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.*
|
import com.topjohnwu.magisk.core.Config
|
||||||
|
import com.topjohnwu.magisk.core.Const
|
||||||
|
import com.topjohnwu.magisk.core.Info
|
||||||
|
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.ktx.cachedFile
|
import com.topjohnwu.magisk.ktx.cachedFile
|
||||||
import com.topjohnwu.magisk.ktx.deviceProtectedContext
|
import com.topjohnwu.magisk.ktx.deviceProtectedContext
|
||||||
import com.topjohnwu.magisk.ktx.rawResource
|
import com.topjohnwu.magisk.ktx.rawResource
|
||||||
@ -13,18 +16,12 @@ import com.topjohnwu.superuser.ShellUtils
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
|
|
||||||
abstract class BaseShellInit : Shell.Initializer() {
|
class ShellInit : Shell.Initializer() {
|
||||||
final override fun onInit(context: Context, shell: Shell): Boolean {
|
override fun onInit(context: Context, shell: Shell): Boolean {
|
||||||
return init(context.wrap(), shell)
|
if (shell.isRoot) {
|
||||||
}
|
RootRegistry.bindTask?.run()
|
||||||
|
RootRegistry.bindTask = null
|
||||||
abstract fun init(context: Context, shell: Shell): Boolean
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BusyBoxInit : BaseShellInit() {
|
|
||||||
|
|
||||||
override fun init(context: Context, shell: Shell): Boolean {
|
|
||||||
shell.newJob().apply {
|
shell.newJob().apply {
|
||||||
add("export ASH_STANDALONE=1")
|
add("export ASH_STANDALONE=1")
|
||||||
|
|
||||||
@ -63,20 +60,7 @@ class BusyBoxInit : BaseShellInit() {
|
|||||||
// Directly execute the file
|
// Directly execute the file
|
||||||
add("exec $localBB sh")
|
add("exec $localBB sh")
|
||||||
}
|
}
|
||||||
}.exec()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppShellInit : BaseShellInit() {
|
|
||||||
|
|
||||||
override fun init(context: Context, shell: Shell): Boolean {
|
|
||||||
|
|
||||||
fun fastCmd(cmd: String) = ShellUtils.fastCmd(shell, cmd)
|
|
||||||
fun getVar(name: String) = fastCmd("echo \$$name")
|
|
||||||
fun getBool(name: String) = getVar(name).toBoolean()
|
|
||||||
|
|
||||||
shell.newJob().apply {
|
|
||||||
add(context.rawResource(R.raw.manager))
|
add(context.rawResource(R.raw.manager))
|
||||||
if (shell.isRoot) {
|
if (shell.isRoot) {
|
||||||
add(context.assets.open("util_functions.sh"))
|
add(context.assets.open("util_functions.sh"))
|
||||||
@ -84,6 +68,10 @@ class AppShellInit : BaseShellInit() {
|
|||||||
add("app_init")
|
add("app_init")
|
||||||
}.exec()
|
}.exec()
|
||||||
|
|
||||||
|
fun fastCmd(cmd: String) = ShellUtils.fastCmd(shell, cmd)
|
||||||
|
fun getVar(name: String) = fastCmd("echo \$$name")
|
||||||
|
fun getBool(name: String) = getVar(name).toBoolean()
|
||||||
|
|
||||||
Const.MAGISKTMP = getVar("MAGISKTMP")
|
Const.MAGISKTMP = getVar("MAGISKTMP")
|
||||||
Info.isSAR = getBool("SYSTEM_ROOT")
|
Info.isSAR = getBool("SYSTEM_ROOT")
|
||||||
Info.ramdisk = getBool("RAMDISKEXIST")
|
Info.ramdisk = getBool("RAMDISKEXIST")
|
||||||
@ -95,6 +83,9 @@ class AppShellInit : BaseShellInit() {
|
|||||||
Config.keepVerity = getBool("KEEPVERITY")
|
Config.keepVerity = getBool("KEEPVERITY")
|
||||||
Config.keepEnc = getBool("KEEPFORCEENCRYPT")
|
Config.keepEnc = getBool("KEEPFORCEENCRYPT")
|
||||||
|
|
||||||
|
// Pre-fetch env
|
||||||
|
Info.env
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user