Skip to content

feat: 使用 WorkManager 重构 ADB 开机自启流程#38

Merged
ItosEO merged 4 commits intomainfrom
feature/wireless-adb-boot-start
Apr 5, 2026
Merged

feat: 使用 WorkManager 重构 ADB 开机自启流程#38
ItosEO merged 4 commits intomainfrom
feature/wireless-adb-boot-start

Conversation

@ItosEO
Copy link
Copy Markdown
Collaborator

@ItosEO ItosEO commented Apr 4, 2026

  • 新增 AdbStartWorkerAdbStarter,通过 WorkManager 实现带重试机制的 ADB 启动逻辑
  • 新增开机启动通知栏,支持显示当前状态、手动重试及取消操作
  • 优化 BootCompleteReceiver,根据上次启动方式(Root/ADB)选择自启路径
  • 支持在开机自启过程中自动开启无线调试并等待设备解锁
  • StellarSettings 中新增 LaunchMethod 以记录上次启动方式
  • 适配 Android 13+ 的 WRITE_SECURE_SETTINGS 权限校验
  • 更新相关字符串资源及依赖配置

- 新增 `AdbStartWorker` 及 `AdbStarter`,通过 WorkManager 实现带重试机制的 ADB 启动逻辑
- 新增开机启动通知栏,支持显示当前状态、手动重试及取消操作
- 优化 `BootCompleteReceiver`,根据上次启动方式(Root/ADB)选择自启路径
- 支持在开机自启过程中自动开启无线调试并等待设备解锁
- 在 `StellarSettings` 中新增 `LaunchMethod` 以记录上次启动方式
- 适配 Android 13+ 的 `WRITE_SECURE_SETTINGS` 权限校验
- 更新相关字符串资源及依赖配置
Copilot AI review requested due to automatic review settings April 4, 2026 02:25
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 将开机自启的 ADB 启动流程重构为基于 WorkManager 的后台任务,并新增通知栏交互来展示/控制启动状态,同时用设置项记录上次启动方式以决定开机自启路径。

