您的位置:首页 > 移动开发 > Android开发

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

2017-05-26 14:26 309 查看
之前一篇文章中分析了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 {

4000
//获得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的封装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RIL phone telephony Android
相关文章推荐