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的封装。
- Phone与Rild连接过程及消息收发
- TCP 接收连接及消息的收发
- RILD 启动与实现过程
- 客户端服务器消息收发过程与排错步骤
- 客户端服务器消息收发过程与排错步骤
- KITLConnectToDesktop过程及收发数据包
- MINA客户端建立连接,收发消息
- android Phone中的消息处理过程
- android Phone中的消息处理过程
- android Phone中的消息处理过程
- androoid framework学习之 - RILd启动过程和如何接收framwork层的消息流程
- androoid framework学习之 - RILd启动过程和如何接收framwork层的消息流程(二)
- 消息收发
- 电子邮件的收发及传输过程解析
- iOS开发—蓝牙4.0(BLE)与外设连接及收发数据的流程
- Android studio使用smack连接xmpp服务器收发消息
- Android studio使用smack连接xmpp服务器收发消息
- RILD及qcril初始化流程
- 《大型网站技术架构:核心原理与案例分析》拜读总结,第六章——永无止境:网站的伸缩性架构
- 最新有收益的自媒体平台-优信新车伯乐号正式上线了!
- kettle安装,启动spoon之后一闪就没了问题
- srs代码学习(1)--listen建立过程
- JAVA GUI 登录注册(连接数据库 oracle)
- Phone与Rild连接过程及消息收发
- 如何优雅的使用 phpStorm
- Android自定义view案例一气泡框
- JUnit4源码分析(TestResult)
- Visual Studio 2017 中使用 SQLite3的方法
- android点击拍照长按录制小视频
- openwrt系统mt7621固件编译
- 自定义录音工具类
- 自定义数值范围和小数点的金额的正则表达式验证