一、概述:卫星短信的特点与挑战
核心发现
基于 Android 16 代码分析,卫星短信不走传统 SmsDispatcher 路径,而是通过 SatelliteManager.sendDatagram() 以 Datagram(数据报) 方式收发。这意味着卫星短信与地面 SMS 是 完全独立的通道。
卫星短信的挑战
| 挑战 | 说明 |
|---|---|
| 高延迟 | RTT 500ms~数秒,远超地面 SMS |
| 间歇性覆盖 | 卫星非持续可见,需等待窗口 |
| 受限消息长度 | 卫星数据报容量有限 |
| 非实时送达 | 需存储转发机制 |
| 低功耗要求 | 终端需控制唤醒频率 |
二、短信发送流程
时序图
App (Gateway/短信应用)
│
│ 1. SatelliteManager.sendDatagram(DATAGRAM_TYPE_SMS, datagram, ...)
↓
SatelliteManager
│
│ 2. ITelephony.sendDatagram(datagramType, datagram, needFullScreenPointingUI, callback)
↓
Telephony Service (ITelephony AIDL)
│
│ 3. 调用 ISatellite.sendSatelliteDatagram(datagram, isEmergency, resultCallback)
↓
SatelliteImplBase (Vendor Service)
│
│ 4. 厂商实现:调用 Vendor HAL / Modem
↓
Satellite Modem
│
│ 5. 卫星链路发送(NAS PDU / 专用通道)
↓
卫星
│
│ 6. 返回发送结果
↓
ISatelliteListener → Framework → App
详细步骤
步骤 1:应用层发起
卫星短信 不使用 SmsManager.sendTextMessage(),而是通过 SatelliteManager.sendDatagram():
// SatelliteManager.java:2289
public void sendDatagram(@DatagramType int datagramType,
@NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener)
关键参数:
datagramType = DATAGRAM_TYPE_SMS(值=6):标识这是 SMS 类型数据报datagram:已编码的SatelliteDatagram(byte[] 格式,由 Gateway 应用加密/编码)needFullScreenPointingUI:是否需要全屏指向 UI
步骤 2:通过 ITelephony 传递到 Telephony Service
// SatelliteManager.java:2307
telephony.sendDatagram(datagramType, datagram,
needFullScreenPointingUI, internalCallback);
步骤 3:Telephony Service 调用 ISatellite AIDL
Telephony 内部将请求转发到 Vendor Service 的 ISatellite.sendSatelliteDatagram():
// ISatellite.aidl
void sendSatelliteDatagram(in SatelliteDatagram datagram, in boolean isEmergency,
in IIntegerConsumer resultCallback);
步骤 4:Vendor Service 实现
OEM 厂商在 SatelliteImplBase.sendSatelliteDatagram() 中实现真正的发送逻辑:
- 调用 Vendor HAL
- Modem 执行卫星随机接入
- 将 SMS 数据封装到卫星信令通道
步骤 5:卫星链路发送
- 3GPP NTN:SMS 封装在 NAS PDU 中,走控制平面,无需建立数据承载
- 私有卫星系统(如北斗):通过 RDSS 通道发送短报文
步骤 6:状态回调
发送结果通过 IIntegerConsumer resultCallback 返回,可能的错误码包括:
| 错误码 | 含义 |
|---|---|
SATELLITE_RESULT_SUCCESS | 发送成功 |
SATELLITE_RESULT_NETWORK_TIMEOUT | 网络超时 |
SATELLITE_RESULT_NOT_REACHABLE | 卫星不可达 |
SATELLITE_RESULT_ACCESS_BARRED | 接入被拒 |
SATELLITE_RESULT_REQUEST_ABORTED | 请求被中止 |
三、短信接收流程
时序图
卫星
│
│ 1. 下发 SMS 数据报
↓
Satellite Modem
│
│ 2. ISatelliteListener.onSatelliteDatagramReceived(datagram, pendingCount)
↓
SatelliteImplBase (Vendor Service)
│
│ 3. 回调到 Telephony Framework
↓
Telephony Service
│
│ 4. ISatelliteDatagramCallback.onSatelliteDatagramReceived(datagramId, datagram, pendingCount, ack)
↓
SatelliteManager → SatelliteDatagramCallback
│
│ 5. App 收到数据报,5分钟内必须 ack
↓
App (Gateway/短信应用)
详细步骤
步骤 1-2:Modem 接收并上报
Modem 收到卫星数据报后,Vendor Service 通过 ISatelliteListener 回调:
// ISatelliteListener.aidl
void onSatelliteDatagramReceived(in SatelliteDatagram datagram, in int pendingCount);
步骤 3-4:Framework 分发到应用
应用需先注册接收回调:
// SatelliteManager.java:2134
@SatelliteResult public int registerForIncomingDatagram(
@NonNull Executor executor,
@NonNull SatelliteDatagramCallback callback)
当有数据报到达时,回调触发:
// SatelliteDatagramCallback.java
void onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram,
int pendingCount, Consumer<Void> callback);
关键机制:5 分钟 ACK 超时
// SatelliteDatagramCallback.java 注释
// If the callback is not received within five minutes,
// Telephony will resend the datagram.
如果应用在 5 分钟内未调用 callback.accept(null) 确认,Telephony 会重新发送该数据报。
步骤 5:主动拉取(Poll)
对于存储转发的场景,应用可以主动拉取待接收的数据报:
// SatelliteManager.java:2232
public void pollPendingDatagrams(Executor executor, Consumer<Integer> resultListener)
对应的 Vendor 接口:
// ISatellite.aidl
void pollPendingSatelliteDatagrams(in IIntegerConsumer resultCallback);
四、卫星短信特有机制
1. Datagram 类型体系
卫星短信不是传统 SMS,而是通过 Datagram 承载:
| 类型 | 值 | 用途 |
|---|---|---|
DATAGRAM_TYPE_SOS_MESSAGE | 1 | SOS 紧急消息 |
DATAGRAM_TYPE_LOCATION_SHARING | 2 | 位置共享 |
DATAGRAM_TYPE_KEEP_ALIVE | 3 | 保活/检查入消息 |
DATAGRAM_TYPE_SMS | 6 | SMS 短信 |
DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS | 7 | 检查待接收 SMS |
2. 数据报传输状态机
IDLE → SENDING → SEND_SUCCESS / SEND_FAILED → IDLE
IDLE → RECEIVING → RECEIVE_SUCCESS / RECEIVE_NONE / RECEIVE_FAILED → IDLE
IDLE → WAITING_TO_CONNECT → (连接卫星后继续) → IDLE
通过 SatelliteTransmissionUpdateCallback 监听状态变化:
void onSendDatagramStateChanged(int state, int sendPendingCount, int errorCode);
void onReceiveDatagramStateChanged(int state, int receivePendingCount, int errorCode);
3. 紧急短信优先级
DATAGRAM_TYPE_SOS_MESSAGE(1) 优先级最高sendSatelliteDatagram的isEmergency参数标识紧急消息- Modem 侧可能为紧急消息分配更高的卫星接入优先级
4. 存储转发与主动拉取
卫星链路非实时,接收流程有两种模式:
| 模式 | 触发方式 | 接口 |
|---|---|---|
| 被动接收 | Modem 收到数据后回调 | ISatelliteListener.onSatelliteDatagramReceived |
| 主动拉取 | 应用主动查询 | pollPendingDatagrams() / DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS |
5. 卫星监听模式
// ISatellite.aidl
void requestSatelliteListeningEnabled(in boolean enable, in int timeout,
in IIntegerConsumer resultCallback);
timeout:Modem 等待下一个入站页面的时间- 超时后自动禁用监听模式,节省功耗
6. 地面网络扫描
// ISatellite.aidl
void enableTerrestrialNetworkScanWhileSatelliteModeIsOn(in boolean enabled,
in IIntegerConsumer errorCallback);
卫星模式下允许扫描地面网络,当用户不活跃时检查是否有地面网络可用。
五、与地面 SMS 的对比
| 维度 | 地面 SMS | 卫星 SMS (Android 16) |
|---|---|---|
| API 入口 | SmsManager.sendTextMessage() | SatelliteManager.sendDatagram() |
| 协议栈 | 3GPP TS 23.040/24.011 | 3GPP NTN NAS PDU / 私有协议 |
| 传输通道 | SmsDispatcher → RILJ → Modem | ITelephony → ISatellite → Vendor Service → Modem |
| 消息格式 | GSM/3GPP SMS PDU | SatelliteDatagram (byte[]) |
| 消息长度 | 160 字符/条 | 由卫星提供商决定(更受限) |
| 典型时延 | 1-5 秒 | 5 秒~数分钟 |
| 送达报告 | deliveryIntent 实时 | IIntegerConsumer 回调(延迟大) |
| 接收模式 | Modem 主动上报 +CMT | 被动回调 + 主动 pollPendingDatagrams |
| ACK 机制 | acknowledgeLastIncomingSms() 即时 | 5 分钟内 Consumer<Void> 确认 |
| 分片支持 | sendMultipartTextMessage | 应用层自行处理 |
| 存储转发 | SMSC 存储 | 卫星网络侧 + 终端 poll |
| 紧急优先 | 无特殊优先级 | isEmergency=true + DATAGRAM_TYPE_SOS_MESSAGE |
六、Android 关键代码与配置位置
Framework 层
| 文件 | 作用 |
|---|---|
| SatelliteManager.java | 应用 API,sendDatagram() / pollPendingDatagrams() / registerForIncomingDatagram() |
| SatelliteDatagram.java | 数据报模型,byte[] mData |
| SatelliteDatagramCallback.java | 接收回调,onSatelliteDatagramReceived() |
| SatelliteTransmissionUpdateCallback.java | 传输状态回调 |
Vendor Service 层(stub)
| 文件 | 作用 |
|---|---|
| ISatellite.aidl | Framework → Vendor 接口,sendSatelliteDatagram() / pollPendingSatelliteDatagrams() |
| ISatelliteListener.aidl | Vendor → Framework 回调,onSatelliteDatagramReceived() |
| SatelliteImplBase.java | 厂商需继承的基类 |
| SatelliteService.java | Service 入口 |
| SatelliteGatewayService.java | Gateway 服务(绑定/解绑生命周期管理) |
关键配置
| 配置 | 说明 |
|---|---|
config_satellite_service_package | Vendor SatelliteService 的包名 |
config_satellite_gateway_service_package | Gateway 服务包名 |
android.permission.BIND_SATELLITE_SERVICE | 绑定卫星服务权限 |
android.permission.SATELLITE_COMMUNICATION | 应用调用卫星 API 权限 |
七、调试与测试建议
logcat 标签
| Tag | 用途 |
|---|---|
SatelliteManager | 应用 API 调用日志 |
SatelliteService | Service 绑定日志 |
SatelliteImplBase | Vendor Service 方法调用日志 |
关键调试点
- 发送流程:在
SatelliteManager.sendDatagram()打断点,跟踪ITelephony.sendDatagram()调用 - 接收流程:在
SatelliteDatagramCallback.onSatelliteDatagramReceived()打断点 - 状态变化:监听
SatelliteTransmissionUpdateCallback.onSendDatagramStateChanged() - ACK 超时:注意 5 分钟 ACK 超时机制,未确认会重发
模拟测试
- 使用
DATAGRAM_TYPE_SOS_MESSAGE模拟紧急短信 - 使用
pollPendingDatagrams()模拟存储转发场景 - 通过
requestSatelliteListeningEnabled(true, timeout)控制监听窗口