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

Android RIL java 详解---------command interface

2014-09-28 13:10 295 查看

概括

 RIL java command interface 起到承上启下的作用,对上调用注册的notify, 对下(RIL C) 通信。在和RIL C 通信中主要使用使用socket 通信机制,主要有两个类RILSender,完成消息打包和发送的。RILReceiver 完成消息接收和处理。按照处力方式的不同可以把消息分成两大类,
Solicited 消息,主动请求的消息,如sim 状态的查询,请求和应答一一对应。
Unsolicited 消息,主动上报的消息,如Radio on 消息,模块状态的改变等,只有应答。

知识要点

RIL 主要完成 RILSender RILReceiver 的构造还有一些常用消息的封装,
//***** Constructors

public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
super(context);
if (RILJ_LOGD) {
riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
" cdmaSubscription=" + cdmaSubscription + ")");
}
mCdmaSubscription  = cdmaSubscription;
mPreferredNetworkType = preferredNetworkType;
mPhoneType = RILConstants.NO_PHONE;

PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
mWakeLock.setReferenceCounted(false);
mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,
DEFAULT_WAKE_LOCK_TIMEOUT);
mRequestMessagesPending = 0;
mRequestMessagesWaiting = 0;

//构造发送线程
mSenderThread = new HandlerThread("RILSender");
mSenderThread.start();

Looper looper = mSenderThread.getLooper();
mSender = new RILSender(looper);

ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
Context.CONNECTIVITY_SERVICE);
if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
riljLog("Not starting RILReceiver: wifi-only");
} else {
//构造接受线程
riljLog("Starting RILReceiver");
mReceiver = new RILReceiver();
mReceiverThread = new Thread(mReceiver, "RILReceiver");
mReceiverThread.start();

//注册屏幕开关广播接受
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(mIntentReceiver, filter);
}
}


RILSender 这个类继承Handler ,使用android Handler 机制,先将消息经过序列化打包生成RILRequest,之后再发送。其中RILRequest 负责完成加入serial,和序列化,

主要包括两个函数obtain onError .
其关键属性:
//***** Instance Variables
int mSerial;//表示消息,每发送自动++
int mRequest; // 表示发送消息类型
Message mResult; // 接受处理用
Parcel mp; //序列化变量
其关键方法:

/**
* Retrieves a new RILRequest instance from the pool.
*
* @param request RIL_REQUEST_*
* @param result sent when operation completes
* @return a RILRequest instance from the pool.
*/
static RILRequest obtain(int request, Message result) {
RILRequest rr = null;

synchronized(sPoolSync) {//暂时没用
if (sPool != null) {
rr = sPool;
sPool = rr.mNext;
rr.mNext = null;
sPoolSize--;
}
}

if (rr == null) {
rr = new RILRequest(); //申请一个消息单元
}

synchronized(sSerialMonitor) {
rr.mSerial = sNextSerial++;//标示唯一一个消息,
}
//下面是序列化
rr.mRequest = request;
rr.mResult = result;
rr.mp = Parcel.obtain();

if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
}

// first elements in any RIL Parcel
rr.mp.writeInt(request);
rr.mp.writeInt(rr.mSerial);

return rr;
}

RIL Sender ,负责发送消息到RIL C。

class RILSender extends Handler implements Runnable {
public RILSender(Looper looper) {
super(looper);
}

// Only allocated once
byte[] dataLength = new byte[4];

//***** Runnable implementation
public void
run() {
//setup if needed
}

//***** Handler implementation
@Override public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;

switch (msg.what) {
case EVENT_SEND:
/**
* mRequestMessagePending++ already happened for every
* EVENT_SEND, thus we must make sure
* mRequestMessagePending-- happens once and only once
*/
boolean alreadySubtracted = false;
try {
LocalSocket s;

s = mSocket;//这个是RILReceiver 中的获得socket 句柄

if (s == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
if (mRequestMessagesPending > 0)
mRequestMessagesPending--;
alreadySubtracted = true;
return;
}

synchronized (mRequestsList) {
mRequestsList.add(rr);
mRequestMessagesWaiting++;
}

if (mRequestMessagesPending > 0)
mRequestMessagesPending--;
alreadySubtracted = true;

byte[] data;

data = rr.mp.marshall();//反序列化得到data,
rr.mp.recycle();
rr.mp = null;

if (data.length > RIL_MAX_COMMAND_BYTES) {
throw new RuntimeException(
"Parcel larger than max bytes allowed! "
+ data.length);
}

// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);

//Log.v(LOG_TAG, "writing packet: " + data.length + " bytes");

s.getOutputStream().write(dataLength);  //发送数据长度
s.getOutputStream().write(data); //发送数据
} catch (IOException ex) {
Log.e(LOG_TAG, "IOException", ex);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
}
} catch (RuntimeException exc) {
Log.e(LOG_TAG, "Uncaught exception ", exc);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null || !alreadySubtracted) {
rr.onError(GENERIC_FAILURE, null);
rr.release();
}
} finally {
// Note: We are "Done" only if there are no outstanding
// requests or replies. Thus this code path will only release
// the wake lock on errors.
releaseWakeLockIfDone();
}

