From 160472a5a58486070e285d03517b249aeee99a23 Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Thu, 25 Dec 2025 12:56:42 +0800 Subject: [PATCH] =?UTF-8?q?6.7.0=20-=20Alpha12=20-=20=E4=BF=AE=E5=A4=8D=20?= =?UTF-8?q?Shizuku=20=E7=94=A8=E6=88=B7=E6=9C=8D=E5=8A=A1=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E6=9C=AA=E8=83=BD=E6=AD=A3=E5=B8=B8=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E8=BF=9B=E7=A8=8B=E5=A0=86=E7=A7=AF=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(issue=20#474)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 3 +- .../autojs/autojs/core/shizuku/UserService.kt | 16 +++++ .../autojs/runtime/api/WrappedShizuku.kt | 64 ++++++++++++++++--- .../org/autojs/autojs/ui/main/MainActivity.kt | 8 ++- version.properties | 6 +- 5 files changed, 83 insertions(+), 14 deletions(-) diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 56b615be..bb3e6046 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -1,7 +1,7 @@ { "$data": { "v6.7.0": { - "released_date": "2025/12/23", + "released_date": "2025/12/25", "feature": [ "插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮)", "cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))", @@ -57,6 +57,7 @@ "项目配置文件中构建版本号或构建时间出现较大数字时可能导致应用崩溃的问题", "频繁获取或重建 ImageReader 时可能因缓冲区暂无可用帧导致应用崩溃的问题", "输入事件观察器 InputEventObserver 可能导致应用启动时明显卡顿的问题", + "Shizuku 用户服务进程未能正常结束导致进程堆积的问题 _[`issue #474`](http://issues.autojs6.com/474)_", "打包应用无法正常使用 Paddle OCR 与 Rapid OCR 功能的问题", "版本历史页面部分系统因字体差别导致统计数据显示不完整的问题", "部分设备无法正常初始化 MLKit Google OCR 的问题 (试修) _[`issue #8`](http://issues.autojs6.com/8#issuecomment-3117061768)_", diff --git a/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.kt b/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.kt index 49e658a4..8d4fbd8a 100644 --- a/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.kt +++ b/app/src/main/java/org/autojs/autojs/core/shizuku/UserService.kt @@ -3,11 +3,13 @@ package org.autojs.autojs.core.shizuku import android.app.ActivityManager import android.content.ComponentName import android.content.Context +import android.os.Process import android.os.RemoteException import android.util.Log import androidx.annotation.Keep import org.autojs.autojs.runtime.api.AbstractShell import org.autojs.autojs.runtime.api.ProcessShell +import kotlin.system.exitProcess class UserService : IUserService.Stub { @@ -49,8 +51,22 @@ class UserService : IUserService.Stub { */ override fun destroy() { Log.i("UserService", "destroy") + + // Ensure the user service process terminates when Shizuku server requests destroy. + // zh-CN: 确保 Shizuku server 请求 destroy 时, user service 进程能够真正退出. + runCatching { + Process.killProcess(Process.myPid()) + } + + // Fallback to exit the process if killProcess doesn't stop it immediately. + // zh-CN: 如果 killProcess 未能立刻终止, 则使用 exitProcess 作为兜底退出. + runCatching { + exitProcess(0) + } } + // Exit method defined by user. + // zh-CN: 用户定义的退出方法. override fun exit() { destroy() } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt index 78b1beab..b075c5c9 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.content.pm.PackageManager +import android.os.DeadObjectException import android.os.IBinder import android.util.Log import org.autojs.autojs.AbstractAutoJs.Companion.isInrt @@ -17,6 +18,7 @@ import org.autojs.autojs.util.App.SHIZUKU import org.autojs.autojs.util.ViewUtils import org.autojs.autojs6.R import rikka.shizuku.Shizuku +import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import org.autojs.autojs.runtime.api.AbstractShell.Result as ShellResult @@ -37,18 +39,27 @@ object WrappedShizuku { } private var mHasBinder = false + private val mServiceWaiters = CopyOnWriteArrayList() + private val mUserServiceConnection: ServiceConnection = object : ServiceConnection { override fun onServiceConnected(componentName: ComponentName, binder: IBinder?) { Log.d(TAG, "onServiceConnected: ${componentName.className}") if (binder?.pingBinder() == true) { service = IUserService.Stub.asInterface(binder) + + // Wake all waiters when binder is ready. + // zh-CN: 当 binder 就绪时, 唤醒所有等待者. + mServiceWaiters.forEach { it.countDown() } + mServiceWaiters.clear() } else { Log.w(TAG, "invalid binder for $componentName received") + service = null } } override fun onServiceDisconnected(componentName: ComponentName) { Log.d(TAG, "onServiceDisconnected: ${componentName.className}") + service = null } } @@ -87,6 +98,9 @@ object WrappedShizuku { } internal fun bindUserServiceIfNeeded() { + if (service?.asBinder()?.pingBinder() == true) { + return + } if (hasPermission()) { bindUserService() } @@ -148,17 +162,41 @@ object WrappedShizuku { @ScriptInterface fun execCommand(context: Context, cmd: String): ShellResult { + return execCommandWithAutoReconnect(context, cmd, allowRetry = true) + } + + private fun execCommandWithAutoReconnect(context: Context, cmd: String, allowRetry: Boolean): ShellResult { if (service == null && hasPermission()) { + onCreate() + bindUserServiceIfNeeded() initializeShizukuServiceAndWait(5000L) } + val service = service ?: when { !hasPermission() -> R.string.error_no_permission_to_access_shizuku !isRunning() -> R.string.error_shizuku_service_may_be_not_running else -> R.string.error_unable_to_use_shizuku_service }.let { throw IllegalStateException(context.getString(it)) } + return try { - ShellResult.fromJson(service.execCommand(cmd.replace(Regex("^\\s*adb\\s+shell\\s+", RegexOption.IGNORE_CASE), ""))) + ShellResult.fromJson( + service.execCommand( + cmd.replace(Regex("^\\s*adb\\s+shell\\s+", RegexOption.IGNORE_CASE), "") + ) + ) } catch (e: Throwable) { + // Reconnect and retry once when binder is dead. + // zh-CN: 当 binder 已死亡时, 自动重连并重试一次. + if (allowRetry && e is DeadObjectException) { + this.service = null + runCatching { + onCreate() + bindUserServiceIfNeeded() + initializeShizukuServiceAndWait(5000L) + } + return execCommandWithAutoReconnect(context, cmd, allowRetry = false) + } + ShellResult().apply { code = 1 error = e.message ?: when { @@ -191,17 +229,25 @@ object WrappedShizuku { } private fun initializeShizukuServiceAndWait(@Suppress("SameParameterValue") timeout: Long) { - onCreate() - bindUserServiceIfNeeded() + if (service?.asBinder()?.pingBinder() == true) { + return + } val latch = CountDownLatch(1) - val tmpConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName, binder: IBinder) = latch.countDown() - override fun onServiceDisconnected(name: ComponentName) = Unit + mServiceWaiters.add(latch) + + // Re-check after registering waiter to avoid missing a fast onServiceConnected(). + // zh-CN: 注册等待者后再次检查, 避免 onServiceConnected() 很快到来导致错过唤醒. + if (service?.asBinder()?.pingBinder() == true) { + mServiceWaiters.remove(latch) + return + } + + runCatching { + latch.await(timeout, TimeUnit.MILLISECONDS) + }.also { + mServiceWaiters.remove(latch) } - Shizuku.bindUserService(mUserServiceArgs, tmpConnection) - latch.await(timeout, TimeUnit.MILLISECONDS) - Shizuku.unbindUserService(mUserServiceArgs, tmpConnection, true) } } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt index 8b8c8340..f85cb06f 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt @@ -155,7 +155,13 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { override fun onStart() { super.onStart() - WrappedShizuku.bindUserServiceIfNeeded() + // @Hint by SuperMonster003 on Dec 24, 2025. + // ! Avoid binding Shizuku user service on app start. + // ! It may spawn root user-service processes repeatedly during IDE "Run" (force-stop + relaunch). + // ! zh-CN: + // ! 避免在应用启动时绑定 Shizuku user service. + // ! IDE "Run" (force-stop + relaunch) 期间可能反复拉起 root user-service 进程. + // # WrappedShizuku.bindUserServiceIfNeeded() } private fun recreateIfNeeded() { diff --git a/version.properties b/version.properties index 4aeedd78..d07d6e1e 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue Dec 23 06:37:24 CST 2025 -BUILD_TIME=1766443044399 +#Wed Dec 24 16:10:20 CST 2025 +BUILD_TIME=1766563820979 COMPILE_SDK_VERSION=36 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -27,6 +27,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=36 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3544 +VERSION_BUILD=3546 VERSION_NAME=6.7.0 Alpha12 VSCODE_EXT_REQUIRED_VERSION=1.0.8