一、调用链全景图
┌─────────────────────────────────────────────────────────────────────┐
│ 应用层 (App) │
│ TelephonyManager.customRequest(request, extrasData, executor, cb) │
└──────────────────────────────┬──────────────────────────────────────┘
│ Binder IPC (ITelephony)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Telephony 服务层 (PhoneInterfaceManager) │
│ PhoneInterfaceManager.customRequest(request, extrasData, callback) │
│ → sendRequestAsync(CMD_CUSTOM_REQUEST, argument, xwPhone, null) │
└──────────────────────────────┬──────────────────────────────────────┘
│ MainHandler 消息机制
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Phone 抽象层 │
│ Phone.customRequest(request, extrasData, response) │
│ → mCi.customRequest(request, extrasData, response) │
└──────────────────────────────┬──────────────────────────────────────┘
│ CommandsInterface 接口
▼
┌─────────────────────────────────────────────────────────────────────┐
│ RIL Java 层 │
│ RIL.customRequest(request, extrasData, result) │
│ → xwRadioProxy.customRequest(serial, request, extrasData) │
└──────────────────────────────┬──────────────────────────────────────┘
│ HIDL/AIDL IPC
▼
┌─────────────────────────────────────────────────────────────────────┐
│ RIL HAL 层 (vendor.xwos.hardware.radio.IXwRadio) │
│ IXwRadio.sendCustomRequest(serial, request, extrasData) │
│ → Modem CP 执行请求 │
└──────────────────────────────┬──────────────────────────────────────┘
│ HAL 响应回调
▼
┌─────────────────────────────────────────────────────────────────────┐
│ RIL 响应处理 │
│ XwRadioResponse.sendCustomRequestResponse(info, result, extrasData)│
│ → 构造 CustomResponse → processResponseDone → Message 回调 │
└──────────────────────────────┬──────────────────────────────────────┘
│ Handler 消息 (EVENT_CUSTOM_REQUEST_DONE)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ PhoneInterfaceManager 响应处理 │
│ EVENT_CUSTOM_REQUEST_DONE → CustomRequestCallback.onResult() │
│ → ICustomRequestCallback.onResult(errorno, result, extrasData) │
└──────────────────────────────┬──────────────────────────────────────┘
│ Binder IPC 回调
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 应用层回调 │
│ CustomRequestCallback.onResult(errorno, result, extrasData) │
└─────────────────────────────────────────────────────────────────────┘
二、各层详细实现分析
第1层:TelephonyManager(应用层入口)
文件: TelephonyManager.java:17506-17530
public void customRequest(int request, @NonNull byte[] extrasData, @NonNull Executor executor,
@NonNull CustomRequestCallback callback) {
Objects.requireNonNull(extrasData);
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
ICustomRequestCallback aidlCustomRequest = new ICustomRequestCallback.Stub() {
@Override
public void onResult(int errorno, int result, byte[] extrasData) {
final long identity = Binder.clearCallingIdentity();
try {
executor.execute(() -> callback.onResult(errorno, result, extrasData));
} finally {
Binder.restoreCallingIdentity(identity);
}
}
};
try {
ITelephony telephony = getITelephony();
if (telephony != null)
telephony.customRequest(request, extrasData, aidlCustomRequest);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#customRequest", e);
}
}
关键设计点:
-
回调 适配器模式:将应用层的
CustomRequestCallback接口适配为 AIDL 的ICustomRequestCallback.Stub,实现跨进程回调 -
线程切换:通过
Executor参数,将 Binder 回调线程的结果切换到应用指定的执行线程 -
Binder 身份清理:
Binder.clearCallingIdentity()确保回调执行时使用本地进程权限,而非远程调用者权限 -
参数校验:三个
@NonNull参数均进行Objects.requireNonNull校验
回调 接口定义:
public interface CustomRequestCallback {
// errorno: 详情见 RILConstants.java
// result: RIL event数据
// extrasData: 附加数据
public void onResult(int errorno, int result, byte[] extrasData);
}
第2层:ITelephony AIDL 接口(跨进程通信桥梁)
void customRequest(int request, in byte[] extrasData, ICustomRequestCallback resultCallback);
AIDL 回调 接口:ICustomRequestCallback.aidl
oneway interface ICustomRequestCallback {
void onResult(int errorno, int result, in @nullable byte[] extrasData);
}
关键设计点:
-
回调接口标记为
oneway,表示异步调用,不阻塞 RIL 服务端线程 -
extrasData标记为@nullable,允许返回空数据 -
byte[]使用in方向标记,表示从服务端向客户端传递
第3层:PhoneInterfaceManager(Telephony 服务端实现)
文件: PhoneInterfaceManager.java:12138-12173
@Override
public void customRequest(int request, byte[] extrasData, ICustomRequestCallback resultCallback) {
Log.d(LOG_TAG, "customRequest uid " + Binder.getCallingUid() + " pid " + Binder.getCallingPid() +
" request "+ request + " extrasData " + extrasData);
final long identity = Binder.clearCallingIdentity();
try {
final Phone xwPhone = PhoneFactory.getPhone(TelephonyManager.getDefault().getSatellitePhoneId());
if (xwPhone == null) {
try {
resultCallback.onResult(RILConstants.OEM_ERROR_1, CUSTOM_EVENT_UNKNOWN, null);
} catch (RemoteException e) {}
return;
}
Pair<Pair<Integer, byte[]>, TelephonyManager.CustomRequestCallback> argument =
Pair.create(Pair.create(request, extrasData), new TelephonyManager.CustomRequestCallback() {
@Override
public void onResult(int errorno, int result, @Nullable byte[] extrasData) {
try {
Log.d(LOG_TAG, "customRequest errorno :" + errorno + " result:" + result);
resultCallback.onResult(errorno, result, extrasData);
} catch (RemoteException e) {}
}
});
sendRequestAsync(CMD_CUSTOM_REQUEST, argument, xwPhone, null);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
关键设计点:
-
获取卫星电话实例:通过
PhoneFactory.getPhone(TelephonyManager.getDefault().getSatellitePhoneId())获取 XW 卫星通信 Phone 实例,说明 customRequest 专用于卫星通信模块 -
空实例保护:当 xwPhone 为 null 时,直接返回
OEM_ERROR_1错误码和CUSTOM_EVENT_UNKNOWN(-1)结果 -
参数封装:使用嵌套
Pair结构封装请求参数和回调,外层 Pair 的 first 是(request, extrasData),second 是CustomRequestCallback -
异步发送:通过
sendRequestAsync将请求投递到主线程 Handler 处理 -
Binder 身份管理:
clearCallingIdentity/restoreCallingIdentity确保以系统权限执行
主线程 Handler 处理:PhoneInterfaceManager.java:2483-2513
case CMD_CUSTOM_REQUEST: {
request = (MainThreadRequest) msg.obj;
onCompleted = obtainMessage(EVENT_CUSTOM_REQUEST_DONE, request);
Pair<Pair<Integer, byte[]>, TelephonyManager.CustomRequestCallback> args =
(Pair<Pair<Integer, byte[]>, TelephonyManager.CustomRequestCallback>)
request.argument;
int requestId = args.first.first;
byte[] extrasData = args.first.second;
request.phone.customRequest(requestId, extrasData, onCompleted);
break;
}
case EVENT_CUSTOM_REQUEST_DONE: {
ar = (AsyncResult) msg.obj;
request = (MainThreadRequest) ar.userObj;
TelephonyManager.CustomRequestCallback callback =
((Pair<Pair<Integer, byte[]>, TelephonyManager.CustomRequestCallback>)
request.argument).second;
CustomResponse result = (CustomResponse) ar.result;
int err = RILConstants.SUCCESS;
if (ar.exception != null && ar.exception instanceof CommandException) {
err = ((CommandException)ar.exception).getCommandError().ordinal();
} else if (ar.exception != null) {
err = RILConstants.OEM_ERROR_1;
}
if (ar.result == null) {
callback.onResult(err, CUSTOM_EVENT_UNKNOWN, null);
break;
}
callback.onResult(err, result.result, result.extrasData);
break;
}
响应处理流程:
-
从
AsyncResult中提取CustomResponse对象 -
异常分类处理:
CommandException→ 转换为对应错误码 ordinal;其他异常 →OEM_ERROR_1 -
空结果保护:
ar.result == null时返回CUSTOM_EVENT_UNKNOWN -
正常路径:从
CustomResponse提取result和extrasData回调给应用
第4层:Phone 抽象层
public void customRequest(int request, byte[] extrasData, Message response) {
mCi.customRequest(request, extrasData, response);
}
设计说明:
-
Phone 层是纯粹的委托模式,将请求直接转发给
mCi(CommandsInterface 实例,即 RIL 对象) -
Message response参数用于接收 RIL 层的异步响应
第5层:CommandsInterface 接口定义
文件: CommandsInterface.java:2269
public void customRequest(int request, byte[] extrasData, Message result);
BaseCommands 默认实现:BaseCommands.java:1076-1078
@Override
public void customRequest(int request, byte[] extrasData, Message result) {
// 空实现,由 RIL 子类覆写
}
第6层:RIL Java 层(核心实现)
@Override
public void customRequest(int request, byte[] extrasData, Message result) {
XwRadioProxy xwRadioProxy = getRadioServiceProxy(XwRadioProxy.class, result);
if (!xwRadioProxy.isEmpty()) {
RILRequest rr = obtainRequest(RIL_XW_REQUEST_SEND_CUSTOM_REQUEST, result, mRILDefaultWorkSource);
if (RILJ_LOGD) {
riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
}
try {
xwRadioProxy.customRequest(rr.mSerial, request, extrasData);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(XW_SERVICE, "customRequest", e);
}
}
}
关键设计点:
-
RIL 请求封装:通过
obtainRequest(RIL_XW_REQUEST_SEND_CUSTOM_REQUEST, ...)创建RILRequest对象,分配唯一序列号mSerial,用于请求-响应匹配 -
RIL 请求 ID:使用
RIL_XW_REQUEST_SEND_CUSTOM_REQUEST(值为80016,定义于 XWRadioConstants.java),这是 XW 卫星通信专用的 RIL 请求码 -
XwRadioProxy 代理:通过
getRadioServiceProxy获取 XW 无线电代理,与 HAL 层通信 -
异常处理:
RemoteException(HAL 服务不可用)和RuntimeException统一由handleRadioProxyExceptionForRR处理
第7层:XwRadioProxy(HAL 代理层)
public void customRequest(int serial, int request, byte[] extrasData) throws RemoteException {
if (isEmpty()) return;
if (isAidl()) {
mXwRadioProxy.sendCustomRequest(serial, request, extrasData);
} else {
Rlog.e(TAG, "mXwRadioProxy error");
}
}
关键设计点:
-
AIDL 优先:仅支持 AIDL 方式调用(
isAidl()检查),不提供 HIDL 回退 -
HAL 接口:调用
vendor.xwos.hardware.radio.IXwRadio.sendCustomRequest(),这是厂商自定义的 HAL 接口 -
参数透传:将
serial(请求序列号)、request(自定义请求 ID)、extrasData(附加数据)直接传递给 HAL 层
第8层:XwRadioResponse(HAL 响应处理)
文件: XwRadioResponse.java:138-155
public void sendCustomRequestResponse(XwRadioResponseInfo info, int result, byte[] extrasData) {
RadioResponseInfo responseInfo = new RadioResponseInfo();
responseInfo.type = info.type;
responseInfo.serial = info.serial;
responseInfo.error = info.error;
RILRequest rr = mRil.processResponse(RIL.XW_SERVICE, responseInfo);
if (rr != null) {
CustomResponse ret = new CustomResponse();
ret.result = result;
ret.extrasData = extrasData;
if (responseInfo.error == XwRadioError.NONE) {
RadioResponse.sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
}
}
关键设计点:
-
响应信息转换:将
XwRadioResponseInfo(HAL 层)转换为RadioResponseInfo(Framework 层) -
请求匹配:通过
processResponse根据serial匹配原始请求的RILRequest -
CustomResponse 构造:将 HAL 返回的
result和extrasData封装为 CustomResponse 对象 -
成功路径:仅当
error == NONE时,通过sendMessageResponse将结果发送到原始Message目标 -
完成处理:
processResponseDone释放 RILRequest 资源并触发错误处理(如有)
CustomResponse 数据结构:
public class CustomResponse {
public int result; // RIL event 数据(整型结果)
public byte[] extrasData; // 附加数据(可变长度字节流)
}
三、参数传递机制详解
| 层级 | request 参数 | extrasData 参数 | 返回值机制 |
|---|---|---|---|
| TelephonyManager | int request (XWRadioConstants中的请求ID) | byte[] extrasData | CustomRequestCallback.onResult(errorno, result, extrasData) |
| ITelephony (AIDL) | int request | in byte[] extrasData | ICustomRequestCallback.onResult(errorno, result, extrasData) |
| PhoneInterfaceManager | int request | byte[] extrasData | 通过 Pair 封装回调 |
| Phone | int request | byte[] extrasData | Message response (异步) |
| RIL | int request | byte[] extrasData | RILRequest + Message |
| XwRadioProxy | int serial, int request | byte[] extrasData | HAL AIDL 回调 |
| HAL (IXwRadio) | int serial, int request | byte[] extrasData | IXwRadioResponse.sendCustomRequestResponse |
| XwRadioResponse | — | int result, byte[] extrasData | CustomResponse → Message |
request 参数的分层含义
request 参数在不同层级有不同语义:
-
应用层:使用 XWRadioConstants.java 定义的
CUSTOM_REQUEST_SET_*/CUSTOM_REQUEST_GET_*等常量(范围 0-59, 0x100000+, 0x200000+) -
RIL 层:统一封装为
RIL_XW_REQUEST_SEND_CUSTOM_REQUEST(80016),request作为该请求的子命令参数传递给 HAL -
HAL 层:将
request透传给 Modem CP 执行
四、核心作用分析
1. 统一的卫星通信扩展接口
customRequest 的核心设计理念是提供一个通用的"管道"式请求通道,避免为每个卫星通信功能都单独定义一套从 TelephonyManager → RIL → HAL 的完整调用链。它通过 request ID 区分不同的子功能,通过 byte[] extrasData 承载可变结构的请求数据,实现了:
-
接口稳定性:Framework 层接口不变,新增功能只需在
XWRadioConstants中定义新的 request ID -
扩展灵活性:
byte[] extrasData可以承载任意序列化数据结构 -
维护成本低:新增功能无需修改 TelephonyManager、ITelephony、Phone、RIL 等多层代码
2. 卫星通信专用通道
从代码中可以明确看到,customRequest 专用于 XW 卫星通信模块:
-
PhoneFactory.getPhone(TelephonyManager.getDefault().getSatellitePhoneId())— 获取卫星通信 Phone 实例 -
使用
XwRadioProxy— XW 专用无线电代理 -
RIL 请求码
RIL_XW_REQUEST_SEND_CUSTOM_REQUEST— XW 专用请求
3. 双向通信机制
customRequest 处理请求-响应模式(solicited),而配套的 CustomEvent 机制处理主动上报模式(unsolicited):
-
请求-响应:
customRequest→sendCustomRequestResponse -
主动上报:
XwRadioIndication.onCustomEvent→BaseCommands.customNotify→ICustomEventListener.onEvent
五、典型应用场景
根据 XWRadioConstants.java 中的定义,customRequest 覆盖以下业务场景:
1. 卫星网络管理
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_SET_CREGXW (1) | 设置卫星网络注册状态 | SET |
CUSTOM_REQUEST_GET_CREGXW (101) | 查询卫星网络注册状态 | GET |
CUSTOM_REQUEST_SET_CARRIERMODEXW (25) | 设置窄带终端载波模式 | SET |
CUSTOM_REQUEST_GET_CARRIERMODEXW (136) | 查询窄带终端载波模式 | GET |
CUSTOM_REQUEST_SET_REGIONXW (26) | 设置终端部署区域 | SET |
2. 通信质量控制
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_SET_CQOSXW (2) | 设置卫星服务质量 | SET |
CUSTOM_REQUEST_SET_TXPOWERXW (11) | 设置终端发射功率 | SET |
CUSTOM_REQUEST_SET_NETWORKRATEXW (12) | 设置终端上下行速率 | SET |
CUSTOM_REQUEST_SET_AGCGAINXW (36) | 设置AGC增益参数 | SET |
CUSTOM_REQUEST_SET_APCGAINXW (37) | 设置APC增益参数 | SET |
3. 导航与定位
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_SET_POSTIMEXW (5) | 设置位置与时间 | SET |
CUSTOM_REQUEST_GET_POSTIMEXW (106) | 查询位置与时间 | GET |
CUSTOM_REQUEST_SET_SSRINFOXW (6) | 设置导航增强业务 | SET |
CUSTOM_REQUEST_SET_EPHEMXW (8) | 设置星历信息 | SET |
4. 安全与设备管理
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_EXECUTE_STUN (40) | 摇晕(远程禁用) | SET |
CUSTOM_REQUEST_EXECUTE_KILL (41) | 摇毙(远程销毁) | SET |
CUSTOM_REQUEST_SET_CSCNSECXW (19) | 设置CSCN安全开关 | SET |
CUSTOM_REQUEST_GET_DEVKEY (121) | 获取设备秘钥 | GET |
CUSTOM_REQUEST_GET_DEVCERT (122) | 获取设备证书 | GET |
5. 物联网数据传输
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_SET_IOTULDATAXW (34) | 发送物联网上行数据包 | SET |
CUSTOM_REQUEST_GET_IOTDLDATAXW (148) | 接收物联网下行数据包 | GET |
CUSTOM_REQUEST_SET_SERVQOSXW (33) | 设置业务类型和QOS要求 | SET |
6. 设备维护与升级
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_SET_CPOTAXW (15) | 通知终端CP进行软件版本升级 | SET |
CUSTOM_REQUEST_SET_REBOOTXW (10) | 终端CP重启 | SET |
CUSTOM_REQUEST_SET_ANTOTAXW (28) | 终端天线软件升级 | SET |
7. 透传与测试
| 请求 ID | 功能 | 类型 |
|---|---|---|
CUSTOM_REQUEST_AT_PASSTHROUGH (155) | AT指令透传 | GET |
CUSTOM_REQUEST_OTA_PASSTHROUGH (156) | OTA透传 | GET |
CUSTOM_REQUEST_BYPASS_PASSTHROUGH (157) | 自动化测试 | GET |
六、性能与兼容性考量
性能特征
-
全链路异步设计:从 TelephonyManager 到 HAL 层,整个调用链均为异步模式,不会阻塞调用线程
-
Binder IPC 开销:应用→TelephonyService 需要两次 Binder 调用(请求 + 回调),对于高频调用场景需注意 Binder 缓冲区压力
-
Handler 消息队列:PhoneInterfaceManager 使用主线程 Handler 处理请求,若主线程繁忙可能导致延迟
-
byte[]序列化开销:extrasData 的序列化/反序列化在跨进程传输时有内存拷贝开销,大数据量场景需谨慎
兼容性考量
-
HAL 版本依赖:XwRadioProxy 仅支持 AIDL 模式(
isAidl()检查),不支持 HIDL 回退,这意味着需要较新的 HAL 版本 -
request ID 向后兼容:新增 request ID 时,旧版本 HAL 可能无法识别,需要在 HAL 层返回
REQUEST_NOT_SUPPORTED错误码 -
extrasData 结构兼容:
byte[]是无类型的数据容器,其内部结构依赖调用方和 HAL 层的约定,缺乏版本协商机制,升级时需注意前后兼容 -
卫星 Phone 可用性:
getSatellitePhoneId()可能返回无效 ID,导致PhoneFactory.getPhone()返回 null,调用方需处理此场景 -
权限模型:PhoneInterfaceManager 中未对 customRequest 做显式权限检查,依赖调用者 UID/PID 隐式控制,安全强度有限
七、总结
customRequest 是一个专为 XW 卫星通信系统设计的通用扩展请求通道,其架构设计体现了以下核心思想:
-
管道化设计:通过
request ID + byte[]的组合,将 Framework 层的接口稳定性与 HAL 层的功能扩展性解耦,新增卫星通信功能无需修改多层 Framework 代码 -
全异步架构:从应用层到 HAL 层,整条链路采用异步回调模式,保障了通信请求不会阻塞 UI 线程
-
专用通道隔离:独立于标准 Android telephony 请求通道(使用
XwRadioProxy和RIL_XW_REQUEST_SEND_CUSTOM_REQUEST),避免与常规蜂窝通信逻辑产生干扰 -
请求-事件双模型:
customRequest处理主动请求,CustomEvent机制处理被动上报,共同构成完整的卫星通信交互模型
该机制覆盖了卫星网络注册、通信质量控制、导航定位、安全管控、物联网数据传输、设备维护升级、AT/OTA 透传等 7 大类近 60 个具体功能请求,是 XW 卫星通信框架中最为核心的通用接口。