这两个月做了两个项目,可以说算是一年当中最忙的阶段了。升级项目问题难度完全不亚于新项目,和其他模块扯了很多皮, 踢过皮球,也提了很多代码。
总的来说,增加了解 bug 经验。此贴记录一下解过的问题,方便以后回顾。
电信短信自注册
- 提供相关短信接口给上层app调用,在 ISms.aidl 增加专用接口
- 解决短信7bit编码问题,由于这三个特殊字符,0x00,0x01,0x03,在编码过程中,不能正确的编码。
- 参照message app,解决短信都是从卡1发送的问题
- 短信 pdu 内容格式参考:http://www.cppblog.com/zhangyq/archive/2009/07/04/89245.html
第二步遇到的问题说明一下,
需要对特殊字符做特殊处理,如果不做特殊处理,Telephony framework 会采用 16 bit 编码,这导致短信内容超过一条的长度限制,会分成两条发送出去。
所以只能对这几个特殊字符处理。
cdma采用7位编码发送,在打包的时候针对前四个字符做特殊处理,修改文件
frameworks/base/telephony/java/com/android/internal/telephony/cdma/BearerData.java
try {
int msgLen = msg.length();
BitwiseOutputStream outStream = new BitwiseOutputStream(msgLen);
for (int i = 0; i < msgLen; i++) {
if(i < 4) {
outStream.write(7, msg.charAt(i));
} else {
int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
if (charCode == -1) {
if (force) {
outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
} else {
throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
}
} else {
outStream.write(7, charCode);
}
}
}
return outStream.toByteArray();
ims gsm 短信编码采用7位编码时,电信的 ims 网络收到的短信内容不能正确解码,采用 8 位则正常,所以强制用 8 位编码,修改文件
/frameworks/base/telephony/java/com/android/internal/telephony/GsmAlphabet.java
ret = new byte[msgLen + 1];
ret[1] = (byte)(msg.charAt(0));
ret[2] = (byte)(msg.charAt(1));
ret[3] = (byte)(msg.charAt(2));
ret[4] = (byte)(msg.charAt(3));
stringToGsm8BitUnpackedField(msg.substring(4), ret, 5, ret.length - 5);
ret[0] = (byte)(msgLen);
return ret;
RILD重启问题分析
分析 force cp crash 后,rild2 不能重启问题。这个问题原因需要说明一下。
以前版本,rild2 挂了会强制重启 rild 进程,rild 进程会带动 rild2 进程重启。
现在版本,rild 重启带动rild2 的代码已经被删除,这个时候 rild2 就没法再次启动,只是启动了 rild.
以前 7.1 版本启动 rild 的 rc 文件的配置如下:
service ril-daemon /system/bin/rild
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
socket rild-cas stream 660 casdrm mmb
user root
service ril-daemon1 /system/bin/rild -c 2
class main
socket rild2 stream 660 root radio
socket rild-debug2 stream 660 radio system
user root
disabled
现在 8.1 版本启动 rild 的 rc 文件的配置如下:
service ril-daemon /vendor/bin/hw/rild -l ${vendor.sec.rild.libpath}
class main
user radio
socket rild-cas stream 660 casdrm mmb
service ril-daemon1 /vendor/bin/hw/rild -c 2 -l ${vendor.sec.rild.libpath2}
class main
user radio
看到两者的主要差别在于,8.1 版本, ril-daemon1 并没有 disabled 字眼,说明 rild2 挂了的情况,是可以自动重启的。
但是现在问题是不能重启,问题在于这个函数并没有让 rild2 挂掉,而是去让 rild 重启,7.0 能 rild 能带 rild2, 而8.0版本么有,所以重启不了。
int DoModemSilentReset()
{
RilLogE("%s()", __FUNCTION__);
RLOGD("RIL_Init start ril-daemon");
property_set("ctl.stop", "ril-daemon");
sleep(1);
property_set("ctl.start", "ril-daemon");
return 0;
}
修改如下
int DoModemSilentReset()
{
exit(EXIT_SUCCESS);
}
此时,force cp crash 后,rild 和 rild2 能正常重启。
在调试的过程中发现,如果我们单单杀死 rild2 进程,rild2 依然没法自动重启。
adb shell
ps -A|grep rild
kill -9 pid
对比发现依旧7.0版本是OK的,是因为 rild2 挂了会强制启动 rild,所以两个 ril-daemon 都会重启。
换句话说,rild2 挂了,必须两个 ril-daemon 都必须重启,才能正常工作。
所以,修改 rc 文件,增加如下代码:
on property:init.svc.ril-daemon1=restarting
restart ril-daemon
之后,ril-daemon 和 ril-daemon1 都重启,正常工作。
多线程变量问题导致手机无服务
手机手动搜网后,选择一个 forbidden 网络点击注册(这个过程频繁操作),sometime 问题,之后手机发生一直注册不上网络。
调查后发现,手动选择 forbidden 网络后,手机端发送一个 set manul 的命令给 cp,之后,手机端还会发一个 set auto 自动选择网络的命令下去。
然而,这两个命令作为一个消息会用同一个变量 mTxSetNwMsg;
这两个需要和 cp 端进行交互,是一个异步的过程,可以这么简单理解,发送命令是一个发送线程,接收设置的结果是响应线程。
-
在 set auto 时候,mTxSetNwMsg 代表 set auto 消息。
-
cp 响应 set auto 消息,这个消息通过管道的方式继续传递,表示 set auto 处理完成。
-
rild 的处理流程认为 set auto 消息处理完成了,set manual 消息就发下去,mTxSetNwMsg 此时代表的是 set manul 消息了。
-
然而在这个时候,set auto 消息还会去把 mTxSetNwMsg 置为 null, 那么 mTxSetNwMsg 代表的消息 set manul,就无法返回了。
-
rild 记录着 set manul 消息一直没有返回,所有消息都会卡住,所以手机显示无服务,因为 rild 已经无法正常工作。
他们对应如下命令
10-25 11:04:04.775 radio 15708 15708 D RILJ : [0709]> SET_NETWORK_SELECTION_MANUAL operatorNumeric = 45413 [SUB0]
10-25 11:04:09.907 radio 15708 15708 D RILJ : [0734]> SET_NETWORK_SELECTION_AUTOMATIC [SUB0]
10-25 11:04:09.933 radio 15708 16459 D RILJ : [0709]< SET_NETWORK_SELECTION_MANUAL error 38 [SUB0]
10-25 11:04:09.933 radio 15708 16459 D RilRequest: [0709]< SET_NETWORK_SELECTION_MANUAL error: com.android.internal.telephony.CommandException: INTERNAL_ERR ret=
通过增加一个变量的方式,来规避这个问题(也可以通过加锁的方式,但这个更简单):
修改前:
void QmiNasService::NwSelectionDone(int err)
{
if (mNwSelectTxn) {
mModem->ProcessMessageDone(NULL, err, mNwSelectTxn);//通过管道的方式,传递消息
mNwSelectTxn = NULL;//之后置为null
}
mNwSelectRat = SRIL_RAT_UNKNOWN;
mNwSelectCsgId = 0;
}
修改后:
void QmiNasService::NwSelectionDone(int err)
{
if (mNwSelectTxn) {
QmiTransaction *curNwSelectTxn = mNwSelectTxn;//增加一个局部变量
mNwSelectTxn = NULL;//先把这个置为null,
mModem->ProcessMessageDone(NULL, err, curNwSelectTxn);//set manul 会消息等待这个传递完,才会发下来。
curNwSelectTxn = NULL;
}
mNwSelectRat = SRIL_RAT_UNKNOWN;
mNwSelectCsgId = 0;
}
其他项目问题分析
- 双 CTC 卡情况下,副卡无法拨打紧急号码问题,需要直接从 cs 域直接拨打。
- CTC 无法注册上 volte sometimes 问题,原因是属性设置问题,导致判断条件不对,没有设置到 modem 端。
- 插 CTC 卡显示漫游问题,针对中国向,修改 isInPrl 默认值为 true。