Phone与Rild连接过程及消息收发

来源:互联网 发布:仿爱奇艺网站源码php 编辑:程序博客网 时间:2024/05/22 13:35

之前一篇文章中分析了RILD及qcril初始化流程,已经讲过RILD中建立socket服务和接受上层client连接的过程。现在来看下客户端——Phone进程,如何与rild socket建立连接和收发消息。

这里写图片描述

1. 连接Rild 和消息的接收

开机Phone进程启动后,Ril在PhoneFactory::makeDefaultPhone的时候被创建,并对应着Phone实例的数量,双卡机会有2个RIL各自与Rild关联并各自负责一个卡的业务。

public static void makeDefaultPhone(Context context) {        synchronized (sLockProxyPhones) {            ...            //            for (int i = 0; i < numPhones; i++) {                ...                //创建RIL实例                sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i);            }            //创建Phone实例            for (int i = 0; i < numPhones; i++) {                PhoneBase phone = null;                // int phoneType =                // TelephonyManager.getPhoneType(networkModes[i]);                if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {                    phone = TelephonyPluginDelegate.getInstance().makeGSMPhone(context, sCommandsInterfaces[i],                            sPhoneNotifier, i);                } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {                    phone = TelephonyPluginDelegate.getInstance().makeCDMALTEPhone(context, sCommandsInterfaces[i],                            sPhoneNotifier, i);                }                sProxyPhones[i] = TelephonyPluginDelegate.getInstance().makePhoneProxy(phone);            }        }    }

以下是RIL.java中定义的与Socket连接有关的成员,有Socket、各自负责收发的2个类实例 和 提供给它们运行的子线程。

public final class RIL extends BaseCommands implements CommandsInterface {    ...    //与rild连接的socket    LocalSocket mSocket;    //负责发送消息的线程    HandlerThread mSenderThread;    //实现发送消息的Handler    RILSender mSender;    //负责接收消息的线程    Thread mReceiverThread;    //实现接收消息的类,实现了Runnable    RILReceiver mReceiver;    //保存Request消息列表    SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>();    //rild socket的名字    static final String[] SOCKET_NAME_RIL = {"rild", "rild2", "rild3"};    ...    //RIL构造方法    public RIL(Context context, int preferredNetworkType,            int cdmaSubscription, Integer instanceId) {        super(context);        ...        //sender & senderThread        mSenderThread = new HandlerThread("RILSender" + mInstanceId);        mSenderThread.start();        Looper looper = mSenderThread.getLooper();        mSender = new RILSender(looper);        ...            //Receiver& ReceiverThread            riljLog("Starting RILReceiver" + mInstanceId);            mReceiver = new RILReceiver();            mReceiverThread = new Thread(mReceiver, "RILReceiver" + mInstanceId);            mReceiverThread.start();        ...        }}}

具体分析代码前,先看一张图了解它们大致的工作方式。
RILReceiver 实现了Runnable接口,在子线程中循环从socket读取RILD上报的消息。
RILSender则是一个Handler,同样实现了Runnable接口,作为下发消息到RILD的角色。

这里写图片描述

RILReceiver在run方法中连接rild socket,获取到输入流后,进入一个循环读取数据,读出的消息被封装成Parcel并传给processResponse方法处理。

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;                //根据RIL实例ID选择对应的rild socket名字{rild,rild2...}                if (mInstanceId == null || mInstanceId == 0 ) {                    rilSocket = SOCKET_NAME_RIL[0];                } else {                    rilSocket = SOCKET_NAME_RIL[mInstanceId];                }                try {                    //连接socket                    s = new LocalSocket();                    l = new LocalSocketAddress(rilSocket,                            LocalSocketAddress.Namespace.RESERVED);                    s.connect(l);                } catch (IOException ex){                    ...//失败重连                }                retryCount = 0;                mSocket = s;                int length = 0;                try {                    //获得socket输入流                    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);                        processResponse(p);                        p.recycle();                    }                } catch (java.io.IOException ex) {                    ...                }                //socket连接出错,跳出循环做恢复处理                setRadioState (RadioState.RADIO_UNAVAILABLE);                try {                    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);        }    }

2. 消息的发送

RILD及qcril初始化流程 提到过Rild中用于处理socket客户端下发消息的eventLoop函数,现在来看下phone进程作为rild socket的客户端处理下发消息的过程。

RILSender只接收和处理EVENT_SEND和EVENT_WAKE_LOCK_TIMEOUT消息:
EVENT_SEND - 向RILD下发消息。
EVENT_WAKE_LOCK_TIMEOUT - 下发消息时会申请WAKE_LOCK,但如果超时没有收到RILD的反馈,这里会释放WAKE_LOCK。

class RILSender extends Handler implements Runnable {        public RILSender(Looper looper) {            super(looper);        }        // Only allocated once        byte[] dataLength = new byte[4];        //***** Runnable implementation        @Override        public void        run() {            //setup if needed        }        @Override public void        handleMessage(Message msg) {            RILRequest rr = (RILRequest)(msg.obj);            RILRequest req = null;            switch (msg.what) {                //send()方法发送包含RILRequest的EVENT_SEND消息                case EVENT_SEND:                    try {                        LocalSocket s;                        s = mSocket;                        ...                        synchronized (mRequestList) {                            //下发消息前保存到mRequestList                            mRequestList.append(rr.mSerial, rr);                        }                        //准备数据                        byte[] data;                        data = rr.mParcel.marshall();                        rr.mParcel.recycle();                        rr.mParcel = null;                        // parcel length in big endian                        dataLength[0] = dataLength[1] = 0;                        dataLength[2] = (byte)((data.length >> 8) & 0xff);                        dataLength[3] = (byte)((data.length) & 0xff);                        //向socket输出流写入数据                        s.getOutputStream().write(dataLength);                        s.getOutputStream().write(data);                    } catch (IOException ex) {                        ...                    }                    break;                case EVENT_WAKE_LOCK_TIMEOUT:                    //下发消息后,超时没有获得RILD的回复,释放wake lock                    synchronized (mRequestList) {                        if (clearWakeLock()) {                            ...                        }                    }                    break;            }        }    }

send方法向RILSender发出EVENT_SEND后,会调用acquireWakeLock方法申请一个wakelock并设定超时释放的时间。

private void send(RILRequest rr) {        Message msg;        ...        msg = mSender.obtainMessage(EVENT_SEND, rr);        //获取WAKE_LOCK        acquireWakeLock();        msg.sendToTarget();    }    private void    acquireWakeLock() {        synchronized (mWakeLock) {            mWakeLock.acquire();            mWakeLockCount++;            mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);            Message msg = mSender.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);            //获取wakelock后设定超时的时间            mSender.sendMessageDelayed(msg, mWakeLockTimeout);        }    }

超时的时间由system property定义,默认为60秒。
在我的手机上查看这个property并没有赋值,因此使用默认的时间。

    // PROPERTY_WAKE_LOCK_TIMEOUT = "ro.ril.wake_lock_timeout";    // private static final int DEFAULT_WAKE_LOCK_TIMEOUT = 60000;    mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,                DEFAULT_WAKE_LOCK_TIMEOUT);

THE END

RILJ通过socket的输入输出流读写数据,实现上比Rild侧简单很多,这估计是得益于JAVA的封装。

阅读全文
0 0