一、概述:卫星短信的特点与挑战
1.1 Android 16 卫星短信的两种架构
Android 16 中卫星短信存在两条完全不同的路径:
| 路径 | 机制 | 适用场景 | AOSP 原生支持 |
|---|---|---|---|
| 运营商 NTN 漫游 SMS | 复用标准 3GPP SMS over NAS,通过 SmsDispatchersController → DatagramDispatcher → ImsSmsDispatcher → RIL | 运营商 NB-IoT NTN 网络(如 T-Mobile Starlink) | ✅ 完整支持 |
| OEM 卫星数据报 | 通过 SatelliteManager.sendDatagram() 发送加密数据报,不经过标准 SMS 协议栈 | OEM 私有卫星(天通、铱星 SBD 等) | ✅ 完整支持 |
关键设计决策:运营商 NTN 漫游模式下,标准 P2P SMS 不经过 SatelliteManager.sendDatagram(),而是走标准 SMS 协议栈,由 SmsDispatchersController 判断当前处于 NTN 漫游后,将 SMS 路由到 DatagramDispatcher 协调发送。
1.2 核心挑战
| 挑战 | 地面 SMS | 卫星 SMS | 影响 |
|---|---|---|---|
| 传播延迟 | 1-5秒 | 5-30秒 (LEO) / 30-120秒 (GEO) | 超时判断、用户体验 |
| 间歇性覆盖 | 持续覆盖 | 卫星过境才可用 | 存储转发、MT SMS 轮询 |
| 消息长度 | 160字符 (GSM) | 更短(北斗140字节、铱星340字节) | 分片策略 |
| 功耗 | 低 | 高(需对星、发射功率大) | 接收窗口调度 |
| 双向通信 | 实时 | 半双工或受限 | MT SMS 需主动轮询 |
二、短信发送流程
2.1 运营商 NTN 漫游 SMS 发送流程
这是 Android 16 中最完整的卫星 SMS 实现,代码路径清晰可追踪。
┌─────────────────────────────────────────────────────────────────────────────┐
│ 运营商 NTN 漫游 SMS 发送流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ① 应用层发起 │
│ SmsManager.sendTextMessage(destAddr, scAddr, text, sentIntent, delivery) │
│ │ → IccSmsInterfaceManager.sendText() │
│ │ → SmsDispatchersController.sendText() │
│ ▼ │
│ ② NTN 漫游判断与路由 │
│ SmsDispatchersController.sendText() │
│ │ → SatelliteController.shouldSendSmsToDatagramDispatcher(phone) │
│ │ 条件: │
│ │ 1. isInCarrierRoamingNbIotNtn(phone) == true │
│ │ - 卫星已启用 │
│ │ - 运营商支持卫星 (isSatelliteSupportedViaCarrier) │
│ │ - 连接类型为 MANUAL (CARRIER_ROAMING_NTN_CONNECT_MANUAL) │
│ │ - subId 匹配卫星订阅 │
│ │ 2. isDemoModeEnabled() == false │
│ │ 3. getSupportedServicesOnCarrierRoamingNtn() 包含 SERVICE_TYPE_SMS │
│ │ │
│ ├── shouldSendSmsToDatagramDispatcher == true │
│ │ → DatagramDispatcher.sendSms(pendingRequest) ← 卫星路径 │
│ │ │
│ ├── shouldSendSmsToDatagramDispatcher == false │
│ │ && isInCarrierRoamingNbIotNtn == true │
│ │ → triggerSentIntentForFailure() ← 阻止SMS(P2P不支持时) │
│ │ │
│ └── 否则 → sendTextInternal() ← 标准地面路径 │
│ │
│ ③ DatagramDispatcher 处理 │
│ DatagramDispatcher.sendSms(pendingSms) │
│ │ → SatelliteController.startPointingUI() // 启动对星UI │
│ │ → mPendingSmsMap.put(messageId, pendingSms) // 加入待发队列 │
│ │ │
│ │ 判断卫星连接状态: │
│ ├── needsWaitingForSatelliteConnected() == true │
│ │ → updateSendStatus(WAITING_TO_CONNECT) │
│ │ → startDatagramWaitForConnectedStateTimer() │
│ │ │
│ ├── !mSendingInProgress && isPollingInIdleState() │
│ │ → mSendingInProgress = true │
│ │ → updateSendStatus(SENDING) │
│ │ → sendMessage(CMD_SEND_SMS, pendingSms) │
│ │ │
│ └── 否则 → 排队等待(mSendingInProgress=true 或正在接收) │
│ ▼ │
│ ④ CMD_SEND_SMS 处理 │
│ DatagramDispatcher.handleMessage(CMD_SEND_SMS) │
│ │ → satellitePhone = SatelliteController.getSatellitePhone() │
│ │ → smsDispatchersController = satellitePhone.getSmsDispatchersController│
│ │ → mSmsTransmissionStartTime = System.currentTimeMillis() │
│ │ → smsDispatchersController.sendCarrierRoamingNbIotNtnText(request) │
│ ▼ │
│ ⑤ SmsDispatchersController 回调到标准 SMS 栈 │
│ sendCarrierRoamingNbIotNtnText(request) │
│ │ → sendMessage(CMD_SEND_TEXT, request) │
│ │ → sendTextInternal(request) │
│ │ → mImsSmsDispatcher.sendText(...) // 走IMS SMS通道 │
│ │ → RIL.sendImsGsmSms() → Modem → 卫星NAS → SMSC │
│ ▼ │
│ ⑥ 发送结果回调 │
│ SmsDispatchersController.onSmsSentResult() │
│ │ → if (shouldSendSmsToDatagramDispatcher && isLastSmsPart) │
│ │ DatagramDispatcher.onSendSmsDone(subId, messageId, success) │
│ ▼ │
│ ⑦ DatagramDispatcher 处理发送结果 │
│ handleEventSendSmsDone(subId, messageId, success) │
│ │ → pendingSms = mPendingSmsMap.remove(messageId) │
│ │ → mSendingInProgress = false │
│ │ │
│ ├── success == true │
│ │ → updateSendStatus(SEND_SUCCESS) │
│ │ → if (isMtSmsPolling) startMtSmsPollingThrottle() │
│ │ → reportSendSmsCompleted(SATELLITE_RESULT_SUCCESS) │
│ │ │
│ └── success == false │
│ → updateSendStatus(SEND_FAILED) │
│ → reportSendSmsCompleted(SATELLITE_RESULT_NETWORK_ERROR) │
│ │ │
│ → if (pendingMessages > 0) sendPendingMessages() │
│ → else updateSendStatus(IDLE) │
│ └─────────────────────────────────────────────────────────────────────────┘
2.2 P2P SMS 禁用判断
运营商可能不允许 P2P SMS,此时 SMS 会被阻止:
// SmsDispatchersController.java L1885-1894
if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) {
// Send P2P SMS using carrier roaming NB IOT NTN
DatagramDispatcher.getInstance().sendSms(pendingRequest);
return;
} else if (SatelliteController.getInstance().isInCarrierRoamingNbIotNtn()) {
// Block SMS in satellite mode if P2P SMS is not supported.
triggerSentIntentForFailure(pendingRequest.sentIntents);
return;
}
P2P SMS 禁用条件(SatelliteController.java:9594):
public boolean isP2PSmsDisallowedOnCarrierRoamingNtn(int subId) {
int carrierRoamingNtnConnectType = getCarrierRoamingNtnConnectType(subId);
if (carrierRoamingNtnConnectType == CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
if (!isNtnSmsSupportedByMessagesApp()
|| !isApplicationSupportsP2P(getSatelliteGatewayServicePackageName())) {
return true; // 短信应用或网关应用不支持P2P
}
if (!isSubscriptionProvisioned(subId)) {
return true; // 订阅未开通
}
}
return false;
}
2.3 OEM 卫星数据报发送流程
OEM 卫星模式(天通/铱星等)使用完全不同的路径——SatelliteManager.sendDatagram():
┌─────────────────────────────────────────────────────────────────────────────┐
│ OEM 卫星数据报发送流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ① 应用层发起 │
│ SatelliteManager.sendDatagram(datagram, datagramType, needPointingUI) │
│ │ → ISatelliteService.sendSatelliteDatagram() │
│ │ → SatelliteService → SatelliteController │
│ ▼ │
│ ② DatagramController 处理 │
│ DatagramController.sendSatelliteDatagram(subId, datagramType, datagram) │
│ │ → 检查卫星状态(已连接、已对星) │
│ │ → DatagramDispatcher.sendSatelliteDatagram() │
│ ▼ │
│ ③ DatagramDispatcher 下发到 Modem │
│ │ → SatelliteModemInterface.sendSatelliteDatagram(datagram, isEmergency) │
│ │ → mSatelliteService.sendSatelliteDatagram() // HAL AIDL │
│ │ → Modem 固件 → 卫星链路 │
│ ▼ │
│ ④ 结果回调 │
│ Modem → HAL → SatelliteModemInterface → DatagramDispatcher │
│ → DatagramController.updateSendStatus() → SatelliteManager callback │
│ └─────────────────────────────────────────────────────────────────────────┘
关键区别:OEM 数据报路径不经过 SmsDispatchersController,消息由应用自行编码为加密数据报,框架不解析内容。
三、短信接收流程
3.1 运营商 NTN 漫游 SMS 接收流程
NTN 漫游模式下,MT SMS 的接收有一个独特机制——终端需要主动轮询(MT SMS Polling),因为卫星链路无法像地面网络那样实时推送 Paging。
┌─────────────────────────────────────────────────────────────────────────────┐
│ 运营商 NTN 漫游 SMS 接收流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ① MT SMS 轮询触发 │
│ DatagramDispatcher │
│ │ 触发条件: │
│ │ - 卫星 Modem 进入 CONNECTED 状态(首次连接时) │
│ │ - 卫星对准成功(isAligned == true) │
│ │ - MT SMS 轮询节流超时后 │
│ │ │
│ │ allowMtSmsPolling() 检查: │
│ │ - !isP2PSmsDisallowedOnCarrierRoamingNtn(subId) │
│ │ - Modem状态为 CONNECTED 或 DATAGRAM_TRANSFERRING │
│ │ - !mIsMtSmsPollingThrottled (未被节流) │
│ │ - mIsAligned == true (已对星) │
│ │ - isEnabledMtSmsPolling() (配置启用) │
│ │ - shouldPollMtSms() (卫星控制器允许) │
│ ▼ │
│ ② 构造轮询 SMS │
│ SmsDispatchersController.sendMtSmsPollingMessage() │
│ │ → destAddr = 自己的手机号 (SubscriptionManager.getPhoneNumber) │
│ │ → mtSmsPollingText = config_mt_sms_polling_text (配置的轮询文本) │
│ │ → 创建 PendingRequest(isMtSmsPolling=true) │
│ │ → DatagramDispatcher.sendSms(pendingRequest) │
│ ▼ │
│ ③ 轮询 SMS 发送(同发送流程) │
│ DatagramDispatcher → CMD_SEND_SMS → SmsDispatchersController │
│ → sendCarrierRoamingNbIotNtnText → ImsSmsDispatcher → RIL → Modem │
│ → 卫星链路 → SMSC │
│ │ │
│ │ SMSC 收到发往自己的 SMS 后, │
│ │ 将所有待投递的 MT SMS 下发给终端 │
│ ▼ │
│ ④ MT SMS 到达 Modem │
│ Modem → RIL_UNSOL_RESPONSE_NEW_SMS │
│ → RILJ → mSmsRegistrant.notifyRegistrant() │
│ → SmsDispatchersController.handleMessage(EVENT_NEW_SMS) │
│ → InboundSmsHandler → 写入 content://sms │
│ → SMS_RECEIVED_ACTION 广播 │
│ → 默认短信应用显示新消息 │
│ ▼ │
│ ⑤ 轮询结果处理 │
│ handleEventSendSmsDone(subId, messageId, success) │
│ │ datagramType = DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS │
│ │ if (success) startMtSmsPollingThrottle() │
│ │ │
│ │ MT SMS 轮询节流: │
│ │ mIsMtSmsPollingThrottled = true │
│ │ sendMessageDelayed(EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT, │
│ │ config_mt_sms_polling_throttle_millis) │
│ └─────────────────────────────────────────────────────────────────────────┘
3.2 MT SMS 轮询的核心设计
为什么需要轮询? 卫星网络中,终端无法像地面网络那样持续监听 Paging 信道(功耗太高、卫星可能不在上空)。因此采用"终端主动询问 SMSC 是否有待收消息"的模式。
轮询 SMS 的构造(SmsDispatchersController.java:2264):
public void sendMtSmsPollingMessage() {
// 目标地址 = 自己的手机号
String destAddr = subscriptionManager.getPhoneNumber(mPhone.getSubId());
// 轮询文本 = 配置的固定文本
String mtSmsPollingText = mContext.getResources()
.getString(R.string.config_mt_sms_polling_text);
// 创建轮询请求
PendingRequest pendingRequest = new PendingRequest(TYPE_TEXT, null,
callingPackage, ..., destAddr, scAddr, ..., asArrayList(mtSmsPollingText),
..., true /*isMtSmsPolling*/, true /*skipShortCodeCheck*/, ...);
DatagramDispatcher.getInstance().sendSms(pendingRequest);
}
轮询节流机制(DatagramDispatcher.java:1392):
private void startMtSmsPollingThrottle() {
mIsMtSmsPollingThrottled.set(true);
sendMessageDelayed(obtainMessage(EVENT_MT_SMS_POLLING_THROTTLE_TIMED_OUT),
getMtSmsPollingThrottleMillis()); // config_mt_sms_polling_throttle_millis
}
3.3 OEM 卫星数据报接收流程
┌─────────────────────────────────────────────────────────────────────────────┐
│ OEM 卫星数据报接收流程 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ① Modem 接收卫星数据报 │
│ Modem → SatelliteModemInterface.onSatelliteDatagramReceived() │
│ → DatagramReceiver.pollPendingSatelliteDatagrams() │
│ → SatelliteModemInterface.pollPendingSatelliteDatagrams() │
│ → mSatelliteService.pollPendingSatelliteDatagrams() // HAL AIDL │
│ → Modem 返回 SatelliteDatagram + pendingCount │
│ ▼ │
│ ② DatagramReceiver 处理 │
│ EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE │
│ │ → 解析 SatelliteDatagram + pendingCount │
│ │ │
│ ├── pendingCount <= 0 && datagram == null │
│ │ → updateReceiveStatus(RECEIVE_NONE) // 无待收消息 │
│ │ │
│ └── datagram != null │
│ → updateReceiveStatus(RECEIVE_SUCCESS) │
│ → datagramId = getDatagramId() // 持久化ID │
│ → insertDatagram(datagramId, datagram) // 写入DB │
│ content://satellite_datagrams │
│ → 通知所有注册的 ISatelliteDatagramCallback: │
│ listener.onSatelliteDatagramReceived(datagramId, datagram, │
│ pendingCount, ackCallback) │
│ → 启动 ACK 超时定时器: │
│ sendMessageDelayed(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, │
│ config_timeout_to_receive_delivered_ack_millis) │
│ ▼ │
│ ③ 应用层接收 │
│ ISatelliteDatagramCallback.onSatelliteDatagramReceived() │
│ → 卫星消息应用解析数据报 │
│ → 调用 ackCallback.accept() 确认接收 │
│ ▼ │
│ ④ ACK 处理与重试 │
│ EVENT_RECEIVED_ACK │
│ │ → pendingAckCount -= 1 │
│ │ → removeMessages(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM) │
│ │ → if (pendingAckCount <= 0) deleteDatagram(datagramId) │
│ │
│ EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM │
│ → 重新调用 onSatelliteDatagramReceived() // 5分钟未ACK则重试 │
│ │
│ ⑤ 继续轮询 │
│ if (pendingCount > 0) │
│ → pollPendingSatelliteDatagramsInternal() // 继续拉取下一条 │
│ └─────────────────────────────────────────────────────────────────────────┘
3.4 SMS 接收通知(运营商 NTN)
当运营商 NTN 漫游模式下收到标准 SMS 时,DatagramController 会更新接收状态:
// DatagramController.java L375-386
void onSmsReceived(int subId) {
// 快速通知三个状态:RECEIVING → RECEIVE_SUCCESS → IDLE
updateReceiveStatus(subId, SatelliteManager.DATAGRAM_TYPE_SMS,
SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, ...);
updateReceiveStatus(subId, SatelliteManager.DATAGRAM_TYPE_SMS,
SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, ...);
updateReceiveStatus(subId, SatelliteManager.DATAGRAM_TYPE_SMS,
SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, ...);
}
四、卫星短信特有机制
4.1 长延迟与重试
发送队列与串行化:
DatagramDispatcher 使用 mPendingSmsMap(LinkedHashMap)维护待发 SMS 队列,严格串行发送:
// DatagramDispatcher.java
private final LinkedHashMap<Long, PendingRequest> mPendingSmsMap = new LinkedHashMap<>();
private AtomicBoolean mSendingInProgress = new AtomicBoolean(false);
- 同一时刻只有一条 SMS 在发送(
mSendingInProgress标志) - 发送完成后才处理下一条(
sendPendingMessages()) - 若正在接收数据报,也等待接收完成(
isPollingInIdleState())
等待卫星连接:
若 SMS 到达时卫星未连接,进入等待状态:
// DatagramDispatcher.java L1167-1172
if (mDatagramController.needsWaitingForSatelliteConnected(datagramType)) {
mDatagramController.updateSendStatus(subId, datagramType,
SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_WAITING_TO_CONNECT, ...);
startDatagramWaitForConnectedStateTimer(datagramType);
}
ACK 超时重试(OEM 数据报模式):
// DatagramReceiver.java L249-252
private int getTimeoutToReceiveAck() {
return sInstance.mContext.getResources().getInteger(
R.integer.config_timeout_to_receive_delivered_ack_millis); // 默认5分钟
}
5分钟内未收到应用 ACK,则重新投递数据报。
4.2 受限消息长度
| 卫星系统 | 最大消息长度 | 分片策略 |
|---|---|---|
| 3GPP NTN SMS | 标准 GSM SMS 160字符 | 标准 SMS 分片(concat ref) |
| 北斗 RDSS 短报文 | 140字节(民用)/ 1000字节(授权) | 应用层分段 |
| 铱星 SBD | 340字节 | 应用层分段 |
| 天通 SMS | ~140字节 | 标准 SMS 分片 |
| OEM 数据报 | 由 SatelliteCapabilities 声明 | 框架不限制,应用负责 |
运营商 NTN SMS 的长短信处理:
SmsDispatchersController 的 sendMultipartText() 同样支持 NTN 漫游路由:
// SmsDispatchersController.java L2056-2065
if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) {
// Send multipart P2P SMS using carrier roaming NB IOT NTN
DatagramDispatcher.getInstance().sendSms(pendingRequest);
return;
} else if (SatelliteController.getInstance().isInCarrierRoamingNbIotNtn()) {
// Block SMS in satellite mode if P2P SMS is not supported.
triggerSentIntentForFailure(pendingRequest.sentIntents);
return;
}
发送完成回调仅触发一次(最后一片时):
// SmsDispatchersController.java L1272-1276
if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)
&& isLastSmsPart) {
DatagramDispatcher.getInstance().onSendSmsDone(
mPhone.getSubId(), messageId, success);
}
4.3 紧急短信优先级
OEM 数据报模式:紧急数据报(SOS_MESSAGE)获得更高优先级:
// DatagramDispatcher.java L104-105
private AtomicBoolean mIsEmergencyCommunicationEstablished = new AtomicBoolean(false);
紧急数据报标记 isEmergency=true,Modem 可能给予更高的卫星接入优先级。
运营商 NTN SMS:紧急号码检测:
// SmsDispatchersController.java L2070-2075
private boolean isEmergencyNumber(String number) {
if (!mPhone.hasCalling()) return false;
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
if (tm == null) return false;
return tm.isEmergencyNumber(number);
}
紧急 SMS 会触发 EmergencyStateTracker.onEmergencySmsReceived()。
4.4 波束切换时的 SMS 处理
发送中切换:
若卫星 Modem 状态变化(波束切换、卫星切换),DatagramDispatcher 收到 EVENT_SATELLITE_MODEM_STATE_CHANGED:
// DatagramDispatcher.java L429-438
case EVENT_SATELLITE_MODEM_STATE_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
int state = (int) args.arg1;
handleEventSatelliteModemStateChanged(state);
break;
}
- 若切换到
NOT_CONNECTED:等待重新连接,mPendingSmsMap保留未发送的 SMS - 若切换回
CONNECTED:触发sendPendingMessages()继续发送 - 若卫星被禁用:
cleanUpResources()清理所有待发 SMS 并返回错误
接收中切换:
DatagramReceiver 同样监听 Modem 状态变化,若重新连接后自动触发 pollPendingSatelliteDatagrams()。
4.5 SMS 投递策略(shouldDropSms)
当终端处于 NTN 漫游但不支持 SMS 时,SMS 会被丢弃:
// SatelliteController.java L9792-9803
public boolean shouldDropSms(@Nullable Phone phone) {
if (!isInCarrierRoamingNbIotNtn(phone)) {
return false;
}
int[] services = getSupportedServicesOnCarrierRoamingNtn(phone.getSubId());
return !ArrayUtils.contains(services, NetworkRegistrationInfo.SERVICE_TYPE_SMS);
}
五、与地面 SMS 的对比表格
| 对比维度 | 地面 SMS | 运营商 NTN SMS | OEM 卫星数据报 |
|---|---|---|---|
| 协议栈 | 3GPP TS 23.040/24.011 | 3GPP SMS over NAS over NTN | 厂商私有(加密数据报) |
| 发送路径 | SmsManager → SmsDispatcher → RIL → Modem | SmsManager → SmsDispatchersController → DatagramDispatcher → ImsSmsDispatcher → RIL | SatelliteManager.sendDatagram → DatagramController → SatelliteModemInterface → HAL |
| 接收路径 | Modem → RIL_UNSOL → InboundSmsHandler → DB → 广播 | 同左 + DatagramController.onSmsReceived() 通知 | Modem → HAL → DatagramReceiver.poll → DB → ISatelliteDatagramCallback |
| MT 触发方式 | 网络主动 Paging 推送 | 终端主动轮询(MT SMS Polling) | 终端主动轮询(pollPendingDatagrams) |
| 典型发送时延 | 1-5秒 | 5-30秒 (LEO) | 5-60秒 |
| 典型接收时延 | 即时 | 轮询间隔 + 传播延迟 | 轮询间隔 + 传播延迟 |
| 消息长度 | 160字符/条 | 160字符/条(标准SMS分片) | 取决于卫星能力 |
| 送达报告 | 支持(deliveryIntent) | 支持(但延迟大) | 不支持(应用层实现) |
| 存储转发 | SMSC 存储 | SMSC 存储 + 终端轮询拉取 | 卫星网关存储 + 终端轮询 |
| ACK 机制 | CP-ACK + RP-ACK | 同左 | 应用层 ACK(5分钟超时重试) |
| 发送队列 | 无(并发发送) | 严格串行(mSendingInProgress) | 严格串行 |
| 对星要求 | 不需要 | 需要(isAligned) | 需要(isAligned) |
| 功耗 | 低 | 高 | 高 |
| Android API | SmsManager | SmsManager(透明) | SatelliteManager.sendDatagram |
| 数据存储 | content://sms | content://sms | content://satellite_datagrams |
| 3GPP 标准 | TS 23.040/24.011 | TS 23.040 + R17 NTN | 无标准 |
六、Android 关键代码与配置位置
6.1 核心类索引
| 类 | 路径 | 卫星 SMS 职责 |
|---|---|---|
| SmsDispatchersController | SmsDispatchersController.java | SMS 路由决策:NTN 漫游→DatagramDispatcher,否则→标准路径 |
| DatagramDispatcher | DatagramDispatcher.java | 卫星 SMS 发送协调:队列管理、串行发送、MT SMS 轮询 |
| DatagramReceiver | DatagramReceiver.java | 卫星数据报接收:轮询、ACK 管理、重试投递 |
| DatagramController | DatagramController.java | 数据报收发状态管理、SMS 接收通知 |
| SatelliteController | SatelliteController.java | NTN 漫游判断、SMS 服务策略、P2P 禁用判断 |
| SatelliteModemInterface | SatelliteModemInterface.java | HAL 接口:sendDatagram/pollDatagrams |
| ImsSmsDispatcher | telephony/imsphone/ImsSmsDispatcher.java | NTN SMS 最终通过 IMS SMS 通道发送 |
6.2 关键方法索引
| 方法 | 类 | 行号 | 说明 |
|---|---|---|---|
shouldSendSmsToDatagramDispatcher() | SatelliteController | L9773 | 判断 SMS 是否应走卫星路径 |
isInCarrierRoamingNbIotNtn() | SatelliteController | L4816 | 判断是否在 NTN 漫游模式 |
isP2PSmsDisallowedOnCarrierRoamingNtn() | SatelliteController | L9594 | P2P SMS 是否被禁用 |
shouldDropSms() | SatelliteController | L9792 | SMS 是否应被丢弃 |
sendSms() | DatagramDispatcher | L1151 | 卫星 SMS 发送入口 |
handleEventSendSmsDone() | DatagramDispatcher | L1282 | SMS 发送结果处理 |
sendMtSmsPollingMessage() | SmsDispatchersController | L2264 | MT SMS 轮询消息发送 |
allowMtSmsPolling() | DatagramDispatcher | L1404 | MT SMS 轮询允许判断 |
sendCarrierRoamingNbIotNtnText() | SmsDispatchersController | L2240 | NTN SMS 发送到标准 SMS 栈 |
onSmsReceived() | DatagramController | L375 | SMS 接收状态通知 |
pollPendingSatelliteDatagrams() | SatelliteModemInterface | L907 | 轮询待收数据报 |
onSatelliteDatagramReceived() | DatagramReceiver | L320 | 数据报投递到应用 |
6.3 关键配置
| 配置 | 类型 | 说明 |
|---|---|---|
config_enabled_mt_sms_polling | bool | 是否启用 MT SMS 轮询 |
config_mt_sms_polling_throttle_millis | integer | MT SMS 轮询节流时间 |
config_mt_sms_polling_text | string | MT SMS 轮询消息文本 |
config_timeout_to_receive_delivered_ack_millis | integer | 数据报 ACK 超时(默认5分钟) |
KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT | CarrierConfig | NTN 连接类型(MANUAL/AUTO) |
KEY_SATELLITE_NTN_SMS_SUPPORTED_BOOL | CarrierConfig | 是否支持 NTN SMS |
6.4 数据报类型常量
| 常量 | 值 | 说明 |
|---|---|---|
DATAGRAM_TYPE_SOS_MESSAGE | 0 | SOS 紧急消息 |
DATAGRAM_TYPE_LOCATION_SHARING | 1 | 位置共享 |
DATAGRAM_TYPE_KEEP_ALIVE | 2 | 保活消息 |
DATAGRAM_TYPE_SMS | 3 | P2P SMS(运营商 NTN) |
DATAGRAM_TYPE_CHECK_PENDING_INCOMING_SMS | 4 | MT SMS 轮询 |
七、调试与测试建议
7.1 logcat 标签
# 卫星 SMS 发送
adb logcat -s DatagramDispatcher
adb logcat -s SmsDispatchersController
# 卫星 SMS 接收
adb logcat -s DatagramReceiver
adb logcat -s DatagramController
# 卫星状态判断
adb logcat -s SatelliteController
# HAL 交互
adb logcat -s SatelliteModemInterface
# 标准 SMS 栈
adb logcat -s ImsSmsDispatcher
adb logcat -s GsmInboundSmsHandler
7.2 dumpsys 命令
# 卫星整体状态
adb shell dumpsys satellite
# SMS 相关状态
adb shell dumpsys isub
adb shell dumpsys phone
# 数据报数据库
adb shell content query --uri content://satellite_datagrams
7.3 关键日志过滤
# SMS 路由判断
adb logcat | grep "shouldSendSmsToDatagramDispatcher"
adb logcat | grep "isInCarrierRoamingNbIotNtn"
# SMS 发送流程
adb logcat | grep "CMD_SEND_SMS"
adb logcat | grep "handleEventSendSmsDone"
adb logcat | grep "sendCarrierRoamingNbIotNtnText"
# MT SMS 轮询
adb logcat | grep "CMD_SEND_MT_SMS_POLLING_MESSAGE"
adb logcat | grep "allowMtSmsPolling"
adb logcat | grep "startMtSmsPollingThrottle"
# 数据报接收
adb logcat | grep "EVENT_SATELLITE_DATAGRAM_RECEIVED"
adb logcat | grep "EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM"
adb logcat | grep "pollPendingSatelliteDatagrams"
7.4 CTS 测试
// SmsDispatchersControllerTest.java
@Test
public void testSendSmsToDatagramDispatcher() {
when(mSatelliteController.shouldSendSmsToDatagramDispatcher(any(Phone.class)))
.thenReturn(true);
mSmsDispatchersController.sendText("1111", "2222", "text", ...);
processAllMessages();
verify(mMockDatagramDispatcher).sendSms(any());
}
@Test
public void testSendCarrierRoamingNbIotNtnText() {
PendingRequest pendingRequest = createPendingRequest();
switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
mSmsDispatchersController.sendCarrierRoamingNbIotNtnText(pendingRequest);
processAllMessages();
verify(mSimulatedCommandsVerifier, times(1)).sendImsGsmSms(...);
}
总结:Android 16 的卫星 SMS 实现体现了精巧的双路径设计:
-
运营商 NTN 漫游 SMS:完全复用标准
SmsManagerAPI,应用无需任何修改。SmsDispatchersController在检测到 NTN 漫游状态后,将 SMS 路由到DatagramDispatcher协调发送,最终仍通过ImsSmsDispatcher→ RIL → Modem 的标准 SMS 协议栈完成。MT SMS 则通过创新的主动轮询机制(终端给自己发 SMS 触发 SMSC 下发待收消息)解决卫星网络无法实时 Paging 的问题。 -
OEM 卫星数据报:使用独立的
SatelliteManager.sendDatagram()API,消息由应用自行编码加密,框架不解析内容,通过SatelliteModemInterface→ HAL → Modem 发送。接收采用pollPendingSatelliteDatagrams()轮询拉取,配合应用层 ACK 和5分钟超时重试机制保证可靠投递。
报告已完成。核心发现是 Android 16 卫星 SMS 的双路径架构:
-
运营商 NTN 漫游 SMS:对应用完全透明,
SmsDispatchersController自动检测 NTN 漫游状态后将 SMS 路由到DatagramDispatcher协调,最终仍走标准ImsSmsDispatcher→ RIL 路径。最独特的设计是 MT SMS 主动轮询机制——终端给自己发一条 SMS,触发 SMSC 下发所有待收消息,解决了卫星网络无法实时 Paging 的根本问题。 -
OEM 卫星数据报:使用独立的
SatelliteManager.sendDatagram()API,消息由应用自行编码加密,通过SatelliteModemInterface→ HAL 发送,接收采用轮询拉取 + 5分钟 ACK 超时重试。