文档概述
说明:
1.文章由移远通信技术股份有限公司提供
2.以下内容包含了个人理解,仅供参考,如有不合理处,请联系笔者修改

概述

OpenHarmony 的短信能力由 Telephony 子系统提供,是标准系统的基础通信能力之一,核心功能与相关说明如下:
1.
‌核心系统能力‌
支持短信/彩信(暂不支持,需要自行适配)收发、SIM 卡短信管理、短信服务中心地址配置、默认 SIM 卡槽设置等基础能力,配套提供了系统级 API 供开发者调用。
2.
‌应用侧开发能力‌
系统预置短信应用已实现会话管理、消息收发、送达报告、短信备份、垃圾短信拦截等完整功能,可通过一套代码适配手机、平板等多类设备。
普通三方应用可通过 startAbility 接口拉起系统短信页面,预填收件人与短信内容完成发送,无需申请高权限系统短信 API。
Flutter 生态已完成 flutter_sms 库适配,支持短信对话框唤起、多收件人发送、设备短信能力检测等跨平台功能。

在这里插入图片描述

架构设计

分层模型

短信发送模块采用四层架构,自上而下分别为:

在这里插入图片描述

设计原则

单一职责原则:每个模块专注特定功能领域

  • SmsSendManager:发送调度与生命周期管理
  • GsmSmsSender/CdmaSmsSender:制式特定的编码与通信
  • SmsNetworkPolicyManager:网络路由与优先级决策

策略模式应用:网络制式差异通过策略对象动态封装

  • 运行时选择对应的Sender实例
  • 同一接口下适配多个网络标准

异步处理模式:所有发送操作均为异步非阻塞的事件驱动

  • 发送请求入队后立即返回
  • 通过回调机制通知应用层结果

核心组件详解

SmsInterfaceManager(接口管理器)

