RIL 机制---消息RILJ中的处理

来源:互联网 发布:微信数据储存到sd卡里 编辑:程序博客网 时间:2024/06/05 08:16

9,RILJ

接收子线程要完成的就是对接收数据的处理操作。还分为两步去分析:

1、如何接收的消息;

2、消息的处理流程。

9.1数据接收过程 

接收子线程RILReceiver的run方法主要代码如下,

class RILReceiver implements Runnable {        byte[] buffer;        RILReceiver() {            buffer = new byte[RIL_MAX_COMMAND_BYTES];        }        @Override        public void        run() {            int retryCount = 0;            String rilSocket = "rild";            try {for (;;) {                LocalSocket s = null;                LocalSocketAddress l;                if (mInstanceId == null || mInstanceId == 0 ) {                    rilSocket = SOCKET_NAME_RIL[0];                } else {                    rilSocket = SOCKET_NAME_RIL[mInstanceId];                }                try {                    s = new LocalSocket();                    l = new LocalSocketAddress(rilSocket,                            LocalSocketAddress.Namespace.RESERVED);                    s.connect(l);                } catch (IOException ex){                   •••                    try {                        Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);//休眠4s                    } catch (InterruptedException er) {                    }                    retryCount++;                    continue;                }                retryCount = 0;                mSocket = s;                Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Connected to '"                        + rilSocket + "' socket");                int length = 0;                try {                    InputStream is = mSocket.getInputStream();                    for (;;) {                        Parcel p;                        length = readRilMessage(is, buffer);                        if (length < 0) {                            // End-of-stream reached                            break;                        }                        p = Parcel.obtain();                        p.unmarshall(buffer, 0, length);                        p.setDataPosition(0);                        //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");                        processResponse(p);                        p.recycle();                    }                }                 •••                try { //关闭Socket,然后重新打开                    mSocket.close();                } catch (IOException ex) {                }                mSocket = null;                RILRequest.resetSerial();//清除                // Clear request list on close                clearRequestList(RADIO_NOT_AVAILABLE, false); //清除所有请求            }} catch (Throwable tr) {                Rlog.e(RILJ_LOG_TAG,"Uncaught exception", tr);            }            /* We're disconnected so we don't know the ril version */            notifyRegistrantsRilConnectionChanged(-1); //通知ril连接状态改变        }    }

逻辑也挺简单,主要是2个for循环,

1,第一个for循环打开开了Socket的通道,并且为RIL中的全局变量mSocket赋值。

LocalSocket mSocket;

发送子线程RILSender就是利用该mSocket往RILD发送消息。

2,第二个for循环,首先调用readRilMessage方法从Socket中读取消息,然后调用processResponse方法进行消息处理。

如果读取的过程出现异常,将会关闭Socket通道,并且清除RILRequest系列号和请求列表,重新打开Socket。

 

readRilMessage方法如下,

private static int readRilMessage(InputStream is, byte[] buffer)            throws IOException {        int countRead;        int offset;        int remaining;        int messageLength;        // First, read in the length of the message        offset = 0;        remaining = 4;         //先读取数据的长度        do {            countRead = is.read(buffer, offset, remaining);            if (countRead < 0 ) {                Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length");                return -1;            }            offset += countRead;            remaining -= countRead;        } while (remaining > 0);         //计算数据长度        messageLength = ((buffer[0] & 0xff) << 24)                | ((buffer[1] & 0xff) << 16)                | ((buffer[2] & 0xff) << 8)                | (buffer[3] & 0xff);        // Then, re-use the buffer and read in the message itself        offset = 0;        remaining = messageLength;//再读取有效数据        do {            countRead = is.read(buffer, offset, remaining);            if (countRead < 0 ) {                Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message.  messageLength=" + messageLength                        + " remaining=" + remaining);                return -1;            }            offset += countRead;            remaining -= countRead;        } while (remaining > 0);        return messageLength;    }

可以看出,返回的数据分为两部分,数据长度+数据内容,通过对InputStream的连续读取得到了完整的数据,

并把数据的长度返回出来,而数据的内容通过buffer带出来。发送子线程RILSender发送数据时也是包含2部分,数据长度和内容。

 

再次说明一下,RIL层收到的消息分为2种:

1,第一种是Modem主动上报的消息,比如新短信的提醒,、来电、Modem状态的改变等,这类消息称为URC消息, 在此称为上报消息。

2,第二种是由终端(RILJ)发送给Modem(RIL)后,Modem给出的回应,属于非URC消息,在此称为回应消息。

    对于URC消息来说,只需要调用相应的通知机制即可;而对于非URC消息,我们还需要把相应的数据返回给当初发送请求的单位。

    既然RILC层对消息的处理方式不同,那么对应的在RILJ中也要分开处理:

processResponse方法如下,

private void    processResponse (Parcel p) {        int type;        type = p.readInt();        if (type == RESPONSE_UNSOLICITED) {            processUnsolicited (p);// 上报消息处理        } else if (type == RESPONSE_SOLICITED) {            RILRequest rr = processSolicited (p);//回应消息处理            if (rr != null) {                rr.release();                decrementWakeLock();            }        }    }

上报消息是通过processUnsolicited方法处理的,而回应消息是由processSolicited方法处理的,分别介绍两种处理流程。

9.2. 上报消息处理

processUnsolicited方法如下,

private void    processUnsolicited (Parcel p) {        int response;        Object ret;//读取当前消息的消息码        response = p.readInt();                    try {switch(response) { //先处理            case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret =  responseVoid(p); break;            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); break;            case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: ret =  responseVoid(p); break;•••switch(response) { //再次处理            case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:                /* has bonus radio state int */                RadioState newState = getRadioStateFromInt(p.readInt());                if (RILJ_LOGD) unsljLogMore(response, newState.toString());                switchToRadioState(newState);            break;            case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED:                if (RILJ_LOGD) unsljLog(response);                mImsNetworkStateChangedRegistrants                    .notifyRegistrants(new AsyncResult(null, null, null));            break;            case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:                if (RILJ_LOGD) unsljLog(response);                mCallStateRegistrants                    .notifyRegistrants(new AsyncResult(null, null, null));            break;•••

上面代码只挑出部分消息的处理代码,从中可以看到,上报消息的处理要经过两个switch语句的处理:

 1、第一个switch:

     根据不同的消息码对数据进行初步解析,得到上报的有效数据。

     例如,responseVoid, responseInts等。       

  2、第二个switch

      对有效数据进行不同的处理,主要就是调用相应的管理者去做相应的通知。

消息码是int类型,并且消息码的定义RILJ和RIL肯定保持一致:

1, RILJ的消息码定义在RILConstants.java文件中。

2, RILC的消息码定义在ril.h文件中。

例如,2个文件对RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED定义如下,

RILConstants.java中定义为,

int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;

ril.h中定义为,

#define RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED 1000

9.3 回应消息处理

回应消息是在processSolicited方法中处理的,主要分3个步骤,

9.3.1,获取封装消息的RILRequest对象

int serial, error;boolean found = false;serial = p.readInt();//获取系列号,每个RILRequest对象有唯一的系列号error = p.readInt();RILRequest rr;rr = findAndRemoveRequestFromList(serial);

findAndRemoveRequestFromList方法如下,

private RILRequest findAndRemoveRequestFromList(int serial) {        RILRequest rr = null;        synchronized (mRequestList) {            rr = mRequestList.get(serial);            if (rr != null) {                mRequestList.remove(serial);            }        }        return rr;    }

从mRequestList稀疏list中根据serial获取,获取到之后从mRequestList移除。

mRequestList定义如下,

SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>();

RILRequest对象是在子线程RILSender的handleMessage方法在通过socket发送之前添加到mRequestList,如下,

ynchronized (mRequestList) {         mRequestList.append(rr.mSerial, rr);    }

这样RILRequest对象刚好一一对应起来。

9.3.2,根据RILRequest对象的mRequest变量获取RIL的回应的消息

try {switch (rr.mRequest) {            case RIL_REQUEST_GET_SIM_STATUS: ret =  responseIccCardStatus(p); break;            case RIL_REQUEST_ENTER_SIM_PIN: ret =  responseInts(p); break;            case RIL_REQUEST_ENTER_SIM_PUK: ret =  responseInts(p); break;            case RIL_REQUEST_ENTER_SIM_PIN2: ret =  responseInts(p); break;             ••••

根据不同的消息码(mRequest)对数据进行初步解析,得到回应的有效数据。

 例如,4.1小节中拨号dial方法中消息对应的mRequest变量为RIL_REQUEST_DIAL,

case RIL_REQUEST_DIAL: ret =  responseVoid(p); break;private Object    responseVoid(Parcel p) {        return null;    }

在7.4 小节论述过,modem上报的消息并不一定包含数据。

Modem回应消息的内容有2,一种返回空消息,另外一种返回查询的内容。

拨号对应的返回消息是空的,而发送消息返回的消息有封装数据的,解析数据的方法responseSMS方法如下,

private Object responseSMS(Parcel p) {        int messageRef, errorCode;        String ackPDU;        messageRef = p.readInt();        ackPDU = p.readString();        errorCode = p.readInt();        SmsResponse response = new SmsResponse(messageRef, ackPDU, errorCode);        return response;    }

然后看下reference-ril中从Modem读取数据后对数据进行打包,ril_commands.h有关代码如下,

{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},

RIL_REQUEST_SEND_SMS消息码对应的打包方法为responseSMS。

看到了吧,RILJ对应的解析方法为responseSMS,这是一一对应的。

9.3.3,将有效数据返回给当初的请求者

if (rr.mResult != null) {      AsyncResult.forMessage(rr.mResult, ret, null);      rr.mResult.sendToTarget();   }

在回应消息的处理流程中,同样要先得到RILC层上报的有效数据,但是得到数据之后并不像

上报消息那样主动的去通知相应的管理者去做通知,而是需要根据当前消息的mResult把有效数据发送给当初的发送者,由发送者自己去处理消息。

同样的,和上报消息一样,消息码分别保存在RILConstants.java和ril.h中,并且int数值完全一一对应。

这样,整个消息的流程走下来,终于都走完了。

0 0
原创粉丝点击