Android4.4 RIL短信接收流程分析
最近有客户反馈android接收不到短信,于是一头扎进ril里面找原因。最后发现不是ril的问题,而是bc72上报
短信的格式不对,at+cnma=1无作用等几个小问题导致的。尽管问题不在ril,但总算把ril短信接收流程搞清楚了。
接收到新信息的log:
d/atc ( 1269): at< +cmt:,27
d/atc ( 1268): at< 0891683108705505f0040d91683117358313f500009101329154922307ea31da2c36a301
d/rilj ( 1792): [unsl]< unsol_response_new_sms
d/smsmessage( 1792): sms sc address: +8613800755500
v/smsmessage( 1792): sms originating address: +8613715338315
v/smsmessage( 1792): sms tp-pid:0 data coding scheme: 0
d/smsmessage( 1792): sms sc timestamp: 1571831129000
v/smsmessage( 1792): sms message body (raw): 'jchfbfh'
d/gsminboundsmshandler( 1776): idle state processing message type 1
d/gsminboundsmshandler( 1776): acquired wakelock, leaving idle state
d/gsminboundsmshandler( 1776): entering delivering state
d/gsminboundsmshandler( 1776): uri of new row -> content://raw/3
d/rilj ( 1775): [3706]> sms_acknowledge true 0
d/rilc ( 1254): onrequest: sms_acknowledge
d/atc ( 1254): at> at+cnma=1
d/atc ( 1254): at< ok
d/rilj ( 1775): [3706]< sms_acknowledge
d/gsminboundsmshandler( 1775): delivering sms to: com.android.mms com.android.mms.transaction.privilegedsmsreceiver
e/gsminboundsmshandler( 1775): unexpected broadcastreceiver action: android.provider.telephony.sms_received
d/gsminboundsmshandler( 1775): successful broadcast, deleting from raw table.
d/smsmessage( 2124): sms sc address: +8613800755500
d/gsminboundsmshandler( 1775): deleted 1 rows from raw table.
d/gsminboundsmshandler( 1775): ordered broadcast completed in: 276 ms
d/gsminboundsmshandler( 1775): leaving delivering state
d/gsminboundsmshandler( 1775): entering delivering state
d/gsminboundsmshandler( 1775): leaving delivering state
d/gsminboundsmshandler( 1775): entering idle state
v/smsmessage( 2124): sms originating address: +8613715338315
v/smsmessage( 2124): sms tp-pid:0 data coding scheme: 0
d/smsmessage( 2124): sms sc timestamp: 1572253549000
v/smsmessage( 2124): sms message body (raw): 'jchfbfh'
d/gsminboundsmshandler( 1775): idle state processing message type 5
d/gsminboundsmshandler( 1775): mwakelock released
一、短信接收
1. vendor ril接收到modem上报的短信息
hardware/ril/reference-ril/reference-ril.c
static void onunsolicited (const char *s, const char *sms_pdu) { ... ... if (strstartswith(s, "+cmt:")) { ril_onunsolicitedresponse ( ril_unsol_response_new_sms, /* 上报unsol_response_new_sms消息 */ sms_pdu, strlen(sms_pdu)); } ... ... }
2. rild把短信息发送到rilj
hardware/ril/libril/ril.cpp
extern "c" void ril_onunsolicitedresponse(int unsolresponse, void *data, size_t datalen) { ... ... unsolresponseindex = unsolresponse - ril_unsol_response_base; /* 找出消息在s_unsolresponses[]的索引 */ ... ... switch (s_unsolresponses[unsolresponseindex].waketype) { /* 禁止进入休眠 */ case wake_partial: grabpartialwakelock(); shouldscheduletimeout = true; break; ... ... } ... ... ret = s_unsolresponses[unsolresponseindex] /* 调用消息处理函数responsestring() */ .responsefunction(p, data, datalen); ... ... ret = sendresponse(p); /* 发送parcel中的信息内容到服务端rilj */ } static unsolresponseinfo s_unsolresponses[] = { ... ... /* 消息对应的消息处理函数,新信息到来会唤醒系统 */ {ril_unsol_response_new_sms, responsestring, wake_partial}, ... ... }; static int responsestring(parcel &p, void *response, size_t responselen) { /* one string only */ startresponse; appendprintbuf("%s%s", printbuf, (char*)response); closeresponse; writestringtoparcel(p, (const char *)response); /* 把字符串格式的信息存到parcel容器中 */ return 0; }
二、解析短信息
1. rilj获取短信息
frameworks/opt/telephony/src/java/com/android/internal/telephony/ril.java
private void processunsolicited (parcel p) { ... ... case ril_unsol_response_new_sms: ret = responsestring(p); break; ... ... switch(response) { ... ... case ril_unsol_response_new_sms: { if (rilj_logd) unsljlog(response); /* 参考log:[unsl]< unsol_response_new_sms */ // fixme this should move up a layer string a[] = new string[2]; a[1] = (string)ret; smsmessage sms; sms = smsmessage.newfromcmt(a); /* 解析pdu格式的短信息 */ if (mgsmsmsregistrant != null) { mgsmsmsregistrant .notifyregistrant(new asyncresult(null, sms, null)); } break; } ... ... } ... ... } private object responsestring(parcel p) { string response; response = p.readstring(); /* 信息内容转换成object */ return response; }
2. 解析短信息
smsmessage.newfromcmt(a);根据import android.telephony.smsmessage,得知代码路径:
frameworks/opt/telephony/src/java/android/telephony/smsmessage.java
public static smsmessage newfromcmt(string[] lines) { // received sms in 3gpp format smsmessagebase wrappedmessage = com.android.internal.telephony.gsm.smsmessage.newfromcmt(lines); /* 是对另一个newfromcmt的封装,因为有gsm和cdma两种短信, * 即cdma中也有newfromcmt,根据情况按需选择 */ return new smsmessage(wrappedmessage); }
com.android.internal.telephony.gsm.smsmessage.newfromcmt(lines)的实现在
frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/smsmessage.java
public class smsmessage extends smsmessagebase { ... ... public static smsmessage newfromcmt(string[] lines) { try { smsmessage msg = new smsmessage(); msg.parsepdu(iccutils.hexstringtobytes(lines[1])); /* 解析pdu短信 */ return msg; } catch (runtimeexception ex) { rlog.e(log_tag, "sms pdu parsing failed: ", ex); return null; } } ... ... }
iccutils.hexstringtobytes(lines[1])把十六进制的字符串转换成字节数组msg.parsepdu()解析这个数组的内容,最后获得短信内容
frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/smsmessage.java
private void parsepdu(byte[] pdu) { ... ... mscaddress = p.getscaddress(); if (mscaddress != null) { if (vdbg) rlog.d(log_tag, "sms sc address: " + mscaddress); /* 参考log:sms sc address: +8613800755500 */ } ... ... mmti = firstbyte & 0x3; switch (mmti) { ... ... case 3: //gsm 03.40 9.2.3.1: mti == 3 is reserved. //this should be processed in the same way as mti == 0 (deliver) parsesmsdeliver(p, firstbyte); /* 对短信类型为deliver的短信进行解析 */ break; ... ... } ... ... } private void parsesmsdeliver(pduparser p, int firstbyte) { ... ... moriginatingaddress = p.getaddress(); if (moriginatingaddress != null) { if (vdbg) rlog.v(log_tag, "sms originating address: " /* 参考log: sms originating address: +861371533xxxx */ + moriginatingaddress.address); } ... ... mprotocolidentifier = p.getbyte(); // tp-data-coding-scheme // see ts 23.038 mdatacodingscheme = p.getbyte(); if (vdbg) { rlog.v(log_tag, "sms tp-pid:" + mprotocolidentifier + " data coding scheme: " + mdatacodingscheme); /* 参考log: sms tp-pid:0 data coding scheme: 0 */ } msctimemillis = p.getsctimestampmillis(); if (vdbg) rlog.d(log_tag, "sms sc timestamp: " + msctimemillis); /* 参考log:sms sc timestamp: 1571831129000 */ boolean hasuserdataheader = (firstbyte & 0x40) == 0x40; parseuserdata(p, hasuserdataheader); /* 解析信息有效内容 */ ... ... } private void parseuserdata(pduparser p, boolean hasuserdataheader) { ... ... if (vdbg) rlog.v(log_tag, "sms message body (raw): '" + mmessagebody + "'"); /* 短信内容,参考log: sms message body (raw): 'jchfbfh' */ ... ... }
三、处理短信息
对用户有效的短信内容,最终保存在类型为string的mmessagebody变量中,该变量属于smsmessagebase抽象类,而
smsmessage继承于smsmessagebase。
回到前面frameworks/opt/telephony/src/java/com/android/internal/telephony/ril.java中processunsolicited(),
sms = smsmessage.newfromcmt(a);解析完短信息后,返回一个smsmessage并通知上层应用。
frameworks/opt/telephony/src/java/com/android/internal/telephony/ril.java
mgsmsmsregistrant .notifyregistrant(new asyncresult(null, sms, null)); /* 把sms转成object类型 */
frameworks/base/core/java/android/os/asyncresult.java
public class asyncresult { ... ... /** please note, this sets m.obj to be this */ public asyncresult (object uo, object r, throwable ex) { userobj = uo; result = r; exception = ex; } ... ... }
根据mgsmsmsregistrant.notifyregistrant(new asyncresult(null, sms, null));找到mgsmsmsregistrant注册的代码:
frameworks/opt/telephony/src/java/com/android/internal/telephony/basecommands.java
public abstract class basecommands implements commandsinterface { ... ... @override public void setonnewgsmsms(handler h, int what, object obj) { /* mgsmsmsregistrant.notifyregistrant(new asyncresult(null, sms, null))中的mgsmsmsregistrant是在这里创建的 */ mgsmsmsregistrant = new registrant (h, what, obj); } ... ... }
封装消息event_new_sms消息
frameworks/base/core/java/android/os/registrant.java
public class registrant { public registrant(handler h, int what, object obj) /* 传入需要处理消息为what的事件处理handler h,obj为事件内容,参考phone.mci.setonnewgsmsms(gethandler(), event_new_sms, null); */ { refh = new weakreference(h); this.what = what; userobj = obj; } ... ... /** * this makes a copy of @param ar */ public void notifyregistrant(asyncresult ar) /* 参考mgsmsmsregistrant.notifyregistrant(new asyncresult(null, sms, null)) */ { internalnotifyregistrant (ar.result, ar.exception); /* ar.result为sms */ } /*package*/ void internalnotifyregistrant (object result, throwable exception) /* internalnotifyregistrant (sms, throwable exception) */ { handler h = gethandler(); if (h == null) { clear(); } else { message msg = message.obtain(); /* 创建一个消息 */ msg.what = what; /* 消息类型event_new_sms */ msg.obj = new asyncresult(userobj, result, exception); /* 消息内容sms */ h.sendmessage(msg); /* 发送消息到注册了这个消息的handler,参考phone.mci.setonnewgsmsms(gethandler(), event_new_sms, null);的gethandler() */ } } ... ... }
然而basecommands是一个抽象类,实现了commandsinterface中的setonnewgsmsms接口,这个接口由gsminboundsmshandler调用
(phone.mci.setonnewgsmsms(gethandler(), event_new_sms, null)),也就是说gsminboundsmshandler的gethandler()是event_new_sms
的监听者,也就是说frameworks/opt/telephony/src/java/com/android/internal/telephony/ril.java中mgsmsmsregistrant.notifyregistrant(new asyncresult(null, sms, null))
调用之后,会触发gsminboundsmshandler中gethandler()的handler对event_new_sms消息进行解析。这个handler肯定是gsminboundsmshandler
实例化的对象中的,这个对象在什么时候,在哪里创建的,暂且不管。我们只管event_new_sms这个消息从哪里来,然后到哪里去
就行了。
./frameworks/opt/telephony/src/java/com/android/internal/telephony/imssmsdispatcher.java
public final class imssmsdispatcher extends smsdispatcher { ... ... mgsminboundsmshandler = gsminboundsmshandler.makeinboundsmshandler(phone.getcontext(), /* 获取mgsminboundsmshandler,并启动状态机 */ storagemonitor, phone); ... ... }
./frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/gsminboundsmshandler.java
public class gsminboundsmshandler extends inboundsmshandler { ... ... /** * create a new gsm inbound sms handler. */ private gsminboundsmshandler(context context, smsstoragemonitor storagemonitor, phonebase phone) { super("gsminboundsmshandler", context, storagemonitor, phone, /* 构造gsminboundsmshandler时,通过super()调用inboundsmshandler的构造函数 */ gsmcellbroadcasthandler.makegsmcellbroadcasthandler(context, phone)); phone.mci.setonnewgsmsms(gethandler(), event_new_sms, null); /* 注册event_new_sms消息 */ mdatadownloadhandler = new usimdatadownloadhandler(phone.mci); } ... ... /** * wait for state machine to enter startup state. we can't send any messages until then. */ public static gsminboundsmshandler makeinboundsmshandler(context context, smsstoragemonitor storagemonitor, phonebase phone) { gsminboundsmshandler handler = new gsminboundsmshandler(context, storagemonitor, phone); /* 实例化gsminboundsmshandler */ handler.start(); /* 抽象类inboundsmshandler继承与statemachine,而gsminboundsmshandler继承于inboundsmshandler, * gsminboundsmshandler调用启动状态机方法start() */ return handler; } ... ... }
./frameworks/opt/telephony/src/java/com/android/internal/telephony/inboundsmshandler.java
public abstract class inboundsmshandler extends statemachine { ... ... protected inboundsmshandler(string name, context context, smsstoragemonitor storagemonitor, phonebase phone, cellbroadcasthandler cellbroadcasthandler) { ... ... addstate(mdefaultstate); /* 构造inboundsmshandler时,添加状态机的状态 */ addstate(mstartupstate, mdefaultstate); addstate(midlestate, mdefaultstate); addstate(mdeliveringstate, mdefaultstate); addstate(mwaitingstate, mdeliveringstate); setinitialstate(mstartupstate); /* 初始化状态机 */ if (dbg) log("created inboundsmshandler"); } ... ... class idlestate extends state { @override public void enter() { if (dbg) log("entering idle state"); sendmessagedelayed(event_release_wakelock, wakelock_timeout); } @override public void exit() { mwakelock.acquire(); if (dbg) log("acquired wakelock, leaving idle state"); } @override public boolean processmessage(message msg) { if (dbg) log("idle state processing message type " + msg.what); switch (msg.what) { case event_new_sms: /* 空闲时,接收到短信 */ case event_broadcast_sms: defermessage(msg); transitionto(mdeliveringstate); /* 转到mdeliveringstate */ return handled; ... ... } } } ... ... class deliveringstate extends state { /* 转到mdeliveringstate状态 */ @override public void enter() { if (dbg) log("entering delivering state"); } @override public void exit() { if (dbg) log("leaving delivering state"); } @override public boolean processmessage(message msg) { switch (msg.what) { case event_new_sms: // handle new sms from ril handlenewsms((asyncresult) msg.obj); /* 处理新sms */ sendmessage(event_return_to_idle); /* 处理完回到空闲状态 */ return handled; ... ... } } ... ... } } void handlenewsms(asyncresult ar) { ... ... smsmessage sms = (smsmessage) ar.result; result = dispatchmessage(sms.mwrappedsmsmessage); ... ... } public int dispatchmessage(smsmessagebase smsb) { ... ... return dispatchmessageradiospecific(smsb); ... ... }
通过以上流程可以了解到,当状态机接收到sms后,对消息进行分发,针对type zero, sms-pp data download,
和3gpp/cphs mwi type sms判断,如果是normal sms messages,则调用dispatchnormalmessage(smsb),然后创建
一个inboundsmstracker对象,把信息保存到raw table,然后在通过sendmessage(event_broadcast_sms, tracker)
把消息广播出去。
./frameworks/opt/telephony/src/java/com/android/internal/telephony/inboundsmshandler.java
class deliveringstate extends state { ... ... public boolean processmessage(message msg) { switch (msg.what) { ... ... case event_broadcast_sms: /* 接收到event_broadcast_sms消息并处理 */ // if any broadcasts were sent, transition to waiting state if (processmessagepart((inboundsmstracker) msg.obj)) { transitionto(mwaitingstate); } return handled; ... ... } } ... ... } boolean processmessagepart(inboundsmstracker tracker) { ... ... broadcastreceiver resultreceiver = new smsbroadcastreceiver(tracker); /* 创建一个广播接收者,用来处理短信广播的结果 */ ... ... intent = new intent(intents.sms_deliver_action); /* 设置当前intent的action为sms_deliver_action */ // direct the intent to only the default sms app. if we can't find a default sms app // then sent it to all broadcast receivers. componentname componentname = smsapplication.getdefaultsmsapplication(mcontext, true); /* 这个action只会发送给carrier app,而且carrier app可以通过set result为result_canceled来终止这个广播 */ if (componentname != null) { // deliver sms message only to this receiver intent.setcomponent(componentname); log("delivering sms to: " + componentname.getpackagename() + " " + componentname.getclassname()); } ... ... dispatchintent(intent, android.manifest.permission.receive_sms, /* 广播intent */ appopsmanager.op_receive_sms, resultreceiver); ... ... } private final class smsbroadcastreceiver extends broadcastreceiver { ... ... public void onreceive(context context, intent intent) { ... ... // now that the intents have been deleted we can clean up the pdu data. if (!intents.data_sms_received_action.equals(action) && !intents.data_sms_received_action.equals(action) && !intents.wap_push_received_action.equals(action)) { loge("unexpected broadcastreceiver action: " + action); } int rc = getresultcode(); if ((rc != activity.result_ok) && (rc != intents.result_sms_handled)) { loge("a broadcast receiver set the result code to " + rc + ", deleting from raw table anyway!"); } else if (dbg) { log("successful broadcast, deleting from raw table."); } deletefromrawtable(mdeletewhere, mdeletewhereargs); sendmessage(event_broadcast_complete); /* 成功广播 */ ... ... } ... ... }
到这里,在应用层注册具有intents.sms_received_action这样action的广播,就可以获取到短信了。
上一篇: 投诉