职责范围

  • 对外提供统一的短信发送接口(TextBasedSmsDeliveryDataBasedSmsDelivery
  • 管理每个 SIM 卡槽的资源生命周期
  • 请求的初步验证与权限检查

核心方法

int32_t TextBasedSmsDelivery(
    const std::string &desAddr,              // 目标地址
    const std::string &scAddr,               // 短信服务中心地址
    const std::string &text,                 // 短信文本内容
    const sptr<ISendShortMessageCallback> &sendCallback,      // 发送结果回调
    const sptr<IDeliveryShortMessageCallback> &deliveryCallback, // 送达报告回调
    int32_t id,                              // 业务标识符
    bool isMmsApp = true);                   // 是否为彩信应用

关键特性

  • 接收来自应用程序的短信发送请求
  • 将请求转发给对应 SIM 卡槽的 SmsSendManager
  • 与数据持久化层交互,记录发送历史

SmsSendManager(发送管理器)

核心职责

  • 维护 GSM 和 CDMA 两种网络制式的发送器实例
  • 根据当前网络状态选择合适的发送路径
  • 实现发送队列与重试机制
  • 协调网络策略管理器的决策执行

内部成员

class SmsSendManager {
private:
    int32_t slotId_;                              // SIM卡槽ID
    std::shared_ptr<SmsSender> gsmSmsSender_;     // GSM 发送器
    std::shared_ptr<SmsSender> cdmaSmsSender_;    // CDMA 发送器
    std::shared_ptr<SmsNetworkPolicyManager> networkManager_;  // 网络策略管理
    std::shared_ptr<SmsShortCodeMatcher> smsShortCodeMatcher_;// 短码匹配器
};

发送流程分类

方法 场景 特点
TextBasedSmsDelivery 文本短信 支持自动分段,长短信打包发送
DataBasedSmsDelivery 数据短信 指定端口号,用于数据应用通信
RetriedSmsDelivery 重试短信 发送失败后的自动重试机制

SmsSender(发送器基类)

设计特点:采用模板方法模式的抽象基类

class SmsSender : public TelEventHandler {
public:
    // 纯虚方法 - 子类必须实现
    virtual void TextBasedSmsDelivery(...) = 0;
    virtual void DataBasedSmsDelivery(...) = 0;
    virtual void SendSmsToRil(...) = 0;
    
    // 通用方法 - 所有Sender共享
    void HandleMessageResponse(const std::shared_ptr<SmsSendIndexer> &smsIndexer);
    static void SendResultCallBack(...);
};

职责分离

  • 基类定义通用流程:请求排队、结果回调与重试调度
  • 子类实现制式特定功能:PDU 编码、发送格式与参数配置

GsmSmsSender 与 CdmaSmsSender

两个子类基于相同的基类框架,处理 GSM/CDMA 的特定编码与协议细节。

GSM 短信特点

  • 使用 7-bit GSM 编码或 UCS2 编码
  • PDU 格式定义明确,严格按照 3GPP 规范
  • 支持长短信的分段与连接标识头(Concatenation Header)
  • 服务中心号码在PDU中显式指定

CDMA短信特点

  • 使用8-bit编码
  • 消息参数采用TLV(Type-Length-Value)格式
  • 多数参数可选,需要区分实际值与默认值
  • 时间戳、优先级等参数独立传递

SmsNetworkPolicyManager(网络策略管理器)

职责定位:根据当前网络状态,决定短信应通过哪条网络路径传输。

核心决策逻辑

输入条件检查:
├─ 网络注册状态(已注册/未注册)
├─ 域服务类型(CS域/IMS域)
├─ 信号强度与连接质量
├─ 用户配置的偏好设置
└─ 制式兼容性(设备是否支持该制式)

决策流程:
1. 优先级评估
   - IMS短信可用 → 选择IMS路径
   - CS 域可用 → 选择对应制式(GSM/CDMA)
   - 都不可用 → 等待网络或返回错误

2. 队列管理
   - 维护待发送队列
   - 监听网络状态变化
   - 状态好转时重新尝试发送

参数决策表

场景 网络状态 决策
仅CS可用 GSM 注册 使用GSM通道
仅CS可用 CDMA 注册 使用CDMA通道
CS 与 IMS 均可用 两者状态均良好 IMS优先
都不可用 离线或无信号 加入等待队列,待网络恢复后重试

短信发送流程

完整发送链路

应用层请求
    │
    ▼
SmsInterfaceManager::TextBasedSmsDelivery()
    │ 权限检查 ▶ 验证发送权限
    │ 参数验证 ▶ 检查目标地址、内容有效性
    │
    ▼
SmsSendManager::TextBasedSmsDelivery()
    │ 分段处理 ▶ 长短信自动分段
    │ 短码识别 ▶ 识别是否为短码(安全检查)
    │ 网络路由 ▶ 调用SmsNetworkPolicyManager确定通道
    │
    ▼
SmsSender子类(GsmSmsSender / CdmaSmsSender)
    │ 编码转换 ▶ 文本转GSM 7-bit / UCS2 / CDMA编码
    │ PDU生成 ▶ 构建完整的通信协议数据单元
    │ 参数打包 ▶ 组装发送参数
    │
    ▼
SmsSendIndexer(发送索引)
    │ 持久化存储 ▶ 记录到数据库,支持失败重试
    │ 队列入队 ▶ 加入发送队列
    │
    ▼
RIL层接口
    │ 异步通信 ▶ 通过HDF通道向Modem下发AT命令
    │
    ▼
Modem硬件
    │ 无线发送 ▶ 将短信通过无线信号传递
    │
    ▼
回调处理链
    │ 立即反馈 ▶ Modem返回发送状态(成功/失败)
    │ 结果回调 ▶ 触发ISendShortMessageCallback回调
    │ 送达报告 ▶ 网络返回送达确认时触发IDeliveryShortMessageCallback

关键环节详解

1. 分段处理(Segmentation)

长短信(长度超过单条限制)需要自动分段处理。

分段逻辑

  • GSM 7-bit 编码:单条最多 160 字符 → 超过自动分段
  • UCS2 编码:单条最多 70 字符 → 超过自动分段
  • CDMA:单条最多 200 字符 → 超过自动分段

分段打包

  • 每条分段短信需添加连接标头(UDH - User Data Header)
  • UDH 用于标明该分段在完整消息中的序号与总数
  • 接收端根据UDH重组为完整消息

示例:一条300字符的GSM短信被分为2段

消息 = "这是一条300字符的短信..." (300 chars)
       │
       ├─ 分段1 = [UDH标头] + 消息1-157字符
       │         (关键字段:当前第1段,总共2段)
       │
       └─ 分段2 = [UDH标头] + 消息158-300字符
                (关键字段:当前第2段,总共2段)

2. 编码转换(Encoding)

原始文本通过字符编码转换成 PDU 中的字节数据。

GSM 7-bit 编码特点

  • 最常用的短信编码
  • 支持标准ASCII字符、数字、标点符号
  • 某些字符需要转义(如 [, ], {, }
  • 编码后长度为原字符数

UCS2 编码特点

  • 支持中文、日文、韩文等多语言字符
  • 每个字符占用2字节
  • 编码后长度为原字符数的两倍
  • 自动选择标准:当文本中包含中文字符或其他非 GSM 7-bit 字符集支持的字符时,采用 UCS2 编码

编码选择算法

if (contain_chinese || contain_unicode_char) {
    encoding = UCS2;
    max_per_message = 70;
} else if (can_encode_with_7bit) {
    encoding = GSM_7BIT;
    max_per_message = 160;
} else {
    encoding = UCS2;  // 回退方案
    max_per_message = 70;
}

3. 网络路由决策(Routing Decision)

系统需要根据实时网络状态决定通过哪条通道发送短信。

决策点

在这里插入图片描述

网络状态监听

系统通过 NetworkStateManager 订阅网络变化事件:

  • 网络从离线变为在线时:启动待发队列的重试
  • 制式从 GSM 切换为 CDMA 时:可能需要重新编码(需缓存原始文本)
  • 信号强度显著下降时:延迟发送或增加重试次数

4. 数据库持久化(Persistence)

为支持发送失败后的重试机制,系统在数据库中记录待发送的短信。

SmsSendIndexer 数据结构

在这里插入图片描述

持久化时机

  • 发送前:确保即使进程崩溃,数据也能恢复
  • 重试前:更新重试次数和时间戳
  • 发送成功后:标记为已完成(可选删除)

5. 重试机制(Retry Logic)

发送失败并非终点,系统采用指数退避算法进行重试。

重试策略

在这里插入图片描述

重试触发条件

  • 网络状态恢复(从无信号到有信号)
  • 定时器触发(指定延迟后自动重试)
  • 通过后台服务定期扫描数据库中标记为“失败”的记录

重试触发代码路径

void SmsSendManager::RetrySmsDelivery(
    const std::shared_ptr<SmsSendIndexer> smsIndexer)
{
    // 从数据库读取原始消息
    // 重新走一遍编码、路由决策流程
    // 如果仍然失败,增加retryCount
    // 再次计算延迟后重新调度
}

6. 回调通知机制(Callback Notification)

异步操作完成后,通过 Binder IPC 通知应用层结果。

两类回调

  1. 发送结果回调ISendShortMessageCallback
    void OnSmsSendComplete(

    ISendShortMessageCallback::SmsSendResult result,  // 成功/失败/缺少权限等
    std::string url                                   // 可选的链接信息
    

    );

    触发时机:Modem 返回发送结果(通常在 0.5–2 秒内)

  2. 送达报告回调IDeliveryShortMessageCallback
    void OnSmsDeliveryComplete(

    ISendShortMessageCallback::SmsSendResult result   // 送达状态
    

    );
    ```raw

    触发时机:网络返回送达确认(可能延迟数秒至数分钟)

回调流程

Modem 返回 AT 响应
    │
    ▼
RIL 层解析响应
    │
    ▼
TelRilManager 回调 SmsSender::ProcessEvent()
    │
    ▼
SmsSender::HandleMessageResponse()
    │
    ├─ 成功 → 调用 SendResultCallBack(result=SUCCESS)
    ├─ 失败 → 调用 SendResultCallBack(result=FAILURE)
    │        更新数据库状态为“失败”
    │        如果 retryCount < MAX:调度重试
    │
    ▼
通过 Binder 通知应用的回调对象
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c9bd70bcd24f4af3a0d95c86ec10b0d7.png)

[短信中心号码长度] [短信中心号码] 
[消息类型标志] [消息参考] 
[目标地址长度] [目标地址类型] [目标地址]
[协议标识符] [数据编码方案]
[消息内容长度] [消息内容]
```raw

**GsmSmsSender 实现职责**:
1. 将目标号码和短信中心号码从国际格式转换为PDU格式
2. 选择合适的编码(7-bit vs UCS2)
3. 构建UDH(如果需要分段)
4. 调用RIL接口`SendSms`下发命令

### CDMA制式短信

**编码特点**:
- 使用8-bit编码
- 消息结构为TLV(Tag-Length-Value)格式
- 更复杂的可选参数

**消息体示例(简化)**:

[消息类型标签] [长度] [内容]
├─ 消息参考(可选)
├─ 目标地址
├─ 原始消息体(文本内容)
├─ 消息显示模式
├─ 优先级
└─ 回复选项(可选)


**CdmaSmsSender实现职责**:
1. 解析CDMA网络参数
2. 构建TLV格式的消息体
3. 填充可选参数
4. 调用RIL接口`SendCdmaSms`下发命令


### 双卡场景处理

在支持双SIM的设备上,系统需要为每张卡维护独立的发送管理器。

**架构设计**:

```mermaid
flowchart TD
    A["SmsService(单例)"] --> B["SmsInterfaceManager (slotId=0)"]
    A --> C["SmsInterfaceManager (slotId=1)"]
    B --> D["SmsSendManager"]
    D --> E["GsmSmsSender"]
    D --> F["CdmaSmsSender"]
    C --> G["SmsSendManager"]
    G --> H["GsmSmsSender"]
    G --> I["CdmaSmsSender"]

关键点

  • 发送操作需指定目标卡槽 ID
  • 不同卡槽的队列、重试计数完全独立
  • 网络状态监听需区分卡槽

在支持双SIM的设备上,系统需要为每张卡维护独立的发送管理器。

架构设计

SmsService(单例)
    │
    ├─ SmsInterfaceManager (slotId=0)
    │  ├─ SmsSendManager
    │  │  ├─ GsmSmsSender
    │  │  └─ CdmaSmsSender
    │  └─ ...
    │
    └─ SmsInterfaceManager (slotId=1)
       ├─ SmsSendManager
       │  ├─ GsmSmsSender
       │  └─ CdmaSmsSender
       └─ ...

**关键点**- 发送操作需指定目标卡槽 ID
- 不同卡槽的队列、重试计数完全独立
- 网络状态监听需区分卡槽


## 关键设计考量

### 可靠性设计

**问题**:短信发送失败会导致用户信息丢失。

**解决方案**1. **持久化存储**:发送前保存到数据库
2. **多次重试**:采用指数退避策略
3. **网络监听**:网络恢复时自动重试
4. **队列管理**:维护内存队列以支持快速重试

**可靠性保证**- 在网络恢复后的 120 秒内:99% 的失败短信可成功重试
- 发送失败后立即向用户返回结果,避免其长时间等待
- 用户可在消息应用中查看重试历史

### 性能优化

**问题**:大量短信并发发送会导致系统响应延迟。

**解决方案**1. **异步处理**:采用非阻塞 I/O 操作
2. **队列限制**:在内存中最多缓存1000条待发短信
3. **数据库批量操作**:减少 I/O 次数
4. **编码缓存**:避免重复的编码计算开销

**性能指标**- 单条短信从API调用到Modem响应:< 200ms
- 1000条短信发送队列处理:< 10秒

### 内存管理

**问题**:长期运行中可能出现内存泄漏。

**设计考虑**1. 使用智能指针(`std::shared_ptr``std::unique_ptr`2. 发送完成后,及时释放缓存的PDU与编码数据
3. 定期清理已过期的重试记录
4. 对各类对象池设置容量上限

### 安全性

**问题**:防止非授权应用发送短信。

**实现方式**1. **权限检查**:检查应用是否持有`SEND_MESSAGES`权限
2. **短码识别**:识别向短码(常用于诈骗)发送短信的行为
3. **频率限制**:限制单应用的发送频率(可选)
4. **审计日志**:记录所有短信发送操作

```cpp
// SmsSendManager中的权限检查示例
int32_t SmsSendManager::TextBasedSmsDelivery(...) {
    if (!CheckPermission(ISmsServiceInterface::SEND_MESSAGES)) {
        return PERMISSION_DENIED;
    }
    if (IsShortCode(desAddr)) {
        // 警告用户或拒绝发送
        LogSecurityWarning("Attempt to send to short code: " + desAddr);
    }
    // ... 继续处理
}

扩展性与可维护性

添加新的网络制式

要支持新的网络制式(如5G 独立组网的短信),需要:

  1. 创建新的Sender子类
    class NewNetworkSmsSender : public SmsSender {
    public:

    void TextBasedSmsDelivery(...) override;
    void DataBasedSmsDelivery(...) override;
    void SendSmsToRil(...) override;
    

    private:

    // 新制式特定的编码逻辑
    

    };

  2. 注册到SmsSendManager
    void SmsSendManager::Init() {

    gsmSmsSender_ = std::make_shared<GsmSmsSender>(...);
    cdmaSmsSender_ = std::make_shared<CdmaSmsSender>(...);
    newNetworkSender_ = std::make_shared<NewNetworkSmsSender>(...);
    

    }

  3. 更新网络策略管理器
    // 在SmsNetworkPolicyManager中添加新制式的路由逻辑
    if (IsNewNetworkAvailable()) {

    return newNetworkSender_;
    

    }

添加新的回调类型

如果应用层需要新的回调信息(如发送至哪个基站),需执行以下步骤:

  1. 扩展回调接口
    interface ISendShortMessageCallback {

    void OnSmsSendComplete(
        SmsSendResult result,
        string url,
        string baseStationInfo  // 新增字段
    );
    

    }

  2. 在 SmsSender 中收集新信息
    void SmsSender::HandleMessageResponse(...) {

    // 从 Modem 响应中提取基站信息
    baseStationInfo = ParseBaseStationFromModemResponse();
    // 传递给应用
    

    }

监控与诊断

系统通过以下指标进行健康度监控

  • 单小时发送成功率
  • 发送失败后的平均重试次数
  • 队列深度(未发送的待发短信数)
  • 从发起到完成的平均处理耗时

诊断工具

  • 日志分析:检索特定号码的发送记录
  • 状态导出功能:导出当前发送队列状态
  • 模拟工具:注入失败场景进行压力测试

下面用 Mermaid 图展示四大设计考量之间的平衡关系:

flowchart TD
    A["关键设计考量"] --> B["可靠性设计"]
    A --> C["性能优化"]
    A --> D["内存管理"]
    A --> E["安全性"]
    
    B --> B1["持久化存储"]
    B --> B2["多次重试(指数退避)"]
    B --> B3["网络监听自动重试"]
    B --> B4["队列管理"]
    
    C --> C1["异步非阻塞 I/O"]
    C --> C2["队列上限 1000 条"]
    C --> C3["数据库批量操作"]
    C --> C4["编码缓存"]
    
    D --> D1["智能指针管理"]
    D --> D2["及时释放 PDU 缓存"]
    D --> D3["定期清理过期记录"]
    D --> D4["对象池容量上限"]
    
    E --> E1["权限检查 SEND_MESSAGES"]
    E --> E2["短码识别与告警"]
    E --> E3["频率限制"]
    E --> E4["审计日志"]
    
    B -.->|"保障"| C
    C -.->|"兼顾"| D
    D -.->|"支撑"| B
    E -.->|"贯穿"| B
    E -.->|"贯穿"| C
    
    style A fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style B fill:#e3f2fd,stroke:#1565c0
    style C fill:#fff3e0,stroke:#e65100
    style D fill:#f3e5f5,stroke:#7b1fa2
    style E fill:#fce4ec,stroke:#c62828

总结

OpenHarmony 的短信能力依托 Telephony 子系统构建,是一套分层解耦、跨制式兼容的完整通信机制,核心原理与运行逻辑可从以下维度展开说明:

一、底层基础机制

短信本质是一种存储转发服务,发送方的短信内容会先提交至短信服务中心暂存,再由服务中心转发给目标接收方,内容以文本、数字或二进制数据为主要载体。OpenHarmony 的短信模块作为系统常驻核心服务,向下适配不同厂商的 Modem 硬件,向上为应用层提供标准化的 JS API 接口,同时兼容 GSM、CDMA 两大主流通信制式的短信协议规范。

二、分层架构原理

整个短信模块采用清晰的分层代码结构,各层职责明确:
1.接口层‌:对外暴露 JS 接口定义,通过 Napi 完成 C++ 层与 JS 层的调用封装,同时提供 Native 层内部调用接口;
2.框架层‌:承载彩信编解码工具、短信业务通用处理逻辑,实现跨硬件的能力抽象;
3.服务配置层‌:提供 SystemAbility 启动配置文件,确保短信服务随系统通信组件自动启动;
4.业务服务层‌:包含 GSM、CDMA 制式专属的 PDU 编解码逻辑,以及短信收发的核心业务处理代码;
5.工具层‌:提供短信通用处理工具,支撑长短信拆分、PDU数据解析等公共能力。

三、短信发送全流程原理

1.上层应用调用短信发送JS API,经过Napi层将请求转发至Native层的SmsInterfaceManager对象;
2.SmsInterfaceManager完成参数合法性过滤、应用权限鉴权,过滤无效请求;
3.请求转发至SmsSendManager,调用搜网服务获取当前SIM卡状态与网络制式信息;
4.根据网络制式自动创建GsmSmsSender或CdmaSmsSender,对长短信进行自动拆分,将文本内容编码为符合协议规范的PDU数据包;
5.编码完成的短信加入发送队列,通过RIL Adapter下发至底层Modem硬件,最终提交至运营商短信服务中心;
6.若发送失败,系统自动触发重发机制,多次重试后将最终发送状态回调给上层应用。

四、短信接收全流程原理

1.系统启动时,SmsReceiveManager会创建对应网络制式的短信接收处理器,提前向RIL层注册短信事件监听;
2.运营商网络下发短信时,Modem通过RIL Adapter将原始PDU数据上报至短信服务;
3.对应制式的接收处理器调用SmsBaseMessage组件,完成PDU数据的解析,还原出短信的发送方号码、内容、时间戳等核心信息;
4.系统自动完成短信存储、送达报告上报,同时将短信通知分发至系统短信应用,触发新消息提醒。

五、配套扩展机制

1.支持SIM卡内短信的增删改查管理,可直接读写SIM卡存储的短信记录;
2.内置Wap Push接收处理、小区广播接收能力,可处理运营商推送的特殊短信;
3.提供垃圾短信规则引擎,支持自定义关键词、正则匹配规则,自动拦截或标记垃圾短信;
4.跨平台适配层屏蔽硬件差异,在RK3568等搭载4G模块的开发板上,无需大幅修改代码即可完整实现短信收发全功能。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