Changes:

  • 新增 AdbStartWorker + AdbStarter:通过 WorkManager 执行无线调试开启、端口发现、ADB 启动与 Binder 等待,并支持重试。
  • 新增开机启动通知渠道/通知动作(重试/取消),并在 Application 中初始化通知渠道。
  • 新增 StellarSettings.LaunchMethod 记录上次启动方式,BootCompleteReceiver 根据 Root/ADB 条件选择自启路径。

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
manager/src/main/res/values/strings.xml 新增开机 ADB Worker 通知相关文案(英文)
manager/src/main/res/values-zh-rCN/strings.xml 新增开机 ADB Worker 通知相关文案(简中)
manager/src/main/kotlin/roro/stellar/manager/ui/features/manager/StarterScreen.kt 启动成功后记录上次启动方式(Root/ADB)
manager/src/main/kotlin/roro/stellar/manager/StellarSettings.kt 新增 LaunchMethod 与持久化读写
manager/src/main/kotlin/roro/stellar/manager/StellarApplication.kt 启动时创建开机启动通知渠道
manager/src/main/kotlin/roro/stellar/manager/startup/worker/AdbStartWorker.kt 新增 WorkManager Worker 实现开机 ADB 自启与重试流程
manager/src/main/kotlin/roro/stellar/manager/startup/worker/AdbStarter.kt 新增 ADB 连接/启动命令执行与 Binder 轮询
manager/src/main/kotlin/roro/stellar/manager/startup/notification/BootStartNotifications.kt 新增通知渠道与前台通知构建/展示/撤销
manager/src/main/kotlin/roro/stellar/manager/startup/notification/BootStartActionReceiver.kt 新增通知动作接收器(重试/取消)
manager/src/main/kotlin/roro/stellar/manager/receiver/StellarReceiver.kt 改为直接触发 AdbStartWorker.enqueue()
manager/src/main/kotlin/roro/stellar/manager/receiver/BootCompleteReceiver.kt 开机自启逻辑改为 Root 优先,其次按上次 ADB 启动选择 WorkManager 路径
manager/src/main/AndroidManifest.xml 注册通知动作接收器
manager/manager.versions.toml 增加 WorkManager 依赖版本与坐标
manager/build.gradle 引入 androidx.work:work-runtime-ktx
.claude/settings.local.json 调整本地 Claude 工具权限配置

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +16 to +20
fun createChannel(context: Context) {
val channel = NotificationChannel(
CHANNEL_ID,
context.getString(R.string.boot_start_channel_name),
NotificationManager.IMPORTANCE_LOW
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BootStartNotifications.createChannel() unconditionally references NotificationChannel, but this app’s minSdk is 24. On API 24/25 this will crash at runtime when Application.onCreate calls it. Guard channel creation with SDK >= 26 (or make it a no-op pre-26) and build notifications with NotificationCompat on older APIs.

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +50
return Notification.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stellar)
.setContentTitle(context.getString(R.string.boot_start_notification_title))
.setContentText(message ?: context.getString(R.string.boot_start_enabling_wireless_adb))
.setOngoing(true)
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildStartingNotification() uses Notification.Builder(context, CHANNEL_ID), which requires API 26+. With minSdk 24 this can crash on API 24/25 (e.g., when enqueue() shows the initial notification). Use NotificationCompat.Builder (and only rely on channels on 26+).

Copilot uses AI. Check for mistakes.
Comment on lines 11 to 14
override fun onReceive(context: Context, intent: Intent) {
if (!ServiceStatus().isRunning) {
val scriptModeEnabled = StellarSettings.getPreferences()
.getBoolean(StellarSettings.BOOT_SCRIPT_ENABLED, false)
if (!scriptModeEnabled) {
val wirelessAdbStatus = adbWirelessHelper.validateThenEnableWirelessAdb(
context.contentResolver, context
)
if (wirelessAdbStatus) {
val intentService = Intent(context, SelfStarterService::class.java)
context.startService(intentService)
}
}
AdbStartWorker.enqueue(context)
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StellarReceiver now enqueues AdbStartWorker unconditionally when the service isn’t running. If WRITE_SECURE_SETTINGS isn’t granted / SDK isn’t supported, AdbStartWorker will currently throw and then Result.retry(), potentially causing endless retries + ongoing notifications. Add gating here (or make the worker return Result.failure on non-retryable preconditions) to avoid a retry loop.

Copilot uses AI. Check for mistakes.
Comment on lines +244 to +260
suspendCancellableCoroutine { cont ->
val observer = Observer<Int> { port ->
if (port > 0 && cont.isActive) {
cont.resume(port)
}
}
val mdns = AdbMdns(
context = applicationContext,
serviceType = AdbMdns.TLS_CONNECT,
observer = observer,
onMaxRefresh = {
if (cont.isActive) cont.resume(-1)
}
)
mdns.start()
cont.invokeOnCancellation { mdns.destroy() }
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discoverAdbPort() creates and starts an AdbMdns instance but only destroys it on coroutine cancellation. When a port is found (or onMaxRefresh resumes), the coroutine resumes without stopping/destroying the discovery, leaving NSD discovery + executor running. Ensure AdbMdns.destroy() is called on all exit paths (success, onMaxRefresh, timeout).

Copilot uses AI. Check for mistakes.
Comment on lines +142 to +154
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Log.e(TAG, "AdbStartWorker 异常", e)
// 检查是否在此期间已成功启动
if (Stellar.pingBinder()) {
BootStartNotifications.dismiss(applicationContext)
return Result.success()
}
return retryWithNotification(
applicationContext.getString(R.string.boot_start_failed, e.message ?: "")
)
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doWork() treats all exceptions as retryable. In particular, a SecurityException from enableWirelessAdb() (missing WRITE_SECURE_SETTINGS) will lead to Result.retry() and can loop indefinitely. Handle non-retryable failures (e.g., permission denied / unsupported SDK) by returning Result.failure() and dismissing/updating the notification accordingly.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,25 @@
package roro.stellar.manager.startup.notification

import android.app.NotificationManager
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import: NotificationManager is imported but never used.

Suggested change
import android.app.NotificationManager

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +17
ACTION_CANCEL -> {
AdbStartWorker.cancel(context)
BootStartNotifications.dismiss(context)
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACTION_CANCEL currently calls AdbStartWorker.cancel(context), which already dismisses the boot-start notification, and then calls BootStartNotifications.dismiss(context) again. Consider removing the redundant dismiss to keep the receiver logic minimal.

Suggested change
ACTION_CANCEL -> {
AdbStartWorker.cancel(context)
BootStartNotifications.dismiss(context)
}
ACTION_CANCEL -> AdbStartWorker.cancel(context)

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 10
{
"permissions": {
"allow": [
"mcp__fast-context__fast_context_search",
"Bash(ls:*)"
"Bash(ls:*)",
"Bash(gh api:*)",
"WebFetch(domain:api.github.com)",
"Bash(curl:*)",
"Bash(git checkout:*)"
]
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be a machine-local Claude configuration file ("settings.local.json") and the change expands allowed tool permissions. Consider removing it from version control and adding it to .gitignore, or moving shared settings to a non-local config file, to avoid accidentally changing other contributors’ local tooling permissions.

Copilot uses AI. Check for mistakes.
ItosEO added 3 commits April 5, 2026 20:14
- 新增 `StellarReceiverStarter` 统一管理 Root 和 ADB 启动逻辑。
- 重构 `BootCompleteReceiver`,移除冗余的 Root 启动实现,统一调用 `StellarReceiverStarter`。
- 优化 `AdbStartWorker`:
    - 改进无线调试启用逻辑,增加对 `adb_wifi_enabled` 状态的监听。
    - 优化设备锁屏时的等待处理,支持在解锁后自动恢复启动流程。
    - 使用 `callbackFlow` 重新实现 ADB 端口发现逻辑,提高稳定性。
    - 根据 ADB TCP 端口配置动态调整 WorkManager 约束条件。
- 在 `AdbStarter` 中增加自动切换 ADB 端口的逻辑。
- 简化 `AndroidManifest.xml` 中的 `BootCompleteReceiver` 意图过滤,仅保留 `BOOT_COMPLETED`。
- 在 `StellarReceiver` 和 `BootStartActionReceiver` 中引入协程与 `goAsync()`,将启动逻辑移至 IO 线程以避免阻塞主线程。
- 优化 `StellarReceiverStarter` 的启动策略:
    - Root 启动失败时自动回退至 ADB 启动。
    - 针对未知启动方式增加兼容性回退路径。
- 改进 `rootStart` 和 `adbStart` 的返回值处理,以便更好地处理链式启动逻辑。
- 在 `BootStartActionReceiver` 中将重试操作由 `AdbStartWorker` 改为调用 `StellarReceiverStarter`。
- 在 `BootStartNotifications` 中增加 Android O 版本检查,防止低版本崩溃。
- 将 `Notification.Builder` 替换为 `NotificationCompat.Builder` 以提升兼容性。
- 简化通知操作按钮(Action)的构建方式。
- 更新 `.claude/settings.local.json`,移除多余的 Bash 和 WebFetch 权限。
@ItosEO ItosEO merged commit d2bdb25 into main Apr 5, 2026
1 check passed
@ItosEO ItosEO deleted the feature/wireless-adb-boot-start branch April 5, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants