Android4.4 RIL软件框架
本文主要对android4.4 RIL的telephony与modem的命令交互流程进行分析,当然本文不是重点介绍telephony。
telephony涉及具体业务逻辑内容比较多,包括sim、dail、sms、network等等,以后会针对这些内容学习分析。
RIL在Android体系中的位置:
(A) 应用层发起访问modem的请求
(B) RILD进程
(A) 应用层发起访问modem的请求
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java中的类RIL,提供了一系
列的接口给上层应用调用,以访问modem。当然这些接口并不是直接给APP使用,而是由framework中sim、dail、
sms、network等相关服务调用。
如: 以查询SIM卡状态getIccCardStatus()为例,该API为UiccController模块所调用:
完整的SIM卡请求log:
10-11 12:21:43.630 D/RILJ ( 1833): [3653]> GET_SIM_STATUS
10-11 12:21:43.630 D/RILC ( 1286): [0005]> GET_SIM_STATUS
10-11 12:21:43.630 D/RILC ( 1286): onRequest: GET_SIM_STATUS
10-11 12:21:43.630 D/ATC ( 1286): AT> AT+CPIN?
10-11 12:21:43.640 D/ATC ( 1286): AT< +CPIN: READY
10-11 12:21:43.640 D/ATC ( 1286): AT< OK
10-11 12:21:43.640 D/RILC ( 1286): [0005]< GET_SIM_STATUS {[app_type=1,app_state=5,perso_substate=2,aid_ptr=(null),app_label_ptr=(null),pin1_replaced=0,pin1=0,pin2=0],}
10-11 12:21:43.640 D/RILJ ( 1833): [3653]< GET_SIM_STATUS IccCardState {CARDSTATE_PRESENT,PINSTATE_UNKNOWN,num_apps=1,gsm_id=0{APPTYPE_SIM,APPSTATE_READY},cdma_id=8,ims_id=8}
发起请求:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
@Override
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); /* 获取一个RILRequest */ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); /* 参考log:[3653]> GET_SIM_STATUS */ send(rr); /* 发送请求 */
}
RILRequest.obtain是从内存池获取一个RILRequest实例,并初始化:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
class RILRequest {
static final String LOG_TAG = "RilRequest"; ... ... static RILRequest obtain(int request, Message result) {
RILRequest rr = null; synchronized(sPoolSync) { /* 从内存池中取出一个RILRequest对象*/
if (sPool != null) {
rr = sPool;
sPool = rr.mNext;
rr.mNext = null;
sPoolSize--;
}
} if (rr == null) { /* 如果内存池中没有,则实例化一个 */
rr = new RILRequest();
} rr.mSerial = sNextSerial.getAndIncrement(); /* 获取串号,并且+1 */ rr.mRequest = request; /* 对应RIL_REQUEST_*请求 */
rr.mResult = result;
rr.mParcel = Parcel.obtain(); /* 初始化一个Parcel,用于封包以发送给底层RILD */ if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
} // first elements in any RIL Parcel
rr.mParcel.writeInt(request); /* 每个RIL Parcel最开始也最基本的两个元素 */
rr.mParcel.writeInt(rr.mSerial); return rr; /* 返回这个从内存池中获取的实例 */
} ... ... String
serialString() {
//Cheesy way to do %04d
StringBuilder sb = new StringBuilder(); /* 创建一个StringBuilder实例用于操作字符串 */
String sn; long adjustedSerial = (((long)mSerial) - Integer.MIN_VALUE)%; sn = Long.toString(adjustedSerial); /* 把数值转换成字符串 */ //sb.append("J[");
sb.append('[');
for (int i = , s = sn.length() ; i < - s; i++) {
sb.append('');
} sb.append(sn);
sb.append(']');
return sb.toString(); /* 转换出来的字符串格式: [xxxx] */
} ... ...
}
send(rr)发送请求到服务端:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private void
send(RILRequest rr) {
Message msg; ... ... msg = mSender.obtainMessage(EVENT_SEND, rr); /* 发送EVENT_SEND时间,时间参数为RILRequest */ acquireWakeLock(); /* 获取wakelock,禁止进入休眠 */ msg.sendToTarget(); /* message从handler类获取,从而可以直接向该handler对象发送消息。target就是创建message的handler */
}
实际上telephony无法直接与modem通讯,由于每个厂商的modem都不一样,modem存在于系统中的方式
也不一样,如:有的CPU芯片厂商的modem是以一个CP核的方式集成在基带上(高通、展讯等),有的CPU芯
片(Exynos 4412等)需要通过串口/USB外接modem模块,如:BC72 LTE模块等。
send(rr)向RILD发送请求,这里涉及一个进程间通信问题,而且Java侧与C++侧的进程通讯,当然这里并没
有用Android开发的朋友都熟悉的Bind,而是socket。
telephony/Java侧RIL命令交互的处理,暂且称为RILJ。
RILJ作为socket的客户端,RILD(rild进程)作为服务端,后面会分析rild进程。
socket客户端的创建:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
... ... mSenderThread = new HandlerThread("RILSender"); /* 创建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"); /* 创建RILReceiver线程 */
mReceiverThread.start(); ... ...
} ... ...
} class RILReceiver implements Runnable {
byte[] buffer; RILReceiver() { /* 构造时,分配一个数组 */
buffer = new byte[RIL_MAX_COMMAND_BYTES];
} @Override
public void
run() { /* 循环读取从RILD返回或主动上报的数据 */
int retryCount = 0; try {for (;;) {
LocalSocket s = null;
LocalSocketAddress l; try {
s = new LocalSocket(); /* 创建一个socket客户端 */
l = new LocalSocketAddress(SOCKET_NAME_RIL,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l); /* 连接服务器 */
} ... ...
} ... ... try {
InputStream is = mSocket.getInputStream(); /* 循环读取socket的数据 */ for (;;) {
Parcel p; length = readRilMessage(is, buffer); /* 解析socket数据 */ if (length < 0) {
// End-of-stream reached
break;
} p = Parcel.obtain(); /* 获取一个Parcel */
p.unmarshall(buffer, 0, length); /* 读取出来的就是之前序列化的byte数组,所以要进行一个反序列化操作 */
p.setDataPosition(0); /* 从buffer转换到Parcel之后,需要将指针手动指向到最初的位置 */ //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes"); processResponse(p);
p.recycle(); /* 数据处理完后,需要回收Parcel的内存 */
}
} ... ...
}
RILReceiver线程创建socket客户端,连接服务端,然后进入等待服务端的processResponse消息处理循环,RILJ
接收到RILD回复的response返回RIL请求的发起者,以getIccCardStatus(Message result)为例,processResponse(p)
会把DRILD的response返回给UiccController
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private static int readRilMessage(InputStream is, byte[] buffer)
throws IOException {
int countRead;
int offset;
int remaining;
int messageLength; // First, read in the length of the message
offset = 0;
remaining = 4;
do {
countRead = is.read(buffer, offset, remaining); /* 读出消息的4字节长度 */ if (countRead < 0 ) {
Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length");
return -1;
} offset += countRead;
remaining -= countRead;
} while (remaining > 0); messageLength = ((buffer[0] & 0xff) << 24) /* 获取长度 */
| ((buffer[1] & 0xff) << 16)
| ((buffer[2] & 0xff) << 8)
| (buffer[3] & 0xff); // Then, re-use the buffer and read in the message itself
offset = 0;
remaining = messageLength;
do {
countRead = is.read(buffer, offset, remaining); /* 读取剩余的数据 */ if (countRead < 0 ) {
Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength
+ " remaining=" + remaining);
return -1;
} offset += countRead;
remaining -= countRead;
} while (remaining > 0); return messageLength;
} private void
processResponse (Parcel p) {
int type; type = p.readInt(); /* 从RILD返回的数据第一个字节,表示请求的返回类型:RESPONSE_UNSOLICITED/RESPONSE_SOLICITED */ if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p); /* 主动上报 */
} else if (type == RESPONSE_SOLICITED) {
RILRequest rr = processSolicited (p); /* 普通请求对应的同步上报 */
if (rr != null) {
rr.release(); /* 释放对应的RILRequest内存和wakelock */
decrementWakeLock();
}
}
}
RILD的response一般有两种,一种是RILJ普通请求,RILD对RILJ请求的response (RESPONSE_SOLICITED),另一种是RILD主动上报的
response (RESPONSE_UNSOLICITED), processResponse (Parcel p)分别对这两种情况的response进行处理。
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
private RILRequest
processSolicited (Parcel p) {
int serial, error;
boolean found = false; serial = p.readInt(); /* 串号,也就是token */
error = p.readInt(); /* 错误码 */ RILRequest rr; rr = findAndRemoveRequestFromList(serial); /* 根据taken取出对应的RILRequest */ ... ...
*/
case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; ... ... if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null); /* 把rr.mResult存到AsyncResult.userObj,并把rr.mResult.obj转换为AsyncResult */
rr.mResult.sendToTarget(); /* msg发送到对应的target(Handler) */
} ... ...
} private Object
responseIccCardStatus(Parcel p) {
IccCardApplicationStatus appStatus; ... ... appStatus = new IccCardApplicationStatus(); ... ... return cardStatus;
}
回到刚才send(rr),send(rr)并不是直接发送到socket服务端RILD,而是通过一个Message发送到RILSender线程,
在handleMessage中,把请求发到socket服务端RILD。
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
class RILSender extends Handler implements Runnable { /* 继承Handler,实现Runnable */
public RILSender(Looper looper) {
super(looper);
} ... ... //***** Handler implementation
@Override public void
handleMessage(Message msg) { /* 继承Handler的handleMessage */
RILRequest rr = (RILRequest)(msg.obj); /* Maessage中携带的RILRequest对象 */
RILRequest req = null; switch (msg.what) {
case EVENT_SEND: /* 发送RIL请求事件 */
try {
LocalSocket s; s = mSocket; /* RILReceiver中创建的用于与RILD通讯的socket */ ... ... synchronized (mRequestList) { /* 多线程保护操作mRequestList */
mRequestList.append(rr.mSerial, rr); /* 把接受到的RILRequest和对应的串号,存到mRequestList数据 */
} byte[] data;
data = rr.mParcel.marshall(); /* 把Parcel中的数据转换为byte数据 */
rr.mParcel.recycle(); /* Parcel的内存回收 */
rr.mParcel = null; ... ... // parcel length in big endian
dataLength[0] = dataLength[1] = 0; /* RIL请求包的大小为4个字节 */
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff); //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes"); s.getOutputStream().write(dataLength); /* 把包大小和包数据发送出去 */
s.getOutputStream().write(data);
} catch (IOException ex) {
Rlog.e(RILJ_LOG_TAG, "IOException", ex);
req = findAndRemoveRequestFromList(rr.mSerial); /* 如果出现异常,则把串号对应的RILRequest从mRequestList中删除 */
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
rr.release();
decrementWakeLock();
}
} ... ...
}
}
}
(B) RILD进程
RILD作为一个独立的进程,telephony与modem之间的通讯通道。抽象出一些接口以适配不同的modem厂商,无需关心具体的
硬件操作,或者以哪种形式存存在于系统(modem作为CP集成于CPU或CPU通过串口/USB连接,如: BC72 LTE模块)。因为这些接口
由厂商去实现具体的硬件操作细节,这些接口都在libreference-ril中,在Android中使用BC72 LTE模块,只要移植
libreference-ril就行。
1. RILD的启动
RILD有init进程直接启动,启动后就监听RILJ客户端,等待RILJ连接请求。
device/samsung/smdk4x12/conf/init.smdk4x12.rc
service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
hardware/ril/rild/rild.c为RILD进程入口:
hardware/ril/rild/rild.c
int main(int argc, char **argv)
{
... ... dlHandle = dlopen(rilLibPath, RTLD_NOW); /* 打开/system/lib/libreference-ril.so */ if (dlHandle == NULL) {
RLOGE("dlopen failed: %s", dlerror());
exit(-);
} RIL_startEventLoop(); /* 创建eventLoop线程, 在ril_event_loop()中监听多路IO的事件,如主动唤醒事件(pipe)、RILJ的请求等 */ /* 获取/system/lib/libreference-ril.so中RIL_Init函数指针 */
rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
if (rilInit == NULL) {
RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
exit(-);
} if (hasLibArgs) {
rilArgv = argv + i - ;
argc = argc -i + ;
} else {
static char * newArgv[MAX_LIB_ARGS];
static char args[PROPERTY_VALUE_MAX];
rilArgv = newArgv;
property_get(LIB_ARGS_PROPERTY, args, "");
argc = make_argv(args, rilArgv);
} // Make sure there's a reasonable argv[0]
rilArgv[] = argv[]; funcs = rilInit(&s_rilEnv, argc, rilArgv); /* 初始化Vender RIL */ RIL_register(funcs); /* 注册RIL */ ... ...
}
hardware/ril/libril/ril.cpp
extern "C" void
RIL_startEventLoop(void) { ... ... ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); /* 创建eventLoop线程 */ ... ...
} static void *
eventLoop(void *param) {
int ret;
int filedes[]; ril_event_init(); /* 初始化事件链表,timer_list,pending_list, watch_table */ pthread_mutex_lock(&s_startupMutex); s_started = ;
pthread_cond_broadcast(&s_startupCond); pthread_mutex_unlock(&s_startupMutex); ret = pipe(filedes); /* 创建一个pipe,用于每次添加一个新事件时,唤醒selet()返回,更新fd_set使select监听新的事件 */ if (ret < ) {
RLOGE("Error in pipe() errno:%d", errno);
return NULL;
} s_fdWakeupRead = filedes[]; /* filedes[0]用于读pipe, filedes[1]用于写pipe */
s_fdWakeupWrite = filedes[]; fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); /* 以非阻塞的方式读pipe */ ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, /* 读pipe描述符绑定到s_wakeupfd_event事件,指定回调processWakeupCallback */
processWakeupCallback, NULL); rilEventAddWakeup (&s_wakeupfd_event); /* 添加s_wakeupfd_event事件到watch_table,更新readFds集合,使select监听该事件,并触发该事件 */ // Only returns on error
ril_event_loop(); /* 进入多路IO事件监听循环 */
RLOGE ("error in event_loop_base errno:%d", errno);
// kill self to restart on error
kill(, SIGKILL); return NULL;
}
main函数主要启动eventLoop线程,在ril_event_loop()中监听多路IO的事件,如主动唤醒事件(pipe)、RILJ的请求等,
注册vendor RIL接口(libreference-ril)
注意这里pipe的主要作用是唤醒select返回,因为每次动态的添加一个事件,都要更新readFds集合,方便select监听
集合中新的IO。
rilEventAddWakeup()添加新事件后,都会触发select返回
hardware/ril/libril/ril.cpp
static void rilEventAddWakeup(struct ril_event *ev) {
ril_event_add(ev); /* 添加事件 */
triggerEvLoop(); /* 触发事件, 每添加一个事件,都通过写pipe唤醒select,以更新多路IO集合,使能够监听该事件 */
}
hardware/ril/libril/ril_event.cpp
void ril_event_add(struct ril_event * ev)
{
dlog("~~~~ +ril_event_add ~~~~");
MUTEX_ACQUIRE();
for (int i = ; i < MAX_FD_EVENTS; i++) {
if (watch_table[i] == NULL) {
watch_table[i] = ev; /* 将新事件添加到watch_table */
ev->index = i;
dlog("~~~~ added at %d ~~~~", i);
dump_event(ev);
FD_SET(ev->fd, &readFds); /* 更新readFds集合 */
if (ev->fd >= nfds) nfds = ev->fd+; /* 更新nfds */
dlog("~~~~ nfds = %d ~~~~", nfds);
break;
}
}
MUTEX_RELEASE();
dlog("~~~~ -ril_event_add ~~~~");
}
hardware/ril/libril/ril.cpp
static void triggerEvLoop() {
int ret;
if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
/* trigger event loop to wakeup. No reason to do this,
* if we're in the event loop thread */
do {
ret = write (s_fdWakeupWrite, " ", ); /* 向pipe写入一个" ",以唤醒select */
} while (ret < && errno == EINTR);
}
}
在ril_event_loop()接收到事件或socket客户端RILJ发过来的请求后,firePending()根据事件请求,调用相应的处理函数
hardware/ril/libril/ril_event.cpp
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv; for (;;) { // make local copy of read fd_set
memcpy(&rfds, &readFds, sizeof(fd_set));
if (- == calcNextTimeout(&tv)) { /* 计算timer_list链表中每个事件对应的超时时间 */
// no pending timers; block indefinitely
dlog("~~~~ no timers; blocking indefinitely ~~~~");
ptv = NULL;
} else {
dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
ptv = &tv;
}
printReadies(&rfds);
n = select(nfds, &rfds, NULL, NULL, ptv); /* 等待readFds集合中的事件唤醒 */
printReadies(&rfds);
dlog("~~~~ %d events fired ~~~~", n);
if (n < ) {
if (errno == EINTR) continue; RLOGE("ril_event: select error (%d)", errno);
// bail?
return;
} // Check for timeouts
processTimeouts(); /* 检查timer_list链表中是否有事件已经超时 */
// Check for read-ready
processReadReadies(&rfds, n); /* 从watch_table中取出监听到的事件, 并添加到pending_list链表 */
// Fire away
firePending(); /* 从pending_list依次取出事件,并执行该事件的回调 */
}
} static void processTimeouts()
{
dlog("~~~~ +processTimeouts ~~~~");
MUTEX_ACQUIRE();
struct timeval now;
struct ril_event * tev = timer_list.next;
struct ril_event * next; getNow(&now);
// walk list, see if now >= ev->timeout for any events
/* 检查timer_list链表中是否有事件已经超时 */
dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
// Timer expired
dlog("~~~~ firing timer ~~~~");
next = tev->next;
removeFromList(tev); /* 将该超时移出链表 */
addToList(tev, &pending_list); /* 并且将该超时添加到pending链表 */
tev = next; /* 指针指向下一个超时 */
}
MUTEX_RELEASE();
dlog("~~~~ -processTimeouts ~~~~");
} static void processReadReadies(fd_set * rfds, int n)
{
dlog("~~~~ +processReadReadies (%d) ~~~~", n);
MUTEX_ACQUIRE(); for (int i = ; (i < MAX_FD_EVENTS) && (n > ); i++) {
struct ril_event * rev = watch_table[i];
if (rev != NULL && FD_ISSET(rev->fd, rfds)) { /* 从watch_table中取出监听到的事件 */
addToList(rev, &pending_list); /* 并把该事件加入pending_list链表 */
if (rev->persist == false) { /* 如果该事件不需要处理,则移出removeWatch */
removeWatch(rev, i);
}
n--;
}
} MUTEX_RELEASE();
dlog("~~~~ -processReadReadies (%d) ~~~~", n);
} static void firePending()
{
dlog("~~~~ +firePending ~~~~");
struct ril_event * ev = pending_list.next;
while (ev != &pending_list) { /* 从pending_list依次取出事件 */
struct ril_event * next = ev->next;
removeFromList(ev);
ev->func(ev->fd, , ev->param); /* 并执行该事件的回调 */
ev = next;
}
dlog("~~~~ -firePending ~~~~");
}
上面分析了RIL_startEventLoop()的事件流程,简单总结就是根据事件调用该事件的处理函数。
到这里还没说到怎样创建socket服务端的,回到mian(),funcs = rilInit(&s_rilEnv, argc, rilArgv);
初始化了libreference-ril,RIL_register(funcs);注册了厂商须实现的相关接口,创建socket服务端的,
并监听客户端连接,一旦连接,则开始等待读取客户端发过来的请求。
hardware/ril/libril/ril.cpp
extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) { ... ... s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); /* 创建socket服务端,用于与RILJ通信 */
if (s_fdListen < ) {
RLOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
exit(-);
} ret = listen(s_fdListen, ); /* 监听RILJ */ if (ret < ) {
RLOGE("Failed to listen on control socket '%d': %s",
s_fdListen, strerror(errno));
exit(-);
} /* note: non-persistent so we can accept only one connection at a time */
ril_event_set (&s_listen_event, s_fdListen, false, /* 设置一个监听事件s_listen_event,一旦与RILJ建立连 */
listenCallback, NULL); /* 则进入listenCallback,等待读取RILJ发送数据 */ rilEventAddWakeup (&s_listen_event); /* 添加s_listen_event到watch_table, 唤醒select */ ... ...
} static void listenCallback (int fd, short flags, void *param) { ... ... s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen); /* 接受RILJ客户端的连接 */ ... ... err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK); /* 非阻塞方式读写socket */ if (ret < ) {
RLOGE ("Error setting O_NONBLOCK errno:%d", errno);
} RLOGI("libril: new connection"); p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES); /* 创建一个stream用于缓存读socket的数据 */ ril_event_set (&s_commands_event, s_fdCommand, , /* 设置s_commands_event,processCommandsCallback循环读取socket的数据 */
processCommandsCallback, p_rs); rilEventAddWakeup (&s_commands_event); /* 添加s_commands_event事件,唤醒select */ onNewCommandConnect(); /* 通知RILJ已建立连接 */
} static void processCommandsCallback(int fd, short flags, void *param) { ... ... for (;;) {
/* loop until EAGAIN/EINTR, end of stream, or other error */
ret = record_stream_get_next(p_rs, &p_record, &recordlen); /* 循环从数据流中读取socket数据 */ if (ret == && p_record == NULL) {
/* end-of-stream */
break;
} else if (ret < ) {
break;
} else if (ret == ) { /* && p_record != NULL */
processCommandBuffer(p_record, recordlen); /* 对接受到的数据进行组包,下发给vender ril,即libreference-ril.so */
}
}
}
processCommandBuffer(p_record, recordlen)对接收到的数据进行组包,下发给vender ril,即libreference-ril.so,
然后就脱离了RILD的控制了,libreference-ril.so主要是厂商对RILD控制modem接口的实现。
hardware/ril/libril/ril.cpp
static int
processCommandBuffer(void *buffer, size_t buflen) { ... ... p.setData((uint8_t *) buffer, buflen); /* 把接受到的数据填装到parcel */ // status checked at end
status = p.readInt32(&request); /* 解析request */
status = p.readInt32 (&token); /* 解析token,RILJ中的serial */ ... ... pRI = (RequestInfo *)calloc(, sizeof(RequestInfo)); /* 分配一个RequestInfo,用于发送请求给vendor ril */ pRI->token = token; /* 设置token */
pRI->pCI = &(s_commands[request]); /* 设置请求 */ ret = pthread_mutex_lock(&s_pendingRequestsMutex);
assert (ret == ); pRI->p_next = s_pendingRequests; /* 添加到s_pendingRequests请求链表中 */
s_pendingRequests = pRI; ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
assert (ret == ); /* sLastDispatchedToken = token; */ pRI->pCI->dispatchFunction(p, pRI); /* 执行事件回调,到这里开始进入vender ril了 */ return ;
}
我们仍然以获取SIM卡状态为例,pRI->pCI->dispatchFunction(p, pRI)对应调用了dispatchVoid()
hardware/ril/libril/ril.cpp
static void
dispatchVoid (Parcel& p, RequestInfo *pRI) {
clearPrintBuf;
printRequest(pRI->token, pRI->pCI->requestNumber);
s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, , pRI);
}
s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI); 调用的就是libreference-ril.c中的onRequest()函数。
以上分析了RILD对RILJ下发的请求处理流程,下面接着分析RILD返回response给RILJ的流程。分两种情况,一种对请求的响应,
另一种是主动上报。
libreference-ril对请求处理完毕后,调用RIL_onRequestComplete回复RILJ该请求的处理结果。
hardware/ril/libril/ril.cpp
RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { ... ...
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);
errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) {
// there is a response payload, no matter success or not.
ret = pRI->pCI->responseFunction(p, response, responselen); ... ...
} ... ... sendResponse(p); ... ...
} static int
sendResponse (Parcel &p) {
printResponse;
return sendResponseRaw(p.data(), p.dataSize());
} static int
sendResponseRaw (const void *data, size_t dataSize) {
... ... ret = blockingWrite(fd, (void *)&header, sizeof(header)); /* 先写4字节数据长度 */ if (ret < ) {
pthread_mutex_unlock(&s_writeMutex);
return ret;
} ret = blockingWrite(fd, data, dataSize); /* 再写数据 */ ... ...
}
最终是通过sendResponseRaw()直接通过写socket回复RILJ。对于主动上报的处理是类似的,也是通过sendResponseRaw()
上报给RILJ。可以参考RIL_onUnsolicitedResponse()函数。
到此,RILJ与RILD之间的通信流程已经分析完,后续分析libreference-ril。libreference-ril中先关接口的实现方式,每个modem厂商都不一样。
BC72是通过串口/USB发送AT的方式控制,实现通话、短信、上网等功能。
谢谢!
Android4.4 RIL软件框架的更多相关文章
- linux内核中的GPIO系统之(1):软件框架
一.前言 作为一个工作多年的系统工程师,免不了做两件事情:培训新员工和给新员工分配任务.对于那些刚刚从学校出来的学生,一般在开始的时候总是分配一些非常简单的任务,例如GPIO driver.LED d ...
- DM8168 DVRRDK软件框架研究
转载注明:http://blog.csdn.net/guo8113/article/details/41120491 Netra(DM8168)处理器是个多核处理器,每一个核之间相互独立却又相互关联, ...
- Niagara解决设备连接应用的软件框架平台技术。
Niagara 是Tridium公司所研发的设计用于解决设备连接应用的软件框架平台技术. Niagara是一种应用框架,或者说是软件框架,特别设计用于应对智能设备所带来的各种挑战,包括设备连接到企业级 ...
- WinForm酒店管理软件--框架
WinForm酒店管理软件--框架 搞软件开发4年多了,现在自认为还是菜鸟,从一开始走上工作岗位各种技术对我都很新奇没解决一个问题都觉得很伟大到后来开始对出路的迷茫,到现在我坚信学什么技术不重要,做什 ...
- CDIF: 基于JSON的SOA软件框架
通用设备互联框架(CDIF)是一个具备中美知识产权保护的,基于web的连接框架,目前有部分开源实现存放在: GitHub - out4b/cdif: Common device interconnec ...
- CDIF:基于JSON的SOA软件框架
通用设备互联框架(CDIF)是一个具备中美知识产权保护的,基于web的连接框架,目前有部分开源实现存放在: GitHub - out4b/cdif: Common device interconnec ...
- django基础-01:软件框架,MVC框架,MVT
1. 软件框架 一个公司是由公司中的各部部门来组成的,每一个部门拥有特定的职能,部门与部门之间通过相互的配合来完成让公司运转起来. 一个软件框架是由其中各个软件模块组成的,每一个模块都有特定的功能,模 ...
- android资讯类软件框架《IT蓝豹》
android资讯类软件框架 android资讯类软件框架,支持侧滑,并且首页viewpager切换tab,tab滑动到最右侧的时候提示滑动结束, 滑动到最左侧的时候切换滑动侧滑menu.左滑和侧滑处 ...
- Mindjet MindManager 思维导图软件-使用思维导图跟踪调用流程,绘制软件框架
思维导图.据说是每一个产品经理必备的软件.假设你阅读大型源码.使用思维导图跟踪调用流程,绘制软件框架将会很方便. 特点:没什么好说的.用过的都说好. 软件截图: 下载:http://www.mindm ...
随机推荐
- Kafka源码分析及图解原理之Producer端
一.前言 任何消息队列都是万变不离其宗都是3部分,消息生产者(Producer).消息消费者(Consumer)和服务载体(在Kafka中用Broker指代).那么本篇主要讲解Producer端,会有 ...
- vim 高级功能
本文章原创首发于公众号:编程三分钟 ,文末二维码. 文本编辑.跳转.删除.复制.替换这些操作用vim确实是快:但是好像仅仅是这样根本不能说服我vim超过鼠标的地方. 花点时间弄熟这些,除了炫技意外,主 ...
- equals、==、hashCode
equals和==的区别 ==主要用来比较基本数据类型,而equal主要用来比较对象是否相等.equal是Object的方法. 如果两者都用来比较对象的相等性,那么如果两个引用地址相同,那么==就返回 ...
- IntelliJ IDEA远程连接tomcat,实现单步调试
web项目部署到tomcat上之后,有时需要打断点单步调试,如果用的是Intellij idea,可以通过如下方法实现: 开启debug端口,启动tomcat 以tomcat7.0.75为例,打开bi ...
- 机器学习常用性能度量中的Accuracy、Precision、Recall、ROC、F score等都是些什么东西?
一篇文章就搞懂啦,这个必须收藏! 我们以图片分类来举例,当然换成文本.语音等也是一样的. Positive 正样本.比如你要识别一组图片是不是猫,那么你预测某张图片是猫,这张图片就被预测成了正样本. ...
- Properties -IO相关的双列集合类
IO相关的集合类 java.util.Properties集合 extends hashtable(淘汰) Properties类表示了一个持久的属性集.Properties可保存流中或从流中加载 P ...
- Wordpress对接小程序配置过程
最近发现一个很棒的开源项目-WordPress版微信小程序 https://github.com/iamxjb/winxin-app-watch-life.net,详细看了下介绍非常棒,不仅支持的功 ...
- ZIP压缩和解压字符串
由于ZIP压缩会产生头信息, 所以当字符串长度没有达到一定规模的时候, 压缩后的长度可能比原来的还长 // 将一个字符串按照zip方式压缩和解压缩 public class ZipUtil { // ...
- selenium基于java 一 软件安装
学习网站 http://www.testclass.net/selenium_java/ 一·安装java环境及eclipse,网上教程较多不讲 二·下载火狐浏览器(旧版) 下载地址:链接: http ...
- 心动吗?正大光明的免费使用IntelliJ IDEA商业版
IntelliJ IDEA是广受Java开发者喜爱的工具,其商业版的价格十分昂贵,如下图: 现在有机会免费获取IntelliJ IDEA的正版License,您是否心动呢?我把自己成功申请Licens ...