1. ATcmdFwd 项目背景与需求解析
在Android Go设备开发过程中,我们遇到了一个关键需求:需要实现AT命令从Modem到AP(应用处理器)的转发功能。AT命令作为移动通信设备中最基础的交互协议,通常用于设备控制、状态查询和参数配置。但在Android Go这类资源受限的设备上,高通基线默认并未预制这一功能模块。
核心需求可以拆解为:
- 实现AT命令从Modem到AP的可靠转发机制
- 适配Android Go系统的特殊编译环境
- 确保转发过程中的数据完整性和稳定性
项目涉及两个关键进程:
- ATFWD-daemon:运行在后台的守护进程,负责命令转发核心逻辑
- atfwd apk:提供上层接口的Android应用
2. 环境配置与编译修改
2.1 基线代码修改要点
在Android Go设备上启用AT命令转发功能,需要修改两处关键配置:
makefile复制# 文件路径:vendor/qcom/proprietary/commonsys/telephony-build/build/telephony_system_product.mk
# 原配置:
ifneq ($(TARGET_HAS_LOW_RAM),true)
TELEPHONY_APPS += atfwd
endif
# 修改后:
TELEPHONY_APPS += atfwd
makefile复制# 文件路径:vendor/qcom/proprietary/telephony-apps/ATFWD-daemon/Android.mk
# 需要完全移除ifneq条件判断,确保在低内存设备上也能编译
重要提示:这些修改会直接影响系统镜像的构建结果,建议在修改后执行clean build以确保变更生效。
2.2 编译验证步骤
- 执行
source build/envsetup.sh初始化编译环境 - 使用
lunch选择正确的目标设备 - 运行
make -j$(nproc)开始完整编译 - 重点检查以下输出:
out/target/product/[设备名]/system/bin/Atfwd_Daemon是否存在out/target/product/[设备名]/system/priv-app/atfwd/atfwd.apk是否生成
3. AT命令添加与实现细节
3.1 新增AT命令流程
参考高通文档KBA-170914180912_REV_4,添加新AT命令的标准流程如下:
- 在Modem侧注册新AT命令处理函数
- 更新AP侧命令映射表
- 配置命令转发白名单
- 实现AP侧处理逻辑
典型实现示例:
c复制// 在Modem侧添加命令处理
void dsat_process_custom_cmd(dsat_result_enum_type *result)
{
*result = DSAT_OK;
// 自定义处理逻辑
}
// AP侧命令映射
static const AtCmd custom_cmds[] = {
{OPCODE_CUSTOM, "CUSTOM", 0, NULL},
{0, NULL, 0, NULL}
};
3.2 命令转发白名单配置
有两种方式配置转发白名单:
- 代码硬编码方式:
c复制// 文件路径:modem_proc/datamodem/interface/atcop/src/dsatclient_ex.c
LOCAL byte allowed_list[][MAX_CMD_SIZE] = {
"+CLVL", "+CKPD", "+CMUT", "+CTSA",
"+CBKLT", "+CFUN", "+CDIS", "+CRSL",
"+CMAR", "+CSO", "+CSS", "+CBC",
"$QCPWRDN", "CUSTOM", "" // 新增自定义命令
};
- EFS文件配置方式:
创建/ds/atcop/strings/allowed_list_efs.txt文件,内容为:
code复制+CLVL +CKPD +CMUT +CTSA +CBKLT +CFUN +CDIS +CRSL +CMAR +CSO +CSS +CBC $QCPWRDN CUSTOM
经验分享:EFS配置方式更灵活,适合量产后的命令调整,无需重新编译固件。
4. 关键问题分析与解决方案
4.1 响应长度限制问题
问题现象:
code复制12-20 14:18:53.373 F libc : FORTIFY: memcpy: prevented 162-byte write into 100-byte buffer
根本原因:
QMI协议层对AT命令响应长度有严格限制,默认定义为100字节:
c复制// 文件:access_terminal_service_v01.h
#define QMI_AT_CMD_RESP_LEN_MAX_V01 100
完整解决方案:
- 修改AP侧定义:
c复制// 文件:access_terminal_service_v01.h
#define QMI_AT_CMD_RESP_LEN_MAX_V01 200
- 同步修改Modem侧配置:
c复制// 文件:access_terminal_service_v01.c
// 修改结构体偏移量对应的长度限制
- 验证修改:
- 编译后测试长响应AT命令
- 检查
Atfwd_Daemon日志确认无溢出错误
避坑指南:单纯修改宏定义可能导致QMI错误-45,必须确保AP和Modem两侧定义完全一致。
4.2 Syscall限制问题
错误日志:
code复制12-15 14:42:08.962 E ATFWD-daemon: libminijail[909]: blocked syscall: ugetrlimit
解决方案:
修改seccomp策略文件:
text复制# 文件路径:ATFWD-daemon/seccomp_policy/atfwd@2.0-arm.policy
ugetrlimit: 1
深度解析:
Android的seccomp机制会限制进程可用的系统调用。对于需要获取资源限制信息的守护进程,必须明确允许ugetrlimit调用。
4.3 AT命令操作类型解析
AT命令支持多种操作类型,通过opcode区分:
c复制#define QMI_ATCOP_NA 0x00000001 // 无参数操作
#define QMI_ATCOP_EQ 0x00000002 // 带参数操作
#define QMI_ATCOP_QU 0x00000004 // 查询操作
#define QMI_ATCOP_AR 0x00000008 // 异步响应
典型处理逻辑:
c复制void process_at_cmd(AtCmd *cmd) {
switch(cmd->opcode) {
case QMI_ATCOP_QU:
// 处理查询请求
break;
case QMI_ATCOP_AR:
// 处理设置请求
for(int i=0; i<cmd->ntokens; i++) {
process_token(cmd->tokens[i]);
}
break;
}
}
5. 性能优化与稳定性保障
5.1 内存管理最佳实践
在AT命令转发过程中,需要特别注意内存管理:
- 响应缓冲区分配:
c复制char *resp = malloc(QMI_AT_MAX_RESP_MSG_SIZE);
if(!resp) {
LOGE("Memory allocation failed");
return QMI_ATCOP_RESULT_ERROR;
}
- 内存释放检查:
c复制if (atCmdResponse.at_resp != NULL) {
free(atCmdResponse.at_resp);
atCmdResponse.at_resp = NULL; // 避免悬垂指针
}
5.2 转发命令数量扩展
默认转发命令数量限制为50条,可通过修改以下定义扩展:
c复制// 文件:qmi_atcop_srvc.h
#define QMI_ATCOP_MAX_AT_CMDS_REG 100 // 从50增加到100
修改后需要:
- 同步更新Modem侧配置
- 重新编译AP和Modem镜像
- 更新EFS白名单文件
5.3 异常处理机制
完善的错误处理应包括:
c复制void sendResponse(AtCmdResponse *response) {
if (!response) {
LOGI("Null response received");
return;
}
if (response->result != QMI_ATCOP_RESULT_OK) {
LOGW("Command failed with code: %d", response->result);
}
// 实际发送逻辑
}
6. 调试技巧与日志分析
6.1 关键日志标记
在调试过程中,重点关注以下日志标签:
Atfwd_Daemon:核心守护进程日志ATFWD-daemon:错误和权限相关日志qmi_atcop:QMI通信层日志
6.2 常见错误代码
| 错误代码 | 含义 | 解决方案 |
|---|---|---|
| -45 | QMI长度不匹配 | 检查AP/Modem长度定义一致性 |
| -22 | 无效参数 | 验证AT命令格式和参数 |
| -13 | 内存不足 | 检查内存分配和释放逻辑 |
6.3 实时调试命令
bash复制# 查看ATFWD守护进程状态
adb shell ps -A | grep Atfwd
# 获取实时日志
adb logcat -s Atfwd_Daemon:V ATFWD-daemon:V
# 手动发送测试命令
adb shell am broadcast -a com.qualcomm.atfwd.ACTION_AT_CMD --es name "AT+CUSTOM" --es opcode "QU"
在实际项目部署中,我们发现Android Go设备上的AT命令转发功能需要特别注意内存使用效率。通过优化缓冲区管理和实现命令批处理,可以将内存占用降低30%以上。对于需要转发大量AT命令的场景,建议采用命令分组和延迟响应机制来平衡性能和资源消耗。
