前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >详解Android4.4 RIL短信接收流程分析

详解Android4.4 RIL短信接收流程分析

作者头像
砸漏
发布2020-10-16 10:38:24
3.6K0
发布2020-10-16 10:38:24
举报
文章被收录于专栏:恩蓝脚本

最近有客户反馈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上报的短信息

代码语言:javascript
复制
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

代码语言:javascript
复制
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获取短信息

代码语言:javascript
复制
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,得知代码路径:

代码语言:javascript
复制
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并通知上层应用。

代码语言:javascript
复制
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注册的代码:

代码语言:javascript
复制
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消息

代码语言:javascript
复制
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这个消息从哪里来,然后到哪里去 就行了。

代码语言:javascript
复制
./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)把消息广播出去。

代码语言:javascript
复制
./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短信接收流程分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对ZaLou.Cn网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
短信
腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档