From 3808dd7fdc3112bdb5a15d1cbc6700e9701ecfc4 Mon Sep 17 00:00:00 2001 From: "Creater. Bai" <1302064396@qq.com> Date: Sat, 3 Oct 2026 18:58:42 +0800 Subject: [PATCH 1/3] refactor(execution): Improve shell executable gateway testability Move the local shell resolver beside the other gateway helpers and document its Shizuku-specific behavior.\nExpose the resolver so unit tests can verify the selected shell executable. --- .../gateway/PluginExecutionGatewayImpl.kt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt index e88d1763..a3979740 100644 --- a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt +++ b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt @@ -22,14 +22,6 @@ class PluginExecutionGatewayImpl @Inject constructor( private val pluginProcessMonitor: PluginProcessMonitor ) { - internal fun resolveLocalShellExecutable(): String{ - val shell = Shell.getShell() - return if (shell.isRoot){ - "su" - }else{ - "sh" - } - } fun executePluginEntryPoint( pluginEntryPoint: String, pluginPackageDirectory: String, @@ -148,4 +140,18 @@ class PluginExecutionGatewayImpl @Inject constructor( } } + /** + * Shizuku 是例外,因为普通 process 无法直接调用 + * + *需要通过 Binder, 所以判断也没有意义,这里不做判断 + */ + fun resolveLocalShellExecutable(): String{ + val shell = Shell.getShell() + return if (shell.isRoot){ + "su" + }else{ + "sh" + } + } + } From 7eb07e1df7c2fa9d7cbd1ff63ed146338b0ed924 Mon Sep 17 00:00:00 2001 From: "Creater. Bai" <1302064396@qq.com> Date: Sat, 3 Oct 2026 18:59:39 +0800 Subject: [PATCH 2/3] refactor(execution): Extract plugin command construction Extract plugin command construction from the entry point execution flow.\nAdd complete KDoc and keep process setup focused on execution for better unit testing. --- .../gateway/PluginExecutionGatewayImpl.kt | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt index a3979740..53990b97 100644 --- a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt +++ b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt @@ -27,10 +27,16 @@ class PluginExecutionGatewayImpl @Inject constructor( pluginPackageDirectory: String, shouldMonitor: Boolean = false ): Flow = callbackFlow { - val processBuilder = ProcessBuilder( - resolveLocalShellExecutable(), "-c", "cd $pluginPackageDirectory ;echo PID:$$;exec $pluginEntryPoint" + + // Prepare Commands + val command = commandFactory( + shellExecutable = resolveLocalShellExecutable(), + pluginEntryPoint = pluginEntryPoint, + pluginPackageDirectory = pluginPackageDirectory ) + val processBuilder = ProcessBuilder(command) + // Prepare Environments val environment = processBuilder.environment() val oldPath = environment["PATH"].orEmpty() @@ -47,8 +53,9 @@ class PluginExecutionGatewayImpl @Inject constructor( Log.d("executePluginEntryPoint","environmentPath: $environmentPath") Log.d("executePluginEntryPoint","environmentLdPath: $environmentLdPath") + // Start Process and + // register monitor val process = processBuilder.start() - if (shouldMonitor){ pluginProcessMonitor(process) } @@ -78,8 +85,8 @@ class PluginExecutionGatewayImpl @Inject constructor( awaitClose { } - } - .flowOn(Dispatchers.IO) + + }.flowOn(Dispatchers.IO) fun executePluginWithoutEnvironmentByShizuku( pluginDirectory: String, @@ -154,4 +161,40 @@ class PluginExecutionGatewayImpl @Inject constructor( } } + /** + * 构造供 [ProcessBuilder] 使用的命令参数列表。 + * + * 该方法只负责根据传入的 Shell、插件入口点以及插件目录组装命令, + * 不负责启动进程或配置运行环境。 + * + * 最终返回的参数列表通常形如:`sh -c cd ; echo PID:$$ ; exec ` + * + * @param shellExecutable 用于执行命令的 Shell 可执行文件,例如 `sh` 或 `su`。 + * @param pluginEntryPoint 插件的可执行入口点。 + * @param pluginPackageDirectory 插件所在目录,同时作为执行时的工作目录。 + * @return 可直接传递给 [ProcessBuilder] 的命令参数列表。 + * + * @since 2026-10-03 + * @lastModified 2026-10-03 + */ + fun commandFactory( + shellExecutable: String, + pluginEntryPoint: String, + pluginPackageDirectory: String, + ): List { + + val commandList = mutableListOf() + + commandList += shellExecutable + commandList += "-c" + commandList += listOf( + "cd $pluginPackageDirectory", + "echo PID:$$", + "exec $pluginEntryPoint" + ).joinToString(" ; ") + + return commandList + + } + } From 711f29e8cdf0b9c14453cd4bf5687780c5e737ed Mon Sep 17 00:00:00 2001 From: "Creater. Bai" <1302064396@qq.com> Date: Sat, 3 Oct 2026 18:59:49 +0800 Subject: [PATCH 3/3] refactor(execution): Rename the Shizuku plugin execution method Rename the gateway method to match its actual execution path.\nUpdate the Shizuku use case and its dispatch comment to use the new method name. --- .../application/execute/ExecutePluginByShizukuUseCase.kt | 4 ++-- .../data/execution/gateway/PluginExecutionGatewayImpl.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/kotlin/com/baidaidai/rootless_store/application/execute/ExecutePluginByShizukuUseCase.kt b/application/src/main/kotlin/com/baidaidai/rootless_store/application/execute/ExecutePluginByShizukuUseCase.kt index ed148e21..7b9af21b 100644 --- a/application/src/main/kotlin/com/baidaidai/rootless_store/application/execute/ExecutePluginByShizukuUseCase.kt +++ b/application/src/main/kotlin/com/baidaidai/rootless_store/application/execute/ExecutePluginByShizukuUseCase.kt @@ -26,9 +26,9 @@ class ExecutePluginByShizukuUseCase @Inject constructor( val pluginManifest = pluginRepositoryImpl.findPlugin(pluginId)!! val shouldMonitor = settingPreferencesRepositoryImpl.observePluginStatusNotificationEnabled().first() - // Dispatch to PluginExecutionGateway.executePluginWithoutEnvironmentByShizuku + // Dispatch to PluginExecutionGateway.executePluginByShizuku var pidSaved = false - val pluginExecutionResult = pluginExecutionGatewayImpl.executePluginWithoutEnvironmentByShizuku( + val pluginExecutionResult = pluginExecutionGatewayImpl.executePluginByShizuku( pluginEntryPoint = pluginManifest.entryPoint, pluginDirectory = pluginManifest.pluginPackageName, shouldMonitor = shouldMonitor diff --git a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt index 53990b97..dbccdb67 100644 --- a/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt +++ b/data/src/main/kotlin/com/baidaidai/rootless_store/data/execution/gateway/PluginExecutionGatewayImpl.kt @@ -88,7 +88,7 @@ class PluginExecutionGatewayImpl @Inject constructor( }.flowOn(Dispatchers.IO) - fun executePluginWithoutEnvironmentByShizuku( + fun executePluginByShizuku( pluginDirectory: String, pluginEntryPoint: String, shouldMonitor: Boolean