欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-05-22 17:01:44
最近有客户反馈Android接收不到短信,于是一头扎进RIL里面找原因。最后发现不是RIL的问题,而是BC72上报短信的格式不对,AT+CNMA=1无作用等几个小问题导致的。尽管问题不在RIL,但总算把RIL短信接收流程搞清楚了。 接收到新信息的log: D/ATC ( 1269): AT< +CM ......

 

        近有客户反馈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的广播,就可以获取到短信了。