if (!alreadySubtracted && mRequestMessagesPending > 0) {
mRequestMessagesPending--;
}

break;

case EVENT_WAKE_LOCK_TIMEOUT:
// Haven't heard back from the last request.  Assume we're
// not getting a response and  release the wake lock.
synchronized (mWakeLock) {
if (mWakeLock.isHeld()) {
// The timer of WAKE_LOCK_TIMEOUT is reset with each
// new send request. So when WAKE_LOCK_TIMEOUT occurs
// all requests in mRequestList already waited at
// least DEFAULT_WAKE_LOCK_TIMEOUT but no response.
// Reset mRequestMessagesWaiting to enable
// releaseWakeLockIfDone().
//
// Note: Keep mRequestList so that delayed response
// can still be handled when response finally comes.
if (mRequestMessagesWaiting != 0) {
Log.d(LOG_TAG, "NOTE: mReqWaiting is NOT 0 but"
+ mRequestMessagesWaiting + " at TIMEOUT, reset!"
+ " There still msg waitng for response");

mRequestMessagesWaiting = 0;

if (RILJ_LOGD) {
synchronized (mRequestsList) {
int count = mRequestsList.size();
Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
" mRequestList=" + count);

for (int i = 0; i < count; i++) {
rr = mRequestsList.get(i);
Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] "
+ requestToString(rr.mRequest));
}
}
}
}
// mRequestMessagesPending shows how many
// requests are waiting to be sent (and before
// to be added in request list) since star the
// WAKE_LOCK_TIMEOUT timer. Since WAKE_LOCK_TIMEOUT
// is the expected time to get response, all requests
// should already sent out (i.e.
// mRequestMessagesPending is 0 )while TIMEOUT occurs.
if (mRequestMessagesPending != 0) {
Log.e(LOG_TAG, "ERROR: mReqPending is NOT 0 but"
+ mRequestMessagesPending + " at TIMEOUT, reset!");
mRequestMessagesPending = 0;

}
mWakeLock.release();
}
}
break;
}
}
}


RILReceiver 主要维护socket 链接,从RIL C 接受消息并处理。

class RILReceiver implements Runnable {
byte[] buffer;

RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}

public void
run() {
int retryCount = 0;

try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l;

try {
s = new LocalSocket(); //构造LocalSocket

l = new LocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED); //打包参数
s.connect(l);//链接socket
} catch (IOException ex){
try {
if (s != null) {
s.close();
}
} catch (IOException ex2) {
//ignore failure to close after failure to connect
}
//连续尝试八此,每次间隔SOCKET_OPEN_RETRY_MILLIS
// don't print an error message after the the first time
// or after the 8th time

if (retryCount == 8) {
Log.e (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket after " + retryCount
+ " times, continuing to retry silently");
} else if (retryCount > 0 && retryCount < 8) {
Log.i (LOG_TAG,
"Couldn't find '" + SOCKET_NAME_RIL
+ "' socket; retrying after timeout");
}

try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}

retryCount++;
continue;
}

retryCount = 0;

mSocket = s;//连接成功,把句柄保存到mSocket
Log.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");

int length = 0;
try {
InputStream is = mSocket.getInputStream();//阻塞获取输入流

for (;;) {
Parcel p;

length = readRilMessage(is, buffer); //读取消息并放到buffer中

if (length < 0) {
// End-of-stream reached

d66f
break;
}

p = Parcel.obtain();
p.unmarshall(buffer, 0, length); //把消息序列化
p.setDataPosition(0);

//Log.v(LOG_TAG, "Read packet: " + length + " bytes");

processResponse(p);// 处理消息
p.recycle();//释放序列化变量
}
} catch (java.io.IOException ex) {
Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",
ex);
} catch (Throwable tr) {
Log.e(LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}

Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL
+ "' socket");

setRadioState (RadioState.RADIO_UNAVAILABLE);

try {
mSocket.close();
} catch (IOException ex) {
}

mSocket = null;
RILRequest.resetSerial();

// Clear request list on close
clearRequestsList(RADIO_NOT_AVAILABLE, false);
}} catch (Throwable tr) {
Log.e(LOG_TAG,"Uncaught exception", tr);
}

