最近有客户反馈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的广播,就可以获取到短信了。
总结
以上所述是小编给大家介绍的Android4.4 RIL短信接收流程分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对w3xue网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!