zoukankan      html  css  js  c++  java
  • 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的广播,就可以获取到短信了。

  • 相关阅读:
    技术每天一点点--2020.01-2020.12月
    【置顶】历史书单--程序员的文娱情怀
    【编程书籍 大系】 计算机开放电子书汇总
    Mysql基础代码(不断完善中)
    php 基础代码大全(不断完善中)
    【读书笔记】阅读美团技术团队文章《领域驱动设计在互联网业务开发中的实践》--2020.06.25 周四 端午节
    【置顶】技术每天一点点--2020.01-2020.12
    【日常】技术每天进展--2019.06.10
    【转载】Spring学习(1)——快速入门--2019.05.19
    vs创建qt dll,并使用qt控制台测试
  • 原文地址:https://www.cnblogs.com/hackfun/p/11775588.html
Copyright © 2011-2022 走看看