diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0ab89fa..b33864a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -47,7 +47,7 @@
android:value="基于 Xposed 实现 OneBot 标准的 QQ 机器人框架" />
+ android:value="93" />
diff --git a/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt b/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt
index 275af4c..288c719 100644
--- a/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt
+++ b/app/src/main/java/moe/fuqiuluo/shamrock/ui/fragment/LabFragment.kt
@@ -1,5 +1,6 @@
package moe.fuqiuluo.shamrock.ui.fragment
+import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.absolutePadding
@@ -22,6 +23,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import moe.fuqiuluo.shamrock.R
import moe.fuqiuluo.shamrock.ui.app.AppRuntime
+import moe.fuqiuluo.shamrock.ui.app.Level
import moe.fuqiuluo.shamrock.ui.app.ShamrockConfig
import moe.fuqiuluo.shamrock.ui.theme.GlobalColor
import moe.fuqiuluo.shamrock.ui.theme.LocalString
@@ -90,7 +92,7 @@ fun LabFragment() {
modifier = Modifier.padding(top = 12.dp),
painter = painterResource(id = R.drawable.round_logo_dev_24),
title = "实验功能"
- ) {
+ ) { color ->
Column {
Divider(
modifier = Modifier,
@@ -101,7 +103,7 @@ fun LabFragment() {
Function(
title = "自动清理QQ垃圾",
desc = "也许会导致奇怪的问题(无效)。",
- descColor = it,
+ descColor = color,
isSwitch = ShamrockConfig.isAutoClean(ctx)
) {
ShamrockConfig.setAutoClean(ctx, it)
@@ -112,7 +114,7 @@ fun LabFragment() {
Function(
title = "拦截QQ无用收包",
desc = "测试阶段,可能导致网络异常或掉线。",
- descColor = it,
+ descColor = color,
isSwitch = ShamrockConfig.isInjectPacket(ctx)
) {
ShamrockConfig.setInjectPacket(ctx, it)
@@ -123,7 +125,7 @@ fun LabFragment() {
Function(
title = "自动唤醒QQ",
desc = "QQ进程死亡时重新打开QQ进程,前提本进程存活。",
- descColor = it,
+ descColor = color,
isSwitch = ShamrockConfig.enableAutoStart(ctx)
) {
ShamrockConfig.setAutoStart(ctx, it)
@@ -133,12 +135,30 @@ fun LabFragment() {
Function(
title = "开启Shell接口",
desc = "可能导致设备被入侵,请勿随意开启。",
- descColor = it,
+ descColor = color,
isSwitch = ShamrockConfig.allowShell(ctx)
) {
ShamrockConfig.setShellStatus(ctx, it)
return@Function true
}
+
+ kotlin.runCatching {
+ ctx.getSharedPreferences("shared_config", Context.MODE_WORLD_READABLE)
+ }.onSuccess {
+ Function(
+ title = "免死金牌",
+ desc = "由系统复活QQ和Shamrock,需要重新启动系统。",
+ descColor = color,
+ isSwitch = it.getBoolean("persistent", false)
+ ) { v ->
+ it.edit().putBoolean("persistent", v).apply()
+ scope.toast(ctx, "重启系统生效哦!")
+ return@Function true
+ }
+ }.onFailure {
+ AppRuntime.log("无法启用免死金牌选项,当前Lsposed模块未激活或者不支持NewSharedPreferences。", Level.WARN)
+ }
+
}
}
diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt
index 1deca8a..995a90c 100644
--- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt
+++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt
@@ -4,6 +4,7 @@ import io.ktor.http.ContentType
import io.ktor.http.content.PartData
import io.ktor.http.content.forEachPart
import io.ktor.http.content.streamProvider
+import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.request.receiveMultipart
import io.ktor.server.response.respondText
@@ -27,6 +28,7 @@ import moe.fuqiuluo.shamrock.tools.fetchOrThrow
import moe.fuqiuluo.shamrock.tools.fetchPostJsonArray
import moe.fuqiuluo.shamrock.tools.getOrPost
import moe.fuqiuluo.shamrock.tools.isJsonArray
+import moe.fuqiuluo.shamrock.tools.json
import moe.fuqiuluo.shamrock.tools.respond
import moe.fuqiuluo.shamrock.utils.FileUtils
import moe.fuqiuluo.shamrock.utils.MD5
@@ -39,7 +41,7 @@ fun Routing.otherAction() {
post("/shell") {
val runtime = Runtime.getRuntime()
val dir = fetchOrThrow("dir")
- val out = StringBuilder()
+ val out = hashMapOf()
withTimeoutOrNull(5000L) {
if (isJsonArray("cmd")) {
val cmd = fetchPostJsonArray("cmd").map {
@@ -59,17 +61,15 @@ fun Routing.otherAction() {
respond(false, Status.IAmTired, "执行超时")
} else {
it.inputStream.use {
- out.append("stdout:\n")
- out.append(it.readBytes().toString(Charsets.UTF_8))
+ out["out"] = it.readBytes().toString(Charsets.UTF_8)
}
it.errorStream.use {
- out.append("\nstderr:\n")
- out.append(it.readBytes().toString(Charsets.UTF_8))
+ out["err"] = it.readBytes().toString(Charsets.UTF_8)
}
}
}
- call.respondText(out.toString())
+ call.respondText(out.json.toString(), ContentType.Application.Json)
}
}
diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/FuckAMS.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/FuckAMS.kt
index 77568e7..e94002b 100644
--- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/FuckAMS.kt
+++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/loader/FuckAMS.kt
@@ -3,6 +3,8 @@ package moe.fuqiuluo.shamrock.xposed.loader
import android.content.pm.ApplicationInfo
import android.os.Build
+import com.arthenica.ffmpegkit.BuildConfig
+import de.robv.android.xposed.XSharedPreferences
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import moe.fuqiuluo.shamrock.tools.hookMethod
@@ -16,6 +18,7 @@ internal object FuckAMS {
private lateinit var KeepThread: Thread
private lateinit var METHOD_IS_KILLED: Method
+ private var allowPersistent: Boolean = false
fun injectAMS(loader: ClassLoader) {
kotlin.runCatching {
@@ -24,15 +27,24 @@ internal object FuckAMS {
increaseAdj(it.result)
}
}.onFailure {
- XposedBridge.log("Plan A failed: ${it.message}")
+ XposedBridge.log("[Shamrock] Plan A failed: ${it.message}")
}
+
+ val pref = XSharedPreferences("moe.fuqiuluo.shamrock", "shared_config")
+ if (pref.file.canRead()) {
+ allowPersistent = pref.getBoolean("persistent", false)
+ XposedBridge.log("[Shamrock] allowPersistent = $allowPersistent")
+ } else {
+ XposedBridge.log("[Shamrock] unable to load XSharedPreferences")
+ }
+
kotlin.runCatching {
val ProcessList = XposedHelpers.findClass("com.android.server.am.ProcessList", loader)
ProcessList.hookMethod("newProcessRecordLocked").after {
increaseAdj(it.result)
}
}.onFailure {
- XposedBridge.log("Plan B failed: ${it.message}")
+ XposedBridge.log("[Shamrock] Plan B failed: ${it.message}")
}
}
@@ -75,14 +87,14 @@ internal object FuckAMS {
if (!it.isAccessible) it.isAccessible = true
}.get(record) as ApplicationInfo
if(applicationInfo.processName in KeepPackage) {
- XposedBridge.log("Process is keeping: $record")
+ XposedBridge.log("[Shamrock] Process is keeping: $record")
KeepRecords.add(record)
keepByAdj(record)
// Error
- //if (noDied.exists()) {
- // XposedBridge.log("Open NoDied Mode!!!")
- // keepByPersistent(record)
- //}
+ if (allowPersistent) {
+ XposedBridge.log("[Shamrock] Open NoDied Mode!!!")
+ keepByPersistent(record)
+ }
checkThread()
}
}