fix: shizuku

This commit is contained in:
lisonge 2023-09-25 20:47:00 +08:00
parent aa706b9fd5
commit c93fa87cb5
9 changed files with 131 additions and 99 deletions

View File

@ -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()

View File

@ -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(

View File

@ -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 {

View 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()
}
}

View File

@ -7,7 +7,6 @@ fun shizukuIsSafeOK(): Boolean {
return try {
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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!");

View File

@ -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")