Repository navigation
Feat/independent task && foreground service - #1433
Conversation
|
我收到你的邮件啦,我会尽快回复的哦,谢谢
Only efforts can prove that I existed in this world ---jarlen
|
|
感谢贡献代码!麻烦先修复一下CI不通过的问题。其实也可以在你fork的仓库跑相同的CI的。目前看是代码格式化的问题。CI里用的android studio版本很低了,不知道是不是跟你用的比较新的ide自动格式化的效果不一致。如果是这样,也可以帮忙升级下CI里的配置。 |
There was a problem hiding this comment.
🟡 Changes recommended
Manifest generation, container ownership, service lifecycle, and concurrency defects remain unresolved.
13 open findings
Release shared lease only after the last Activity instance finishes · New Defer teardown when stopSelf is called during creation · New Translate named launch modes to numeric manifest values · New Atomically validate startId before stopping the service · New Prevent loader delegate overwrites and cross-loader shutdowns · New Mark every service start and clear stale stop markers · New Track queued starts before applying pending stop requests · New Serialize foreground callbacks with service lifecycle operations · New Resolve FOREGROUND_SERVICE_TYPE_MANIFEST before aggregating types · New Clean up replaced secondary foreground notification IDs · New Preserve explicitly empty application taskAffinity values · New Add host permissions required for microphone and screen sharing · New Declare all foreground service types used by plugin tests · New
What changed in this PR
Adds independent-task Activity allocation and shared foreground-service containers to Shadow’s plugin runtime.
Changes:
- Adds container pools, Activity leases, and foreground-service lifecycle management.
- Extends manifest metadata for task affinity, launch modes, permissions, and service types.
- Adds host configuration, manual scenarios, and five automated tests; updates formatting tooling.
| File | Description |
|---|---|
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/task/TestIndependentTaskActivity.java | Automated task lifecycle fixture. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/task/IndependentTaskTestActivity.java | Manual independent-task scenario. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/ThirdPartyForegroundServiceTestActivity.java | Manual multi-service scenarios. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/TestForegroundServiceB.java | Second automated service fixture. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/TestForegroundServiceActivity.java | Service controls and observable state. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/TestForegroundServiceA.java | First automated service fixture. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/MockThirdForegroundService.java | Third shared-container mock. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/MockScreenShareService.java | Media-projection service mock. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/MockMicrophoneService.java | Microphone service mock. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/MockFourthForegroundService.java | Fourth shared-container mock. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/java/com/tencent/shadow/test/plugin/general_cases/lib/usecases/service/BaseTestForegroundService.java | Shared notification and lifecycle fixture. |
| projects/test/plugin/general-cases/test-plugin-general-cases/src/main/AndroidManifest.xml | Registers test components and permissions. |
| projects/test/dynamic/plugin/test-dynamic-runtime/src/main/java/com/tencent/shadow/test/dynamic/runtime/container/PluginIndependentTask2ProxyActivity.java | Second independent-task container. |
| projects/test/dynamic/plugin/test-dynamic-runtime/src/main/java/com/tencent/shadow/test/dynamic/runtime/container/PluginIndependentTask1ProxyActivity.java | First independent-task container. |
| projects/test/dynamic/plugin/test-dynamic-loader/src/main/java/com/tencent/shadow/test/dynamic/loader/TestComponentManager.java | Supplies test container pools. |
| projects/test/dynamic/host/test-dynamic-host/src/main/AndroidManifest.xml | Registers host containers. |
| projects/test/dynamic/host/test-dynamic-host/src/androidTest/java/com/tencent/shadow/test/cases/plugin_main/PluginForegroundServiceTest.java | Three service lifecycle tests. |
| projects/test/dynamic/host/test-dynamic-host/src/androidTest/java/com/tencent/shadow/test/cases/plugin_main/IndependentTaskTest.java | Two independent-task tests. |
| projects/test/dynamic/host/test-dynamic-host/src/androidTest/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtension.java | Formatting only. |
| projects/sdk/dynamic/dynamic-loader-impl/src/main/kotlin/com/tencent/shadow/dynamic/loader/impl/PluginLoaderBinder.kt | Formatting only. |
| projects/sdk/dynamic/dynamic-apk/src/main/java/com/tencent/shadow/dynamic/apk/ApkClassLoader.java | Formatting only. |
| projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/SimpleRenameTransformTest.kt | Formatting only. |
| projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransformTest.kt | Formatting only. |
| projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowService.java | Delegates foreground operations and tracks start IDs. |
| projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowContext.java | Routes foreground-service starts. |
| projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/PluginManifest.java | Extends component metadata. |
| projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/HostServiceDelegator.java | Defines foreground-operation delegation. |
| projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/PluginManifestGenerator.kt | Generates new manifest metadata. |
| projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestReader.kt | Reads new attributes and permissions. |
| projects/sdk/core/manifest-parser/src/main/kotlin/com/tencent/shadow/core/manifest_parser/AndroidManifestKeys.kt | Defines new manifest keys. |
| projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/ShadowPluginLoader.kt | Registers service delegates. |
| projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/PluginServiceManager.kt | Manages shared service lifecycles and notifications. |
| projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/managers/ComponentManager.kt | Allocates containers and tracks leases and pending stops. |
| projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/infos/ContainerActivityInfo.kt | Describes Activity container capabilities. |
| projects/sdk/core/loader/src/main/kotlin/com/tencent/shadow/core/loader/delegates/ShadowActivityDelegate.kt | Checks and releases Activity leases. |
| projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/ShadowPlugin.kt | Formatting only. |
| projects/sdk/core/gradle-plugin/src/main/kotlin/com/tencent/shadow/core/gradle/extensions/PackagePluginExtension.kt | Formatting only. |
| projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerServiceDelegateHolder.java | Stores delegates by loader key. |
| projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerServiceDelegate.java | Defines container lifecycle callbacks. |
| projects/sdk/core/common/src/main/java/com/tencent/shadow/core/runtime/container/PluginContainerService.java | Adds the Android service container. |
| projects/sdk/core/common/build.gradle | Adds build-version metadata dependency. |
| projects/sdk/coding/code-generator/src/main/kotlin/com/tencent/shadow/coding/code_generator/ActivityCodeGenerator.kt | Formatting only. |
| .github/workflows/check-build-test.yml | Updates Android Studio formatter download. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (releaseLease) { | ||
| mComponentManager.releaseContainerActivity( | ||
| mPluginActivityComponent, | ||
| ComponentName(hostActivity.packageName, hostActivity.javaClass.name), | ||
| mActivityLeaseId |
| ) | ||
| mAliveServicesMap[componentName] = service | ||
| mServiceStartByStartServiceSet.add(componentName) | ||
| service.onCreate() |
| val launchModeLiteral = makeResIdLiteral(AndroidManifestKeys.launchMode) { | ||
| it | ||
| } |
| if (startId != mLastStartId) { | ||
| return false; | ||
| } | ||
| stopSelf(); |
| stopSelfResult(startId); | ||
| return START_NOT_STICKY; | ||
| } | ||
| mDelegate = PluginContainerServiceDelegateHolder.getDelegate(delegateProviderKey); |
| updatePluginForeground( | ||
| pluginComponent, container, id, notification, foregroundServiceType | ||
| ) |
| mForegroundServiceRecords[pluginComponent] = ForegroundServiceRecord( | ||
| id, notification, foregroundServiceType | ||
| ) |
| AndroidManifestKeys.name, | ||
| AndroidManifestKeys.theme, | ||
| AndroidManifestKeys.appComponentFactory, | ||
| AndroidManifestKeys.taskAffinity, |
| <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||
| <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> |
| <service | ||
| android:name="com.tencent.shadow.core.runtime.container.PluginContainerService" | ||
| android:exported="false" | ||
| android:foregroundServiceType="dataSync" /> |
|
我已经算是看懂这个PR的全部内容了。非常高质量的一个PR。有多个自动化测试用例验证了新功能。我重点关注了对旧代码的改动影响,可以看到旧逻辑切换到新逻辑的代码分支很少,如果新代码有bug应该是比较容易回退和定位问题的。对其他不需要这个新feature的用户用户来说影响应该是可控的。 在理解了那个CR中留言的新增依赖的问题后应该就可以合入了。 我会把这些提交rebase成一个提交合入。你也可以自己做一下,写下你觉得更合适的提交记录。另外请仔细检查commit的author设置和github账号一致,以便github能正确统计到你的贡献记录。 再次点赞👍 |
|
忘说了,copilot的CR仅供参考,不用理会。 |
插件Activity声明非standard的launchMode或非默认taskAffinity时,原有容器映射无法让其 运行在独立任务栈中;插件前台Service也缺少由宿主真实Service承载的通道。 独立任务栈: - manifest-parser解析并生成插件Activity的launchMode、taskAffinity - ComponentManager新增getContainerActivityPool()/getContainerActivityProfile(), 由框架按launchMode、profile和taskAffinity分组分配、复用和回收宿主容器Activity - 容器在插件Activity首次启动时获得租约,finish销毁后释放;每次分配生成新租约ID, 拒绝旧任务栈迟到的onNewIntent 前台Service: - manifest-parser解析插件Service的foregroundServiceType - 新增宿主侧容器PluginContainerService及委托通道,ComponentManager新增 getContainerServicePool()/onBindContainerService() - 多个插件Service可共享同一容器,分别转发生命周期、startForeground、stopForeground 和停止请求;全部插件Service停止后容器才停止 - 容器onStartCommand回调前收到的stop请求延迟到插件onStartCommand返回后执行, 避免startForegroundService超时 兼容性: - 宿主未提供容器池时保持原有行为 - 保留旧版Manifest生成代码所需的兼容构造方法 测试: - 测试宿主接入独立任务栈容器池和PluginContainerService - 新增IndependentTaskTest、PluginForegroundServiceTest自动化用例 - 测试插件增加第三方SDK前台Service和独立任务栈的手动验证页面 CI: - 代码格式化检查使用的Android Studio从2021.1.1升级到2026.1.1 Patch 2, 新旧版本格式化规则不一致;同时按新版规则重新格式化受影响的已有代码
c64f98e to
ef52996
Compare
|
@shifujun 非常感谢细致的 review 和认可! 已按建议处理:
如果还有需要调整的地方,随时告诉我。再次感谢! |
shifujun
left a comment
There was a problem hiding this comment.
目前看不出什么问题了。我设了个周一上午的提醒会直接合入。留两天时间以防想起什么问题。


背景:插件 Activity 需要按 launchMode 和 taskAffinity 运行在独立 Task 中;插件需要能托管前台 Service(包括 foregroundServiceType,以及多个 Service 共享同一个宿主容器)。
设计:宿主通过 ComponentManager 的 getContainerActivityPool() 和 getContainerActivityProfile() 提供独立 Task 容器池,框架负责分配和回收,并用租约 ID 防止旧 Task 迟到的 onNewIntent 被转发给新的插件 Activity。
前台 Service 由宿主注册的 PluginContainerService 承载,通过 getContainerServicePool() 或 onBindContainerService() 指定容器。
兼容性:不实现这两个容器池方法时,行为和现在完全一样;保留了旧版 Manifest 生成代码用的兼容构造方法。
宿主接入:需要在宿主 Manifest 里注册容器 Activity(声明 launchMode 和 taskAffinity),以及 PluginContainerService 及其 foregroundServiceType。具体写法可以参考测试宿主 test-dynamic-host 的配置。
测试:新增 5 个自动化用例;testSdk 在 API 36 上通过,185 个用例 0 失败,跳过 3 个;目前只在 API 36 上测过,API 28 和 API 19 还没测。