customRequest详解

7 阅读11分钟

一、调用链全景图

┌─────────────────────────────────────────────────────────────────────┐
│  应用层 (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 接口(跨进程通信桥梁)

文件: ITelephony.aidl:2604

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;
}

响应处理流程

  1. AsyncResult 中提取 CustomResponse 对象

  2. 异常分类处理:CommandException → 转换为对应错误码 ordinal;其他异常 → OEM_ERROR_1

  3. 空结果保护:ar.result == null 时返回 CUSTOM_EVENT_UNKNOWN

  4. 正常路径:从 CustomResponse 提取 resultextrasData 回调给应用


第4层:Phone 抽象层

文件: Phone.java:4659-4660

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 层(核心实现)

文件: RIL.java:4589-4603

@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 代理层)

文件: XwRadioProxy.java:186-193

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 返回的 resultextrasData 封装为 CustomResponse 对象

  • 成功路径:仅当 error == NONE 时,通过 sendMessageResponse 将结果发送到原始 Message 目标

  • 完成处理processResponseDone 释放 RILRequest 资源并触发错误处理(如有)

CustomResponse 数据结构

public class CustomResponse {
    public int result;        // RIL event 数据(整型结果)
    public byte[] extrasData; // 附加数据(可变长度字节流)
}

三、参数传递机制详解

层级request 参数extrasData 参数返回值机制
TelephonyManagerint request (XWRadioConstants中的请求ID)byte[] extrasDataCustomRequestCallback.onResult(errorno, result, extrasData)
ITelephony (AIDL)int requestin byte[] extrasDataICustomRequestCallback.onResult(errorno, result, extrasData)
PhoneInterfaceManagerint requestbyte[] extrasData通过 Pair 封装回调
Phoneint requestbyte[] extrasDataMessage response (异步)
RILint requestbyte[] extrasDataRILRequest + Message
XwRadioProxyint serial, int requestbyte[] extrasDataHAL AIDL 回调
HAL (IXwRadio)int serial, int requestbyte[] extrasDataIXwRadioResponse.sendCustomRequestResponse
XwRadioResponseint result, byte[] extrasDataCustomResponseMessage

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):

  • 请求-响应customRequestsendCustomRequestResponse

  • 主动上报XwRadioIndication.onCustomEventBaseCommands.customNotifyICustomEventListener.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

六、性能与兼容性考量

性能特征

  1. 全链路异步设计:从 TelephonyManager 到 HAL 层,整个调用链均为异步模式,不会阻塞调用线程

  2. Binder IPC 开销:应用→TelephonyService 需要两次 Binder 调用(请求 + 回调),对于高频调用场景需注意 Binder 缓冲区压力

  3. Handler 消息队列:PhoneInterfaceManager 使用主线程 Handler 处理请求,若主线程繁忙可能导致延迟

  4. byte[] 序列化开销:extrasData 的序列化/反序列化在跨进程传输时有内存拷贝开销,大数据量场景需谨慎

兼容性考量

  1. HAL 版本依赖:XwRadioProxy 仅支持 AIDL 模式(isAidl() 检查),不支持 HIDL 回退,这意味着需要较新的 HAL 版本

  2. request ID 向后兼容:新增 request ID 时,旧版本 HAL 可能无法识别,需要在 HAL 层返回 REQUEST_NOT_SUPPORTED 错误码

  3. extrasData 结构兼容byte[] 是无类型的数据容器,其内部结构依赖调用方和 HAL 层的约定,缺乏版本协商机制,升级时需注意前后兼容

  4. 卫星 Phone 可用性getSatellitePhoneId() 可能返回无效 ID,导致 PhoneFactory.getPhone() 返回 null,调用方需处理此场景

  5. 权限模型:PhoneInterfaceManager 中未对 customRequest 做显式权限检查,依赖调用者 UID/PID 隐式控制,安全强度有限

七、总结

customRequest 是一个专为 XW 卫星通信系统设计的通用扩展请求通道,其架构设计体现了以下核心思想:

  1. 管道化设计:通过 request ID + byte[] 的组合,将 Framework 层的接口稳定性与 HAL 层的功能扩展性解耦,新增卫星通信功能无需修改多层 Framework 代码

  2. 全异步架构:从应用层到 HAL 层,整条链路采用异步回调模式,保障了通信请求不会阻塞 UI 线程

  3. 专用通道隔离:独立于标准 Android telephony 请求通道(使用 XwRadioProxyRIL_XW_REQUEST_SEND_CUSTOM_REQUEST),避免与常规蜂窝通信逻辑产生干扰

  4. 请求-事件双模型customRequest 处理主动请求,CustomEvent 机制处理被动上报,共同构成完整的卫星通信交互模型

该机制覆盖了卫星网络注册、通信质量控制、导航定位、安全管控、物联网数据传输、设备维护升级、AT/OTA 透传等 7 大类近 60 个具体功能请求,是 XW 卫星通信框架中最为核心的通用接口。