response 分析---从moderm主动发消息给RIL-JAVA
上一篇分析了RIL启动和request的分析,今天来看下response:
1.还记得在reference_ril.c里面:
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
......................
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);//创建mainloop线程,用于从moderm主动到RIL-JAVA
..................................
}
static void *
mainLoop(void *param __unused)
{
...................
ret = at_open(fd, onUnsolicited);
...........................
}
2.下面会调用Achannel.c里面的at_open函数:
int at_open(int fd, ATUnsolHandler h)
{
int ret;
pthread_t tid;
pthread_attr_t attr;
s_fd = fd;
s_unsolHandler = h;//将onUnsolicited赋给s_unsolHandler全局指针
s_readerClosed = 0;
s_responsePrefix = NULL;
s_smsPDU = NULL;
sp_response = NULL;
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);//创建线程用于读取moderm的消息
if (ret < 0) {
perror ("pthread_create");
return -1;
}
return 0;
}
调用readerloop函数:
static void *readerLoop(void *arg)
{
for (;;) {
const char * line;
line = readline();
if (line == NULL) {
break;
}
if(isSMSUnsolicited(line)) {
char *line1;
const char *line2;
// The scope of string returned by 'readline()' is valid only
// till next call to 'readline()' hence making a copy of line
// before calling readline again.
line1 = strdup(line);
line2 = readline();//读取消息
if (line2 == NULL) {
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2);
}
free(line1);
} else {
processLine(line);//处理消息
}
}
onReaderClosed();
return NULL;
}
readloop解决的问题是解析从moderm发过来的回应,如果遇到URC则通过handleUnsolicited上报给RIL.JAVA;
如果是命令的应答,则通过handleFinalResponse通知handleFinalResponse有应答结果
static void processLine(const char *line)
{
pthread_mutex_lock(&s_commandmutex);
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited(line);
} else if (isFinalResponseSuccess(line)) {//判断是否是unsolicited消息
sp_response->success = 1;
handleFinalResponse(line);
} else if (isFinalResponseError(line)) {
sp_response->success = 0;
handleFinalResponse(line);
} else if (s_smsPDU != NULL && 0 == strcmp(line, "> ")) {
// See eg. TS 27.005 4.3
// Commands like AT+CMGS have a "> " prompt
writeCtrlZ(s_smsPDU);
s_smsPDU = NULL;
} else switch (s_type) {
case NO_RESULT:
handleUnsolicited(line);
break;
case NUMERIC:
if (sp_response->p_intermediates == NULL
&& isdigit(line[0])
) {
addIntermediate(line);
} else {
/* either we already have an intermediate response or
the line doesn't begin with a digit */
handleUnsolicited(line);//处理消息
}
break;
case SINGLELINE:
if (sp_response->p_intermediates == NULL
&& strStartsWith (line, s_responsePrefix)
) {
addIntermediate(line);
} else {
/* we already have an intermediate response */
handleUnsolicited(line);
}
break;
case MULTILINE:
if (strStartsWith (line, s_responsePrefix)) {
addIntermediate(line);
} else {
handleUnsolicited(line);
}
break;
default: /* this should never be reached */
RLOGE("Unsupported AT command type %d\n", s_type);
handleUnsolicited(line);
break;
}
pthread_mutex_unlock(&s_commandmutex);
}
static void handleUnsolicited(const char *line)
{
if (s_unsolHandler != NULL) {
s_unsolHandler(line, NULL);
}
}
看到了吧,这个s_unsolHandler就是在at_open函数里面赋值的,它指向onUnsolicited函数,所以接下来就调用onUnsolicited函数:
static void onUnsolicited (const char *s, const char *sms_pdu)
{
char *line = NULL, *p;
int err;
/* Ignore unsolicited responses until we're initialized.
* This is OK because the RIL library will poll for initial state
*/
if (sState == RADIO_STATE_UNAVAILABLE) {
return;
}
if (strStartsWith(s, "%CTZV:")) {
/* TI specific -- NITZ time */
char *response;
line = p = strdup(s);
at_tok_start(&p);
err = at_tok_nextstr(&p, &response);
free(line);
if (err != 0) {
RLOGE("invalid NITZ line %s\n", s);
} else {
RIL_onUnsolicitedResponse (
RIL_UNSOL_NITZ_TIME_RECEIVED,
response, strlen(response));
}
} else if (strStartsWith(s,"+CRING:")
|| strStartsWith(s,"RING")
|| strStartsWith(s,"NO CARRIER")
|| strStartsWith(s,"+CCWA")
) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,
NULL, 0);
#ifdef WORKAROUND_FAKE_CGEV
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL); //TODO use new function
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s,"+CREG:")
|| strStartsWith(s,"+CGREG:")
) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED,
NULL, 0);
#ifdef WORKAROUND_FAKE_CGEV
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s, "+CMT:")) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_NEW_SMS,
sms_pdu, strlen(sms_pdu));
} else if (strStartsWith(s, "+CDS:")) {
RIL_onUnsolicitedResponse (
RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT,
sms_pdu, strlen(sms_pdu));
} else if (strStartsWith(s, "+CGEV:")) {
/* Really, we can ignore NW CLASS and ME CLASS events here,
* but right now we don't since extranous
* RIL_UNSOL_DATA_CALL_LIST_CHANGED calls are tolerated
*/
/* can't issue AT commands here -- call on main thread */
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#ifdef WORKAROUND_FAKE_CGEV
} else if (strStartsWith(s, "+CME ERROR: 150")) {
RIL_requestTimedCallback (onDataCallListChanged, NULL, NULL);
#endif /* WORKAROUND_FAKE_CGEV */
} else if (strStartsWith(s, "+CTEC: ")) {
int tech, mask;
switch (parse_technology_response(s, &tech, NULL))
{
case -1: // no argument could be parsed.
RLOGE("invalid CTEC line %s\n", s);
break;
case 1: // current mode correctly parsed
case 0: // preferred mode correctly parsed
mask = 1 << tech;
if (mask != MDM_GSM && mask != MDM_CDMA &&
mask != MDM_WCDMA && mask != MDM_LTE) {
RLOGE("Unknown technology %d\n", tech);
} else {
setRadioTechnology(sMdmInfo, tech);
}
break;
}
} else if (strStartsWith(s, "+CCSS: "))
这边会通过strStartsWith去判断是什么事件,然后再调用 RIL_onUnsolicitedResponse 将相应的事件发送给RIL-JAVA,
在ril.cpp里面:
void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
{
........................
ret = sendResponse(p, soc_id);//将打包好的数据写入socket,发送给上层ril-Java
.................................
}
最后就是blockingWrite函数了,到这里就完成了response的流程了
3.下面讲一下 新事件或者 send事件response在RIL.C的体现:
在RIL.C里面:
class RILReceiver implements Runnable {
byte[] buffer;
RILReceiver() {
buffer = new byte[RIL_MAX_COMMAND_BYTES];
}
@Override
public void
run() {
int retryCount = 0;
String rilSocket = "rild";
//循环处理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 {
//创建于rild通信的socket 建立连接
s = new LocalSocket();
l = new LocalSocketAddress(rilSocket,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
} catch (IOException ex){
try {
if (s != null) {
s.close();
}
} catch (IOException ex2) {
//ignore failure to close after failure to connect
}
// don't print an error message after the the first time
// or after the 8th time
if (retryCount == 8) {
Rlog.e (RILJ_LOG_TAG,
"Couldn't find '" + rilSocket
+ "' socket after " + retryCount
+ " times, continuing to retry silently");
} else if (retryCount >= 0 && retryCount < 8) {
Rlog.i (RILJ_LOG_TAG,
"Couldn't find '" + rilSocket
+ "' socket; retrying after timeout");
}
try {
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
} catch (InterruptedException er) {
}
retryCount++;
continue;
}
retryCount = 0;
mSocket = s;
Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Connected to '"
+ rilSocket + "' socket");
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);
//Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");
//处理rild传递来的消息
processResponse(p);
p.recycle();
}
} catch (java.io.IOException ex) {
Rlog.i(RILJ_LOG_TAG, "'" + rilSocket + "' socket closed",
ex);
} catch (Throwable tr) {
Rlog.e(RILJ_LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}
Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Disconnected from '" + rilSocket
+ "' socket");
//无法读取数据,将CP状态设置为不可用
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);
}
}
以上代码是一只在循环跑的,当有Response时,receiver就会呗唤醒去读取response信息,并且用processResponse函数来处理RIL response的信息:
private void
processResponse (Parcel p) {
int type;
type = p.readInt();
//新事件Or send事件response
if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);//新事件
} else if (type == RESPONSE_SOLICITED) {
RILRequest rr = processSolicited (p);//send事件的response
if (rr != null) {
rr.release();
decrementWakeLock();
}
}
}
上面code很明显了,当时新事件如来电、短信时,会跑 processUnsolicited (p)函数,然后根据相应的事件