mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 03:32:38 +08:00
fix: shizuku
This commit is contained in:
parent
aa706b9fd5
commit
c93fa87cb5
|
@ -40,16 +40,17 @@ class App : Application() {
|
|||
super.onCreate()
|
||||
_app = this
|
||||
|
||||
ShizukuProvider.enableMultiProcessSupport(isMainProcess)
|
||||
|
||||
CrashReport.initCrashReport(applicationContext, "d0ce46b353", false)
|
||||
MMKV.initialize(this)
|
||||
LogUtils.getConfig().apply {
|
||||
isLog2FileSwitch = true
|
||||
setConsoleSwitch(BuildConfig.DEBUG)
|
||||
saveDays = 3
|
||||
}
|
||||
CrashReport.initCrashReport(applicationContext, "d0ce46b353", false)
|
||||
|
||||
ShizukuProvider.enableMultiProcessSupport(isMainProcess)
|
||||
if (!isMainProcess) {
|
||||
ShizukuProvider.requestBinderForNonProviderProcess(this)
|
||||
}
|
||||
if (isMainProcess) {
|
||||
appScope.launchTry(Dispatchers.IO) {
|
||||
initChannel()
|
||||
|
|
|
@ -17,12 +17,8 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import li.songe.gkd.composition.CompositionAbService
|
||||
import li.songe.gkd.composition.CompositionExt.useLifeCycleLog
|
||||
|
@ -37,9 +33,7 @@ import li.songe.gkd.data.click
|
|||
import li.songe.gkd.data.clickCenter
|
||||
import li.songe.gkd.data.clickNode
|
||||
import li.songe.gkd.db.DbSet
|
||||
import li.songe.gkd.shizuku.newActivityTaskManager
|
||||
import li.songe.gkd.shizuku.shizukuIsSafeOK
|
||||
import li.songe.gkd.shizuku.useShizukuAliveState
|
||||
import li.songe.gkd.shizuku.useSafeGetTasksFc
|
||||
import li.songe.gkd.util.Singleton
|
||||
import li.songe.gkd.util.increaseClickCount
|
||||
import li.songe.gkd.util.launchTry
|
||||
|
@ -51,6 +45,7 @@ import li.songe.selector.Selector
|
|||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
class GkdAbService : CompositionAbService({
|
||||
useLifeCycleLog()
|
||||
|
@ -77,33 +72,13 @@ class GkdAbService : CompositionAbService({
|
|||
delay(1000)
|
||||
}
|
||||
|
||||
val shizukuAliveFlow = useShizukuAliveState()
|
||||
val shizukuGrantFlow = MutableStateFlow(false)
|
||||
scope.launchWhile(IO) {
|
||||
shizukuGrantFlow.value = if (shizukuAliveFlow.value) shizukuIsSafeOK() else false
|
||||
delay(3000)
|
||||
}
|
||||
val activityTaskManagerFlow =
|
||||
combine(shizukuAliveFlow, shizukuGrantFlow) { shizukuAlive, shizukuGrant ->
|
||||
if (shizukuAlive && shizukuGrant) newActivityTaskManager() else null
|
||||
}.flowOn(IO).stateIn(scope, SharingStarted.Eagerly, null)
|
||||
|
||||
fun getActivityIdByShizuku(): String? {
|
||||
try {
|
||||
val topActivity =
|
||||
activityTaskManagerFlow.value?.getTasks(1, false, true)?.firstOrNull()?.topActivity
|
||||
return topActivity?.className
|
||||
} catch (_: NoSuchMethodError) {
|
||||
// java.lang.NoSuchMethodError
|
||||
// 貌似不同手机的方法签名不一样
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
var serviceConnected = false
|
||||
onServiceConnected { serviceConnected = true }
|
||||
onInterrupt { serviceConnected = false }
|
||||
|
||||
val safeGetTasksFc = useSafeGetTasksFc(scope)
|
||||
fun getActivityIdByShizuku(): String? {
|
||||
return safeGetTasksFc()?.lastOrNull()?.topActivity?.className
|
||||
}
|
||||
|
||||
fun isActivity(appId: String, activityId: String): Boolean {
|
||||
return activityId.startsWith(appId) || (try {
|
||||
|
@ -114,7 +89,7 @@ class GkdAbService : CompositionAbService({
|
|||
}
|
||||
|
||||
onAccessibilityEvent { event -> // 根据事件获取 activityId, 概率不准确
|
||||
if (event == null || isScreenLock) return@onAccessibilityEvent
|
||||
if (event == null) return@onAccessibilityEvent
|
||||
|
||||
when (event.eventType) {
|
||||
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
|
||||
|
@ -221,7 +196,7 @@ class GkdAbService : CompositionAbService({
|
|||
|
||||
var lastUpdateSubsTime = System.currentTimeMillis()
|
||||
scope.launchWhile(IO) { // 自动从网络更新订阅文件
|
||||
delay(30 * 60_000)
|
||||
delay(10 * 60_000) // 每 10 分钟检查一次
|
||||
if (isScreenLock // 锁屏
|
||||
|| storeFlow.value.updateSubsInterval <= 0 // 暂停更新
|
||||
|| System.currentTimeMillis() - lastUpdateSubsTime < storeFlow.value.updateSubsInterval.coerceAtLeast(
|
||||
|
|
|
@ -2,7 +2,6 @@ package li.songe.gkd.service
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
import li.songe.gkd.app
|
||||
|
@ -15,7 +14,6 @@ import li.songe.gkd.notif.defaultChannel
|
|||
import li.songe.gkd.util.appIdToRulesFlow
|
||||
import li.songe.gkd.util.clickCountFlow
|
||||
import li.songe.gkd.util.storeFlow
|
||||
import rikka.shizuku.ShizukuProvider
|
||||
|
||||
class ManageService : CompositionService({
|
||||
useLifeCycleLog()
|
||||
|
@ -23,17 +21,11 @@ class ManageService : CompositionService({
|
|||
createNotif(context, defaultChannel.id, abNotif)
|
||||
val scope = useScope()
|
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
|
||||
// https://github.com/RikkaApps/Shizuku-API/issues/54
|
||||
ShizukuProvider.requestBinderForNonProviderProcess(this)
|
||||
}
|
||||
|
||||
scope.launch {
|
||||
combine(appIdToRulesFlow, clickCountFlow, storeFlow) { appIdToRules, clickCount, store ->
|
||||
if (!store.enableService) return@combine "服务已暂停"
|
||||
val appSize = appIdToRules.keys.size
|
||||
val groupSize =
|
||||
appIdToRules.values.flatten().map { r -> r.group.hashCode() }.toSet().size
|
||||
val groupSize = appIdToRules.values.sumOf { r -> r.size }
|
||||
(if (groupSize > 0) {
|
||||
"${appSize}应用/${groupSize}规则组"
|
||||
} else {
|
||||
|
|
104
app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt
Normal file
104
app/src/main/java/li/songe/gkd/shizuku/ShizukuApi.kt
Normal file
|
@ -0,0 +1,104 @@
|
|||
package li.songe.gkd.shizuku
|
||||
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.app.IActivityTaskManager
|
||||
import android.os.Build
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.blankj.utilcode.util.RomUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import li.songe.gkd.composition.CanOnDestroy
|
||||
import li.songe.gkd.data.DeviceInfo
|
||||
import li.songe.gkd.util.launchWhile
|
||||
import rikka.shizuku.Shizuku
|
||||
import rikka.shizuku.ShizukuBinderWrapper
|
||||
import rikka.shizuku.SystemServiceHelper
|
||||
import kotlin.reflect.full.declaredMemberFunctions
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* https://github.com/gkd-kit/gkd/issues/44
|
||||
*/
|
||||
|
||||
val skipShizuku by lazy {
|
||||
Build.VERSION.SDK_INT == Build.VERSION_CODES.P && RomUtils.isVivo()
|
||||
}
|
||||
|
||||
fun newActivityTaskManager(): IActivityTaskManager? {
|
||||
return SystemServiceHelper.getSystemService("activity_task").let(::ShizukuBinderWrapper)
|
||||
.let(IActivityTaskManager.Stub::asInterface)
|
||||
}
|
||||
|
||||
/**
|
||||
* -1: invalid fc
|
||||
* 1: (int) -> List<Task>
|
||||
* 3: (int, boolean, boolean) -> List<Task>
|
||||
*/
|
||||
private var getTasksFcType: Int? = null
|
||||
|
||||
fun IActivityTaskManager.safeGetTasks(): List<ActivityManager.RunningTaskInfo>? {
|
||||
if (getTasksFcType == null) {
|
||||
val fcs = this::class.declaredMemberFunctions
|
||||
val parameters = fcs.find { d -> d.name == "getTasks" }?.parameters
|
||||
if (parameters != null) {
|
||||
if (parameters.size == 4 && parameters[1].type == typeOf<Int>() && parameters[2].type == typeOf<Boolean>() && parameters[3].type == typeOf<Boolean>()) {
|
||||
getTasksFcType = 3
|
||||
} else if (parameters.size == 2 && parameters[1].type == typeOf<Int>()) {
|
||||
getTasksFcType = 1
|
||||
} else {
|
||||
getTasksFcType = -1
|
||||
LogUtils.d(DeviceInfo.instance)
|
||||
LogUtils.d(fcs)
|
||||
ToastUtils.showShort("Shizuku获取方法签名错误,[设置-问题反馈]可反应此问题")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getTasksFcType == 1) {
|
||||
return this.getTasks(1)
|
||||
} else if (getTasksFcType == 3) {
|
||||
return this.getTasks(1, false, true)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun CanOnDestroy.useShizukuAliveState(): StateFlow<Boolean> {
|
||||
val shizukuAliveFlow = MutableStateFlow(Shizuku.pingBinder())
|
||||
val receivedListener = Shizuku.OnBinderReceivedListener { shizukuAliveFlow.value = true }
|
||||
val deadListener = Shizuku.OnBinderDeadListener { shizukuAliveFlow.value = false }
|
||||
Shizuku.addBinderReceivedListener(receivedListener)
|
||||
Shizuku.addBinderDeadListener(deadListener)
|
||||
onDestroy {
|
||||
Shizuku.removeBinderReceivedListener(receivedListener)
|
||||
Shizuku.removeBinderDeadListener(deadListener)
|
||||
}
|
||||
return shizukuAliveFlow
|
||||
}
|
||||
|
||||
fun CanOnDestroy.useSafeGetTasksFc(scope: CoroutineScope): () -> List<ActivityManager.RunningTaskInfo>? {
|
||||
if (skipShizuku) {
|
||||
return { null }
|
||||
}
|
||||
val shizukuAliveFlow = useShizukuAliveState()
|
||||
val shizukuGrantFlow = MutableStateFlow(false)
|
||||
scope.launchWhile(Dispatchers.IO) {
|
||||
shizukuGrantFlow.value = if (shizukuAliveFlow.value) shizukuIsSafeOK() else false
|
||||
delay(3000)
|
||||
}
|
||||
val activityTaskManagerFlow =
|
||||
combine(shizukuAliveFlow, shizukuGrantFlow) { shizukuAlive, shizukuGrant ->
|
||||
if (shizukuAlive && shizukuGrant) newActivityTaskManager() else null
|
||||
}.flowOn(Dispatchers.IO).stateIn(scope, SharingStarted.Lazily, null)
|
||||
return {
|
||||
activityTaskManagerFlow.value?.safeGetTasks()
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ fun shizukuIsSafeOK(): Boolean {
|
|||
return try {
|
||||
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
package li.songe.gkd.shizuku
|
||||
|
||||
|
||||
import android.app.IActivityTaskManager
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import li.songe.gkd.composition.CanOnDestroy
|
||||
import li.songe.gkd.data.DeviceInfo
|
||||
import rikka.shizuku.Shizuku
|
||||
import rikka.shizuku.ShizukuBinderWrapper
|
||||
import rikka.shizuku.SystemServiceHelper
|
||||
import kotlin.reflect.full.declaredMemberFunctions
|
||||
|
||||
fun newActivityTaskManager(): IActivityTaskManager? {
|
||||
val manager = SystemServiceHelper.getSystemService("activity_task").let(::ShizukuBinderWrapper)
|
||||
.let(IActivityTaskManager.Stub::asInterface)
|
||||
try {
|
||||
// 不同手机的签名api貌似不一样
|
||||
manager.getTasks(0, false, true)
|
||||
} catch (e: NoSuchMethodError) {
|
||||
LogUtils.d(DeviceInfo.instance)
|
||||
LogUtils.d(manager::class.declaredMemberFunctions)
|
||||
ToastUtils.showShort("Shizuku获取方法签名错误,[设置-问题反馈]可反应此问题")
|
||||
return null
|
||||
} catch (e: ClassNotFoundException) {
|
||||
ToastUtils.showShort("Shizuku获取系统对象错误,Shizuku将不生效")
|
||||
return null
|
||||
}
|
||||
return manager
|
||||
}
|
||||
|
||||
|
||||
fun CanOnDestroy.useShizukuAliveState(): StateFlow<Boolean> {
|
||||
val shizukuAliveFlow = MutableStateFlow(Shizuku.pingBinder())
|
||||
val receivedListener = Shizuku.OnBinderReceivedListener { shizukuAliveFlow.value = true }
|
||||
val deadListener = Shizuku.OnBinderDeadListener { shizukuAliveFlow.value = false }
|
||||
Shizuku.addBinderReceivedListener(receivedListener)
|
||||
Shizuku.addBinderDeadListener(deadListener)
|
||||
onDestroy {
|
||||
Shizuku.removeBinderReceivedListener(receivedListener)
|
||||
Shizuku.removeBinderDeadListener(deadListener)
|
||||
}
|
||||
return shizukuAliveFlow
|
||||
}
|
|
@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.dylanc.activityresult.launcher.launchForResult
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
|
@ -47,6 +48,7 @@ import li.songe.gkd.debug.FloatingService
|
|||
import li.songe.gkd.debug.HttpService
|
||||
import li.songe.gkd.debug.ScreenshotService
|
||||
import li.songe.gkd.shizuku.newActivityTaskManager
|
||||
import li.songe.gkd.shizuku.safeGetTasks
|
||||
import li.songe.gkd.shizuku.shizukuIsSafeOK
|
||||
import li.songe.gkd.ui.component.AuthCard
|
||||
import li.songe.gkd.ui.component.SettingItem
|
||||
|
@ -94,13 +96,14 @@ fun DebugPage() {
|
|||
if (shizukuIsOk) {
|
||||
// check method type
|
||||
appScope.launchTry(Dispatchers.IO) {
|
||||
newActivityTaskManager()
|
||||
LogUtils.d(newActivityTaskManager()?.safeGetTasks()
|
||||
?.map { t -> t.topActivity?.className })
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!shizukuIsOk) {
|
||||
AuthCard(title = "Shizuku授权",
|
||||
desc = "高级运行模式,能更准确识别界面活动ID\nAndroid14暂无法使用",
|
||||
desc = "高级运行模式,能更准确识别界面活动ID",
|
||||
onAuthClick = {
|
||||
try {
|
||||
Shizuku.requestPermission(Activity.RESULT_OK)
|
||||
|
|
|
@ -8,8 +8,12 @@ import java.util.List;
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
public interface IActivityTaskManager extends IInterface {
|
||||
// miui
|
||||
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra);
|
||||
|
||||
// https://github.com/gkd-kit/gkd/issues/58#issuecomment-1732245703
|
||||
List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
|
||||
|
||||
abstract class Stub extends Binder implements IActivityTaskManager {
|
||||
public static IActivityTaskManager asInterface(IBinder obj) {
|
||||
throw new RuntimeException("Stub!");
|
||||
|
|
|
@ -75,8 +75,8 @@ dependencyResolutionManagement {
|
|||
library("rikka.runtime", "dev.rikka.tools.refine:runtime:4.3.0")
|
||||
|
||||
// https://github.com/RikkaApps/Shizuku-API
|
||||
library("rikka.shizuku.api", "dev.rikka.shizuku:api:13.1.4")
|
||||
library("rikka.shizuku.provider", "dev.rikka.shizuku:provider:13.1.4")
|
||||
library("rikka.shizuku.api", "dev.rikka.shizuku:api:13.1.5")
|
||||
library("rikka.shizuku.provider", "dev.rikka.shizuku:provider:13.1.5")
|
||||
|
||||
// https://github.com/LSPosed/AndroidHiddenApiBypass
|
||||
library("lsposed.hiddenapibypass", "org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
|
||||
|
|
Loading…
Reference in New Issue
Block a user