Skip to content

Commit 381ff84

Browse files
author
Donglu
committed
docs(blog): add HarmonyOS multiprocess socket architecture
1 parent 657e61c commit 381ff84

1 file changed

Lines changed: 211 additions & 0 deletions

File tree

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
layout: post
3+
title: "HarmonyOS 多进程共享 Socket:基于 AppService 与 LocalSocket 的应用层方案"
4+
date: 2026-08-04 20:05:11 +0800
5+
categories: [HarmonyOS, 架构]
6+
tags: [HarmonyOS, ArkTS, 多进程, LocalSocket, AppServiceExtensionAbility]
7+
---
8+
9+
在 HarmonyOS 应用中,主 `UIAbility`、`AgentExtensionAbility` 和后台服务可以运行在不同进程。如果主进程与 Agent 进程都直接初始化网络 SDK,即使使用同一个单例类,也会分别创建 Socket。进程拥有独立的 ArkTS 运行时、静态变量和 Native 库实例,单例的有效范围只覆盖当前进程。
10+
11+
对于「三个进程共用一条长连接」的需求,可以采用一套应用层方案:由独立的 `AppServiceExtensionAbility` 进程担任 Broker,统一持有网络 SDK 和 TCP 连接;主进程与 Agent 进程通过 `LocalSocket` 访问 Broker;调用侧再增加一层 Gateway,保持原有业务接口基本稳定。
12+
13+
这套结构适合复用既有网络 SDK,同时把连接、登录、重连和推送集中到一个进程管理。它也受到 HarmonyOS 组件启动权限和进程生命周期的约束,需要在设计阶段明确 Broker 的启动方式与不可用时的处理策略。
14+
15+
## 适用场景
16+
17+
典型应用包含两个业务入口:
18+
19+
- 主 `UIAbility` 承载完整业务,并使用用户登录态;
20+
- `AgentExtensionAbility` 在独立进程中提供轻量查询能力;
21+
- 两个入口可能同时存活,都需要访问同一套长连接协议;
22+
- 现有网络 SDK 已经稳定,希望通过外层适配完成多进程接入。
23+
24+
如果两个进程各自调用网络 SDK,运行结构如下:
25+
26+
```mermaid
27+
flowchart LR
28+
M["主 UIAbility 进程"] --> S1["业务 Socket 单例"]
29+
A["AgentExtensionAbility 进程"] --> S2["业务 Socket 单例"]
30+
S1 --> N1["TCP 连接 1"]
31+
S2 --> N2["TCP 连接 2"]
32+
```
33+
34+
这里的两个单例都符合各自进程内的约束。由于地址空间互相隔离,Native 网络库会初始化两次,服务端也会识别出两个独立客户端。
35+
36+
## 三进程方案
37+
38+
连接所有权可以集中到独立的 AppService Broker 进程:
39+
40+
```mermaid
41+
flowchart LR
42+
M["主进程<br/>RemoteSocketGateway"] --> L["LocalSocket"]
43+
A["Agent 进程<br/>RemoteSocketGateway"] --> L
44+
L --> B["AppService Broker 进程<br/>LocalSocketGateway"]
45+
B --> C["原业务 Socket SDK"]
46+
C --> S["唯一 TCP 连接"]
47+
```
48+
49+
三个进程的职责可以划分为:
50+
51+
| 进程 | 组件 | 职责 |
52+
| --- | --- | --- |
53+
| 主进程 | `RemoteSocketGateway` | 启动或连接 Broker,发送业务请求,接收响应与推送 |
54+
| Agent 进程 | `RemoteSocketGateway` | 连接已运行的 Broker,访问允许开放的业务方法 |
55+
| AppService Broker 进程 | `LocalSocketGateway` | 初始化网络 SDK,维护唯一 TCP 连接、登录态、重连和订阅 |
56+
57+
原网络 SDK 无需感知多进程。它继续在 Broker 内按原方式工作,只需确保主进程和 Agent 进程不再直接执行 SDK 初始化。
58+
59+
调用侧统一依赖 `SocketGateway`。进程内实现与远程实现遵循同一接口,业务代码无需关心请求最终由本地 SDK 处理,还是经由 `LocalSocket` 转发。
60+
61+
```typescript
62+
interface SocketGateway {
63+
sendMessageForResult(
64+
service: number,
65+
method: number,
66+
body: Uint8Array | null,
67+
timeout?: number
68+
): Promise<RootMessage>
69+
70+
isConnected(): Promise<boolean>
71+
isLoggedIn(): Promise<boolean>
72+
autoLogin(): Promise<void>
73+
addPushListener(listener: PushListener): string
74+
removePushListener(listenerId: string): void
75+
}
76+
```
77+
78+
Broker 使用 `LocalSocketGateway` 直接调用网络 SDK。其他进程使用 `RemoteSocketGateway`,将请求编码后发送给 `LocalSocketServer`。所有网络入口都经过 Gateway,才能持续满足单连接约束。
79+
80+
## 组件与进程约束
81+
82+
### Agent 与主 UIAbility 的启动关系
83+
84+
系统调用 `AgentExtensionAbility` 时,会启动对应的扩展组件进程。这个动作不会自动创建主 `UIAbility`。
85+
86+
如果 Agent 连接主进程监听的 `LocalSocket`,而主进程尚未运行,连接会直接失败。`LocalSocket` 地址只用于进程间通信,系统不会根据该地址查找并启动某个 `UIAbility`。
87+
88+
### Context 能力范围
89+
90+
`UIAbilityContext` 提供启动和连接 `AppServiceExtensionAbility` 的接口。`AgentExtensionContext` 继承自更基础的 `ExtensionContext`,当前公开 API 没有提供等价的 AppService 连接能力,也不适合通过类型强制转换复用 UIAbility 的调用代码。
91+
92+
因此,标准 AbilityKit 启动入口位于主进程:
93+
94+
```text
95+
UIAbility ---- connectAppServiceExtensionAbility() ----> AppService
96+
AgentExtensionAbility ---- LocalSocket ----> 已运行的 AppService
97+
```
98+
99+
Agent 可以通过 `LocalSocket` 访问已经运行的 Broker。Broker 尚未运行时,这次连接无法承担启动职责。
100+
101+
### 子进程创建限制
102+
103+
HarmonyOS 提供 ArkTS 和 Native 子进程能力,官方开发指南要求由主进程创建子进程。这类能力适合隔离计算或 Native 工作,无法覆盖「主进程尚未运行时,由 Agent 创建公共 Broker」的需求。
104+
105+
主进程提前创建子进程时,还需要单独验证父进程退出后的生命周期。对需要独立承载长期连接的组件,AppService 的能力边界更加清晰。
106+
107+
### AppService 生命周期
108+
109+
`AppServiceExtensionAbility` 可以在主 `UIAbility` 退出后继续运行,系统仍可能挂起或回收对应进程。设备重启、应用被强制停止或 Broker 被回收后,Agent 无法自行恢复 Broker。
110+
111+
因此,这套三进程方案提供的是「多个应用进程同时存活时,共用一条连接」。Agent 的全时可用性需要结合产品要求设计单独的降级或恢复机制。
112+
113+
## IPC 数据边界
114+
115+
网络封装中常见的泛型解析接口通常包含进程内函数:
116+
117+
```typescript
118+
sendMessageForBodyResult<T>(
119+
service: number,
120+
method: number,
121+
body: Uint8Array,
122+
parser: (bytes: Uint8Array) => T
123+
): Promise<T>
124+
```
125+
126+
其中的 `parser` 无法跨进程传输。Broker 可以返回原始响应字节,由客户端进程执行 `fromBinary()`,这样既能保持 IPC 协议稳定,也能继续复用现有解析代码。
127+
128+
本地 IPC 协议只承载可序列化数据:
129+
130+
```text
131+
version | type | requestId | service | method | timeout | bodyLength | body
132+
```
133+
134+
协议至少覆盖请求、响应、错误、连接状态、登录状态、订阅和推送。`requestId` 用于匹配并发请求;每一帧都携带 `bodyLength`,用于处理 `LocalSocket` 数据流中的拆包和粘包。
135+
136+
Broker 负责以下工作:
137+
138+
- 维护请求 ID 与等待中的 Promise;
139+
- 客户端断开时清理未完成请求和订阅;
140+
- 统一处理登录、退出、网络切换与自动重连;
141+
- 把推送广播给已订阅的进程;
142+
- 限制 Agent 可调用的业务协议,控制共享登录态后的权限范围。
143+
144+
## 登录态设计
145+
146+
主进程可能使用用户账号,Agent 原先则使用游客账号。一条物理连接通常只能维持一种登录身份,除非服务端协议明确支持单连接多会话。
147+
148+
一种直接的处理方式是由 Broker 维护当前应用登录态:本地存在有效用户状态时使用用户会话,其余情况使用游客会话。Agent 共享当前连接,同时只能访问公开数据对应的方法集合。
149+
150+
登录密码无需通过 `LocalSocket` 在多个进程之间传递。Broker 可以读取同一应用沙箱内的持久化用户状态并执行 `autoLogin()`,主进程只发送「重新登录」或「退出」命令。
151+
152+
## Broker 生命周期与降级策略
153+
154+
Broker 的运行状态决定了两个调用端的可用性:
155+
156+
```mermaid
157+
stateDiagram-v2
158+
[*] --> BrokerAbsent
159+
BrokerAbsent --> BrokerReady: 主进程启动 AppService
160+
BrokerReady --> BrokerReady: 主进程或 Agent 请求
161+
BrokerReady --> BrokerAbsent: 系统回收、强制停止或重启
162+
BrokerAbsent --> ControlledFailure: Agent 先被调用
163+
```
164+
165+
若应用要求始终保持最多一条 Socket,Agent 在 Broker 缺席时应返回明确的不可用结果。主进程启动 Broker 后,Agent 再通过 `LocalSocket` 重试。这样可以避免 Agent 临时创建连接后,主进程又建立第二条连接。
166+
167+
若产品要求 Agent 在主应用从未启动时仍可用,则需要扩展设计,例如允许 Agent 建立游客连接并实现连接所有权交接,或引入具备更高进程管理权限的系统级能力。此类方案会增加状态迁移、并发连接和权限管理成本,应作为另一种产品约束单独评估。
168+
169+
## 实施顺序
170+
171+
建议先建立最小平台原型,确认组件与进程行为,再迁移业务网络调用。原型需要验证以下事实:
172+
173+
1. 主 `UIAbility` 能启动 AppService Broker;
174+
2. 主进程和 Agent 都能连接同一个 `LocalSocket` 地址;
175+
3. 关闭主界面后,Broker 在目标设备上仍能处理请求;
176+
4. Broker 被终止后,主进程能够重新启动它;
177+
5. 主进程尚未运行时,Agent 能收到可识别的连接失败;
178+
6. 进程列表中存在三个 PID,服务端方向只有一条 TCP 连接。
179+
180+
平台行为验证通过后,可以按以下顺序迁移:
181+
182+
1. 将网络 SDK 初始化和连接管理迁入 Broker;
183+
2. 建立请求、响应与错误帧,接通一个只读接口;
184+
3. 增加登录状态、超时与重连处理;
185+
4. 增加订阅、推送广播与客户端退出清理;
186+
5. 将主进程和 Agent 的旧调用逐步切换到 `SocketGateway`;
187+
6. 在目标设备上核对进程、连接数量和生命周期行为。
188+
189+
对于需要兼容旧系统版本的应用,Gateway 可以按系统能力选择进程内实现或远程实现,业务接口保持一致。
190+
191+
## 设计检查清单
192+
193+
方案评审时可以逐项确认:
194+
195+
- 唯一连接所有者及其进程已经明确;
196+
- 其他进程已经移除直接初始化网络 SDK 的入口;
197+
- Broker 的启动方具备所需的 Context API;
198+
- Broker 被系统回收后的恢复责任已经确定;
199+
- 主进程未运行时,Agent 的失败、降级或临时连接策略已经确定;
200+
- 登录态共享规则与 Agent 方法权限已经确定;
201+
- 推送、超时、并发请求和客户端退出都有对应处理;
202+
- 设备侧可以验证三个 PID 和唯一目标 TCP 连接。
203+
204+
这套方案把 Socket 的创建与生命周期集中到 Broker,并通过 Gateway 保持业务调用方式稳定。完成平台原型后再迁移业务接口,可以尽早确认 AppService 启动权限、进程回收和 Agent 降级行为,避免在大范围改造后才暴露平台边界。
205+
206+
## 参考资料
207+
208+
- [AgentExtensionAbility 组件](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/agent-extension-ability)
209+
- [使用 AppServiceExtensionAbility 实现后台服务](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-service-extension-ability)
210+
- [Native 子进程开发指南](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/capi-nativechildprocess-development-guideline)
211+
- [Socket API 参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-socket)

0 commit comments

Comments
 (0)