manager: mount modules webui resources to manager directly.

This commit is contained in:
weishu
2024-02-22 16:01:03 +08:00
parent 9c4d20c0f2
commit 329010a694
3 changed files with 15 additions and 35 deletions

View File

@@ -5,6 +5,7 @@ import coil.Coil
import coil.ImageLoader import coil.ImageLoader
import me.zhanghai.android.appiconloader.coil.AppIconFetcher import me.zhanghai.android.appiconloader.coil.AppIconFetcher
import me.zhanghai.android.appiconloader.coil.AppIconKeyer import me.zhanghai.android.appiconloader.coil.AppIconKeyer
import java.io.File
lateinit var ksuApp: KernelSUApplication lateinit var ksuApp: KernelSUApplication
@@ -24,6 +25,11 @@ class KernelSUApplication : Application() {
} }
.build() .build()
) )
val webroot = File(dataDir, "webroot")
if (!webroot.exists()) {
webroot.mkdir()
}
} }

View File

@@ -15,34 +15,26 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.lifecycleScope
import com.google.accompanist.web.WebView import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewState import com.google.accompanist.web.rememberWebViewState
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.weishu.kernelsu.ui.util.createRootShell import me.weishu.kernelsu.ui.util.createRootShell
import me.weishu.kernelsu.ui.util.serveModule import me.weishu.kernelsu.ui.util.serveModule
import java.net.ServerSocket
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Destination @Destination
@Composable @Composable
fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: String) { fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: String) {
val port = 8080
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
serveModule(moduleId, port) serveModule(moduleId)
} }
val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current val context = LocalContext.current
DisposableEffect(Unit) { DisposableEffect(Unit) {
@@ -50,15 +42,12 @@ fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: St
if (WebViewInterface.isHideSystemUI && context is Activity) { if (WebViewInterface.isHideSystemUI && context is Activity) {
showSystemUI(context.window) showSystemUI(context.window)
} }
lifecycleOwner.lifecycleScope.launch {
stopServer(port)
}
} }
} }
Scaffold { innerPadding -> Scaffold { innerPadding ->
WebView( WebView(
state = rememberWebViewState(url = "http://localhost:$port"), state = rememberWebViewState(url = "file:///data/data/me.weishu.kernelsu/webroot/index.html"),
Modifier Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding), .padding(innerPadding),
@@ -66,6 +55,7 @@ fun WebScreen(navigator: DestinationsNavigator, moduleId: String, moduleName: St
android.webkit.WebView(context).apply { android.webkit.WebView(context).apply {
settings.javaScriptEnabled = true settings.javaScriptEnabled = true
settings.domStorageEnabled = true settings.domStorageEnabled = true
settings.allowFileAccess = true
addJavascriptInterface(WebViewInterface(context), "ksu") addJavascriptInterface(WebViewInterface(context), "ksu")
} }
}) })
@@ -100,22 +90,6 @@ class WebViewInterface(val context: Context) {
} }
private suspend fun getFreePort(): Int {
return withContext(Dispatchers.IO) {
ServerSocket(0).use { socket -> socket.localPort }
}
}
private suspend fun stopServer(port: Int) {
withContext(Dispatchers.IO) {
runCatching {
okhttp3.OkHttpClient()
.newCall(okhttp3.Request.Builder().url("http://localhost:$port/stop").build())
.execute()
}
}
}
private fun hideSystemUI(window: Window) { private fun hideSystemUI(window: Window) {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).let { controller -> WindowInsetsControllerCompat(window, window.decorView).let { controller ->

View File

@@ -131,13 +131,13 @@ fun installModule(
} }
} }
fun serveModule(id: String, port: Int): Process { fun serveModule(id: String): Boolean {
// we should use a new root shell to avoid blocking the global shell // we should use a new root shell to avoid blocking the global shell
val process = Runtime.getRuntime().exec("${getKsuDaemonPath()} debug su") val shell = createRootShell()
val builder = Shell.Builder.create() return ShellUtils.fastCmdResult(
val shell = builder.build(process) shell,
shell.newJob().add("${getKsuDaemonPath()} module serve $id $port").submit() "${getKsuDaemonPath()} module link-manager $id ${android.os.Process.myPid()} ${BuildConfig.APPLICATION_ID}"
return process )
} }
fun reboot(reason: String = "") { fun reboot(reason: String = "") {