/* We're disconnected so we don't know the ril version */
notifyRegistrantsRilConnectionChanged(-1);
}
}

示例

下面以获取sim卡的状态为例子大概说明一下这个过程。
在UiccController.java中EVENT_ICC_STATUS_CHANGED 调用RIL Java 中的getIccCardStatus  参数是当前handler 和 EVENT_GET_ICC_STATUS_DONE,通过RILSender发送RIL_REQUEST_GET_SIM_STATUS消息到RIL C,并保存RILRequest . 经过相应处理,可以得到RIL C中的响应类型为 RIL_REQUEST_GET_SIM_STATUS,通过serial
找到之前发送的RILRequest,信息。在通过responseIccCardStatus 对消息格式化,回掉之前handler消息类型还是EVENT_GET_ICC_STATUS_DONE,这样就可以处理了。
相关函数
public void handleMessage (Message msg) {
synchronized (mLock) {
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
Log.i(LOG_TAG, "Kwan :   **************************** via EVENT_ICC_STATUS_CHANGED");
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); // mCi 是RIL Java 实例的句柄
break;
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
Log.i(LOG_TAG, "Kwan :   **************************** via EVENT_GET_ICC_STATUS_DONE" );
AsyncResult ar = (AsyncResult)msg.obj;
onGetIccCardStatusDone(ar);
break;
default:
Log.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
}

//发送部分
public void
getIccCardStatus(Message result) {
//Note: This RIL request has not been renamed to ICC,
//       but this request is also valid for SIM and RUIM
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);

if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));

send(rr);
}

private void
send(RILRequest rr) {
Message msg;

if (mSocket == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
return;
}
//发送到RILSender 中的handleMessage
msg = mSender.obtainMessage(EVENT_SEND, rr);

acquireWakeLock();

msg.sendToTarget();
}

//接受部分

private void
processSolicited (Parcel p) {
int serial, error;
boolean found = false;

serial = p.readInt();
error = p.readInt();

RILRequest rr;

rr = findAndRemoveRequestFromList(serial); // 根据获取RILRequest

if (rr == null) {
Log.w(LOG_TAG, "Unexpected solicited response! sn: "
+ serial + " error: " + error);
return;
}

Object ret = null;

if (error == 0 || p.dataAvail() > 0) {
// either command succeeds or command fails but with data payload
try {switch (rr.mRequest) {
/*
cat libs/telephony/ril_commands.h \
| egrep "^ *{RIL_" \
| sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'
*/
case RIL_REQUEST_GET_SIM_STATUS: ret =  responseIccCardStatus(p); break; //数据格式化
******************************************************************************
default:
throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
//break;
}} catch (Throwable tr) {
// Exceptions here usually mean invalid RIL responses

Log.w(LOG_TAG, rr.serialString() + "< "
+ requestToString(rr.mRequest)
+ " exception, possible invalid RIL response", tr);

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

if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)
+ " " + retToString(rr.mRequest, ret));

if (rr.mResult != null) { //调用发送时出册的handler
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}

rr.release();
}
private Object
responseIccCardStatus(Parcel p) {
IccCardApplicationStatus appStatus;

IccCardStatus cardStatus = new IccCardStatus();
cardStatus.setCardState(p.readInt());
cardStatus.setUniversalPinState(p.readInt());
cardStatus.mGsmUmtsSubscriptionAppIndex = p.readInt();
cardStatus.mCdmaSubscriptionAppIndex = p.readInt();
cardStatus.mImsSubscriptionAppIndex = p.readInt();
int numApplications = p.readInt();

// limit to maximum allowed applications
if (numApplications > IccCardStatus.CARD_MAX_APPS) {
numApplications = IccCardStatus.CARD_MAX_APPS;
}
cardStatus.mApplications = new IccCardApplicationStatus[numApplications];
for (int i = 0 ; i < numApplications ; i++) {
appStatus = new IccCardApplicationStatus();
appStatus.app_type       = appStatus.AppTypeFromRILInt(p.readInt());
appStatus.app_state      = appStatus.AppStateFromRILInt(p.readInt());
appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(p.readInt());
appStatus.aid            = p.readString();
appStatus.app_label      = p.readString();
appStatus.pin1_replaced  = p.readInt();
appStatus.pin1           = appStatus.PinStateFromRILInt(p.readInt());
appStatus.pin2           = appStatus.PinStateFromRILInt(p.readInt());
cardStatus.mApplications[i] = appStatus;
}
return cardStatus;
}

总结

RIL Java command interface 主要是完成:
1、和RIL C 通信,命令的收发
2、对RIL java 中的其它提供接口
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: