经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android4.4 RIL软件框架
来源:cnblogs  作者:hackfun  时间:2019/10/18 8:34:24  对本文有异议

    文主要对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

  1. @Override
  2. public void
  3. getIccCardStatus(Message result) {
  4. //Note: This RIL request has not been renamed to ICC,
  5. // but this request is also valid for SIM and RUIM
  6. RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); /* 获取一个RILRequest */
  7. if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); /* 参考log:[3653]> GET_SIM_STATUS */
  8. send(rr); /* 发送请求 */
  9. }

 

       RILRequest.obtain是从内存池获取一个RILRequest实例,并初始化:

       frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

  1. class RILRequest {
  2. static final String LOG_TAG = "RilRequest";
  3. ... ...
  4. static RILRequest obtain(int request, Message result) {
  5. RILRequest rr = null;
  6. synchronized(sPoolSync) { /* 从内存池中取出一个RILRequest对象*/
  7. if (sPool != null) {
  8. rr = sPool;
  9. sPool = rr.mNext;
  10. rr.mNext = null;
  11. sPoolSize--;
  12. }
  13. }
  14. if (rr == null) { /* 如果内存池中没有,则实例化一个 */
  15. rr = new RILRequest();
  16. }
  17. rr.mSerial = sNextSerial.getAndIncrement(); /* 获取串号,并且+1 */
  18. rr.mRequest = request; /* 对应RIL_REQUEST_*请求 */
  19. rr.mResult = result;
  20. rr.mParcel = Parcel.obtain(); /* 初始化一个Parcel,用于封包以发送给底层RILD */
  21. if (result != null && result.getTarget() == null) {
  22. throw new NullPointerException("Message target must not be null");
  23. }
  24. // first elements in any RIL Parcel
  25. rr.mParcel.writeInt(request); /* 每个RIL Parcel最开始也最基本的两个元素 */
  26. rr.mParcel.writeInt(rr.mSerial);
  27. return rr; /* 返回这个从内存池中获取的实例 */
  28. }
  29. ... ...
  30. String
  31. serialString() {
  32. //Cheesy way to do %04d
  33. StringBuilder sb = new StringBuilder(8); /* 创建一个StringBuilder实例用于操作字符串 */
  34. String sn;
  35. long adjustedSerial = (((long)mSerial) - Integer.MIN_VALUE)%10000;
  36. sn = Long.toString(adjustedSerial); /* 把数值转换成字符串 */
  37.  
  38. //sb.append("J[");
  39. sb.append('[');
  40. for (int i = 0, s = sn.length() ; i < 4 - s; i++) {
  41. sb.append('0');
  42. }
  43. sb.append(sn);
  44. sb.append(']');
  45. return sb.toString(); /* 转换出来的字符串格式: [xxxx] */
  46. }
  47. ... ...
  48. }

 

send(rr)发送请求到服务端:
frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

  1. private void
  2. send(RILRequest rr) {
  3. Message msg;
  4. ... ...
  5. msg = mSender.obtainMessage(EVENT_SEND, rr); /* 发送EVENT_SEND时间,时间参数为RILRequest */
  6. acquireWakeLock(); /* 获取wakelock,禁止进入休眠 */
  7. msg.sendToTarget(); /* message从handler类获取,从而可以直接向该handler对象发送消息。target就是创建message的handler */
  8. }

 

        实际上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

  1. public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
  2. ... ...
  3. mSenderThread = new HandlerThread("RILSender"); /* 创建RILSender线程 */
  4. mSenderThread.start();
  5. Looper looper = mSenderThread.getLooper();
  6. mSender = new RILSender(looper);
  7. ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
  8. Context.CONNECTIVITY_SERVICE);
  9. if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
  10. riljLog("Not starting RILReceiver: wifi-only");
  11. } else {
  12. riljLog("Starting RILReceiver");
  13. mReceiver = new RILReceiver();
  14. mReceiverThread = new Thread(mReceiver, "RILReceiver"); /* 创建RILReceiver线程 */
  15. mReceiverThread.start();
  16. ... ...
  17. }
  18. ... ...
  19. }
  20. class RILReceiver implements Runnable {
  21. byte[] buffer;
  22. RILReceiver() { /* 构造时,分配一个数组 */
  23. buffer = new byte[RIL_MAX_COMMAND_BYTES];
  24. }
  25. @Override
  26. public void
  27. run() { /* 循环读取从RILD返回或主动上报的数据 */
  28. int retryCount = 0;
  29. try {for (;;) {
  30. LocalSocket s = null;
  31. LocalSocketAddress l;
  32. try {
  33. s = new LocalSocket(); /* 创建一个socket客户端 */
  34. l = new LocalSocketAddress(SOCKET_NAME_RIL,
  35. LocalSocketAddress.Namespace.RESERVED);
  36. s.connect(l); /* 连接服务器 */
  37. }
  38. ... ...
  39. }
  40. ... ...
  41. try {
  42. InputStream is = mSocket.getInputStream(); /* 循环读取socket的数据 */
  43.  
  44. for (;;) {
  45. Parcel p;
  46. length = readRilMessage(is, buffer); /* 解析socket数据 */
  47.  
  48. if (length < 0) {
  49. // End-of-stream reached
  50. break;
  51. }
  52. p = Parcel.obtain(); /* 获取一个Parcel */
  53. p.unmarshall(buffer, 0, length); /* 读取出来的就是之前序列化的byte数组,所以要进行一个反序列化操作 */
  54. p.setDataPosition(0); /* 从buffer转换到Parcel之后,需要将指针手动指向到最初的位置 */
  55.  
  56. //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");
  57. processResponse(p);
  58. p.recycle(); /* 数据处理完后,需要回收Parcel的内存 */
  59. }
  60. }
  61. ... ...
  62. }

 

        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

  1. private static int readRilMessage(InputStream is, byte[] buffer)
  2. throws IOException {
  3. int countRead;
  4. int offset;
  5. int remaining;
  6. int messageLength;
  7. // First, read in the length of the message
  8. offset = 0;
  9. remaining = 4;
  10. do {
  11. countRead = is.read(buffer, offset, remaining); /* 读出消息的4字节长度 */
  12.  
  13. if (countRead < 0 ) {
  14. Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length");
  15. return -1;
  16. }
  17. offset += countRead;
  18. remaining -= countRead;
  19. } while (remaining > 0);
  20. messageLength = ((buffer[0] & 0xff) << 24) /* 获取长度 */
  21. | ((buffer[1] & 0xff) << 16)
  22. | ((buffer[2] & 0xff) << 8)
  23. | (buffer[3] & 0xff);
  24. // Then, re-use the buffer and read in the message itself
  25. offset = 0;
  26. remaining = messageLength;
  27. do {
  28. countRead = is.read(buffer, offset, remaining); /* 读取剩余的数据 */
  29.  
  30. if (countRead < 0 ) {
  31. Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength
  32. + " remaining=" + remaining);
  33. return -1;
  34. }
  35. offset += countRead;
  36. remaining -= countRead;
  37. } while (remaining > 0);
  38. return messageLength;
  39. }
  40. private void
  41. processResponse (Parcel p) {
  42. int type;
  43. type = p.readInt(); /* 从RILD返回的数据第一个字节,表示请求的返回类型:RESPONSE_UNSOLICITED/RESPONSE_SOLICITED */
  44.  
  45. if (type == RESPONSE_UNSOLICITED) {
  46. processUnsolicited (p); /* 主动上报 */
  47. } else if (type == RESPONSE_SOLICITED) {
  48. RILRequest rr = processSolicited (p); /* 普通请求对应的同步上报 */
  49. if (rr != null) {
  50. rr.release(); /* 释放对应的RILRequest内存和wakelock */
  51. decrementWakeLock();
  52. }
  53. }
  54. }

 

        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

  1. private RILRequest
  2. processSolicited (Parcel p) {
  3. int serial, error;
  4. boolean found = false;
  5. serial = p.readInt(); /* 串号,也就是token */
  6. error = p.readInt(); /* 错误码 */
  7. RILRequest rr;
  8. rr = findAndRemoveRequestFromList(serial); /* 根据taken取出对应的RILRequest */
  9. ... ...
  10. */
  11. case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break;
  12. ... ...
  13. if (rr.mResult != null) {
  14. AsyncResult.forMessage(rr.mResult, ret, null); /* 把rr.mResult存到AsyncResult.userObj,并把rr.mResult.obj转换为AsyncResult */
  15. rr.mResult.sendToTarget(); /* msg发送到对应的target(Handler) */
  16. }
  17. ... ...
  18. }
  19. private Object
  20. responseIccCardStatus(Parcel p) {
  21. IccCardApplicationStatus appStatus;
  22. ... ...
  23. appStatus = new IccCardApplicationStatus();
  24. ... ...
  25. return cardStatus;
  26. }

 

        回到刚才send(rr),send(rr)并不是直接发送到socket服务端RILD,而是通过一个Message发送到RILSender线程,
在handleMessage中,把请求发到socket服务端RILD。

frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

  1. class RILSender extends Handler implements Runnable { /* 继承Handler,实现Runnable */
  2. public RILSender(Looper looper) {
  3. super(looper);
  4. }
  5. ... ...
  6. //***** Handler implementation
  7. @Override public void
  8. handleMessage(Message msg) { /* 继承Handler的handleMessage */
  9. RILRequest rr = (RILRequest)(msg.obj); /* Maessage中携带的RILRequest对象 */
  10. RILRequest req = null;
  11. switch (msg.what) {
  12. case EVENT_SEND: /* 发送RIL请求事件 */
  13. try {
  14. LocalSocket s;
  15. s = mSocket; /* RILReceiver中创建的用于与RILD通讯的socket */
  16. ... ...
  17. synchronized (mRequestList) { /* 多线程保护操作mRequestList */
  18. mRequestList.append(rr.mSerial, rr); /* 把接受到的RILRequest和对应的串号,存到mRequestList数据 */
  19. }
  20. byte[] data;
  21. data = rr.mParcel.marshall(); /* 把Parcel中的数据转换为byte数据 */
  22. rr.mParcel.recycle(); /* Parcel的内存回收 */
  23. rr.mParcel = null;
  24. ... ...
  25. // parcel length in big endian
  26. dataLength[0] = dataLength[1] = 0; /* RIL请求包的大小为4个字节 */
  27. dataLength[2] = (byte)((data.length >> 8) & 0xff);
  28. dataLength[3] = (byte)((data.length) & 0xff);
  29. //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");
  30. s.getOutputStream().write(dataLength); /* 把包大小和包数据发送出去 */
  31. s.getOutputStream().write(data);
  32. } catch (IOException ex) {
  33. Rlog.e(RILJ_LOG_TAG, "IOException", ex);
  34. req = findAndRemoveRequestFromList(rr.mSerial); /* 如果出现异常,则把串号对应的RILRequest从mRequestList中删除 */
  35. // make sure this request has not already been handled,
  36. // eg, if RILReceiver cleared the list.
  37. if (req != null) {
  38. rr.onError(RADIO_NOT_AVAILABLE, null);
  39. rr.release();
  40. decrementWakeLock();
  41. }
  42. }
  43. ... ...
  44. }
  45. }
  46. }

 

 

(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

  1. service ril-daemon /system/bin/rild -l /system/lib/libreference-ril.so
  2. class main
  3. socket rild stream 660 root radio
  4. socket rild-debug stream 660 radio system
  5. user root

 

        hardware/ril/rild/rild.c为RILD进程入口:

        hardware/ril/rild/rild.c

  1. int main(int argc, char **argv)
  2. {
  3. ... ...
  4. dlHandle = dlopen(rilLibPath, RTLD_NOW); /* 打开/system/lib/libreference-ril.so */
  5.  
  6. if (dlHandle == NULL) {
  7. RLOGE("dlopen failed: %s", dlerror());
  8. exit(-1);
  9. }
  10. RIL_startEventLoop(); /* 创建eventLoop线程, 在ril_event_loop()中监听多路IO的事件,如主动唤醒事件(pipe)、RILJ的请求等 */
  11.  
  12. /* 获取/system/lib/libreference-ril.so中RIL_Init函数指针 */
  13. rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
  14. if (rilInit == NULL) {
  15. RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
  16. exit(-1);
  17. }
  18. if (hasLibArgs) {
  19. rilArgv = argv + i - 1;
  20. argc = argc -i + 1;
  21. } else {
  22. static char * newArgv[MAX_LIB_ARGS];
  23. static char args[PROPERTY_VALUE_MAX];
  24. rilArgv = newArgv;
  25. property_get(LIB_ARGS_PROPERTY, args, "");
  26. argc = make_argv(args, rilArgv);
  27. }
  28. // Make sure there's a reasonable argv[0]
  29. rilArgv[0] = argv[0];
  30. funcs = rilInit(&s_rilEnv, argc, rilArgv); /* 初始化Vender RIL */
  31. RIL_register(funcs); /* 注册RIL */
  32. ... ...
  33. }

 

hardware/ril/libril/ril.cpp

  1. extern "C" void
  2. RIL_startEventLoop(void) {
  3. ... ...
  4. ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); /* 创建eventLoop线程 */
  5. ... ...
  6. }
  7. static void *
  8. eventLoop(void *param) {
  9. int ret;
  10. int filedes[2];
  11. ril_event_init(); /* 初始化事件链表,timer_list,pending_list, watch_table */
  12. pthread_mutex_lock(&s_startupMutex);
  13. s_started = 1;
  14. pthread_cond_broadcast(&s_startupCond);
  15. pthread_mutex_unlock(&s_startupMutex);
  16. ret = pipe(filedes); /* 创建一个pipe,用于每次添加一个新事件时,唤醒selet()返回,更新fd_set使select监听新的事件 */
  17.  
  18. if (ret < 0) {
  19. RLOGE("Error in pipe() errno:%d", errno);
  20. return NULL;
  21. }
  22. s_fdWakeupRead = filedes[0]; /* filedes[0]用于读pipe, filedes[1]用于写pipe */
  23. s_fdWakeupWrite = filedes[1];
  24. fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); /* 以非阻塞的方式读pipe */
  25. ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, /* 读pipe描述符绑定到s_wakeupfd_event事件,指定回调processWakeupCallback */
  26. processWakeupCallback, NULL);
  27. rilEventAddWakeup (&s_wakeupfd_event); /* 添加s_wakeupfd_event事件到watch_table,更新readFds集合,使select监听该事件,并触发该事件 */
  28.  
  29. // Only returns on error
  30. ril_event_loop(); /* 进入多路IO事件监听循环 */
  31. RLOGE ("error in event_loop_base errno:%d", errno);
  32. // kill self to restart on error
  33. kill(0, SIGKILL);
  34. return NULL;
  35. }

 

        main函数主要启动eventLoop线程,在ril_event_loop()中监听多路IO的事件,如主动唤醒事件(pipe)、RILJ的请求等,
注册vendor RIL接口(libreference-ril)
        注意这里pipe的主要作用是唤醒select返回,因为每次动态的添加一个事件,都要更新readFds集合,方便select监听
集合中新的IO。
        rilEventAddWakeup()添加新事件后,都会触发select返回

hardware/ril/libril/ril.cpp

  1. static void rilEventAddWakeup(struct ril_event *ev) {
  2. ril_event_add(ev); /* 添加事件 */
  3. triggerEvLoop(); /* 触发事件, 每添加一个事件,都通过写pipe唤醒select,以更新多路IO集合,使能够监听该事件 */
  4. }

 

hardware/ril/libril/ril_event.cpp

  1. void ril_event_add(struct ril_event * ev)
  2. {
  3. dlog("~~~~ +ril_event_add ~~~~");
  4. MUTEX_ACQUIRE();
  5. for (int i = 0; i < MAX_FD_EVENTS; i++) {
  6. if (watch_table[i] == NULL) {
  7. watch_table[i] = ev; /* 将新事件添加到watch_table */
  8. ev->index = i;
  9. dlog("~~~~ added at %d ~~~~", i);
  10. dump_event(ev);
  11. FD_SET(ev->fd, &readFds); /* 更新readFds集合 */
  12. if (ev->fd >= nfds) nfds = ev->fd+1; /* 更新nfds */
  13. dlog("~~~~ nfds = %d ~~~~", nfds);
  14. break;
  15. }
  16. }
  17. MUTEX_RELEASE();
  18. dlog("~~~~ -ril_event_add ~~~~");
  19. }

 

 hardware/ril/libril/ril.cpp

  1. static void triggerEvLoop() {
  2. int ret;
  3. if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
  4. /* trigger event loop to wakeup. No reason to do this,
  5. * if we're in the event loop thread */
  6. do {
  7. ret = write (s_fdWakeupWrite, " ", 1); /* 向pipe写入一个" ",以唤醒select */
  8. } while (ret < 0 && errno == EINTR);
  9. }
  10. }

 

在ril_event_loop()接收到事件或socket客户端RILJ发过来的请求后,firePending()根据事件请求,调用相应的处理函数
hardware/ril/libril/ril_event.cpp

  1. void ril_event_loop()
  2. {
  3. int n;
  4. fd_set rfds;
  5. struct timeval tv;
  6. struct timeval * ptv;
  7. for (;;) {
  8. // make local copy of read fd_set
  9. memcpy(&rfds, &readFds, sizeof(fd_set));
  10. if (-1 == calcNextTimeout(&tv)) { /* 计算timer_list链表中每个事件对应的超时时间 */
  11. // no pending timers; block indefinitely
  12. dlog("~~~~ no timers; blocking indefinitely ~~~~");
  13. ptv = NULL;
  14. } else {
  15. dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
  16. ptv = &tv;
  17. }
  18. printReadies(&rfds);
  19. n = select(nfds, &rfds, NULL, NULL, ptv); /* 等待readFds集合中的事件唤醒 */
  20. printReadies(&rfds);
  21. dlog("~~~~ %d events fired ~~~~", n);
  22. if (n < 0) {
  23. if (errno == EINTR) continue;
  24. RLOGE("ril_event: select error (%d)", errno);
  25. // bail?
  26. return;
  27. }
  28. // Check for timeouts
  29. processTimeouts(); /* 检查timer_list链表中是否有事件已经超时 */
  30. // Check for read-ready
  31. processReadReadies(&rfds, n); /* 从watch_table中取出监听到的事件, 并添加到pending_list链表 */
  32. // Fire away
  33. firePending(); /* 从pending_list依次取出事件,并执行该事件的回调 */
  34. }
  35. }
  36. static void processTimeouts()
  37. {
  38. dlog("~~~~ +processTimeouts ~~~~");
  39. MUTEX_ACQUIRE();
  40. struct timeval now;
  41. struct ril_event * tev = timer_list.next;
  42. struct ril_event * next;
  43. getNow(&now);
  44. // walk list, see if now >= ev->timeout for any events
  45. /* 检查timer_list链表中是否有事件已经超时 */
  46. dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
  47. while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
  48. // Timer expired
  49. dlog("~~~~ firing timer ~~~~");
  50. next = tev->next;
  51. removeFromList(tev); /* 将该超时移出链表 */
  52. addToList(tev, &pending_list); /* 并且将该超时添加到pending链表 */
  53. tev = next; /* 指针指向下一个超时 */
  54. }
  55. MUTEX_RELEASE();
  56. dlog("~~~~ -processTimeouts ~~~~");
  57. }
  58. static void processReadReadies(fd_set * rfds, int n)
  59. {
  60. dlog("~~~~ +processReadReadies (%d) ~~~~", n);
  61. MUTEX_ACQUIRE();
  62. for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
  63. struct ril_event * rev = watch_table[i];
  64. if (rev != NULL && FD_ISSET(rev->fd, rfds)) { /* 从watch_table中取出监听到的事件 */
  65. addToList(rev, &pending_list); /* 并把该事件加入pending_list链表 */
  66. if (rev->persist == false) { /* 如果该事件不需要处理,则移出removeWatch */
  67. removeWatch(rev, i);
  68. }
  69. n--;
  70. }
  71. }
  72. MUTEX_RELEASE();
  73. dlog("~~~~ -processReadReadies (%d) ~~~~", n);
  74. }
  75. static void firePending()
  76. {
  77. dlog("~~~~ +firePending ~~~~");
  78. struct ril_event * ev = pending_list.next;
  79. while (ev != &pending_list) { /* 从pending_list依次取出事件 */
  80. struct ril_event * next = ev->next;
  81. removeFromList(ev);
  82. ev->func(ev->fd, 0, ev->param); /* 并执行该事件的回调 */
  83. ev = next;
  84. }
  85. dlog("~~~~ -firePending ~~~~");
  86. }

 

        上面分析了RIL_startEventLoop()的事件流程,简单总结就是根据事件调用该事件的处理函数。
到这里还没说到怎样创建socket服务端的,回到mian(),funcs = rilInit(&s_rilEnv, argc, rilArgv);
初始化了libreference-ril,RIL_register(funcs);注册了厂商须实现的相关接口,创建socket服务端的,
并监听客户端连接,一旦连接,则开始等待读取客户端发过来的请求。

hardware/ril/libril/ril.cpp

  1. extern "C" void
  2. RIL_register (const RIL_RadioFunctions *callbacks) {
  3. ... ...
  4. s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); /* 创建socket服务端,用于与RILJ通信 */
  5. if (s_fdListen < 0) {
  6. RLOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
  7. exit(-1);
  8. }
  9. ret = listen(s_fdListen, 4); /* 监听RILJ */
  10.  
  11. if (ret < 0) {
  12. RLOGE("Failed to listen on control socket '%d': %s",
  13. s_fdListen, strerror(errno));
  14. exit(-1);
  15. }
  16. /* note: non-persistent so we can accept only one connection at a time */
  17. ril_event_set (&s_listen_event, s_fdListen, false, /* 设置一个监听事件s_listen_event,一旦与RILJ建立连 */
  18. listenCallback, NULL); /* 则进入listenCallback,等待读取RILJ发送数据 */
  19. rilEventAddWakeup (&s_listen_event); /* 添加s_listen_event到watch_table, 唤醒select */
  20. ... ...
  21. }
  22. static void listenCallback (int fd, short flags, void *param) {
  23. ... ...
  24. s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen); /* 接受RILJ客户端的连接 */
  25. ... ...
  26. err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
  27. ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK); /* 非阻塞方式读写socket */
  28.  
  29. if (ret < 0) {
  30. RLOGE ("Error setting O_NONBLOCK errno:%d", errno);
  31. }
  32. RLOGI("libril: new connection");
  33. p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES); /* 创建一个stream用于缓存读socket的数据 */
  34. ril_event_set (&s_commands_event, s_fdCommand, 1, /* 设置s_commands_event,processCommandsCallback循环读取socket的数据 */
  35. processCommandsCallback, p_rs);
  36. rilEventAddWakeup (&s_commands_event); /* 添加s_commands_event事件,唤醒select */
  37. onNewCommandConnect(); /* 通知RILJ已建立连接 */
  38. }
  39. static void processCommandsCallback(int fd, short flags, void *param) {
  40. ... ...
  41. for (;;) {
  42. /* loop until EAGAIN/EINTR, end of stream, or other error */
  43. ret = record_stream_get_next(p_rs, &p_record, &recordlen); /* 循环从数据流中读取socket数据 */
  44.  
  45. if (ret == 0 && p_record == NULL) {
  46. /* end-of-stream */
  47. break;
  48. } else if (ret < 0) {
  49. break;
  50. } else if (ret == 0) { /* && p_record != NULL */
  51. processCommandBuffer(p_record, recordlen); /* 对接受到的数据进行组包,下发给vender ril,即libreference-ril.so */
  52. }
  53. }
  54. }

 

        processCommandBuffer(p_record, recordlen)对接收到的数据进行组包,下发给vender ril,即libreference-ril.so,
然后就脱离了RILD的控制了,libreference-ril.so主要是厂商对RILD控制modem接口的实现。

hardware/ril/libril/ril.cpp

  1. static int
  2. processCommandBuffer(void *buffer, size_t buflen) {
  3. ... ...
  4. p.setData((uint8_t *) buffer, buflen); /* 把接受到的数据填装到parcel */
  5.  
  6. // status checked at end
  7. status = p.readInt32(&request); /* 解析request */
  8. status = p.readInt32 (&token); /* 解析token,RILJ中的serial */
  9. ... ...
  10. pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); /* 分配一个RequestInfo,用于发送请求给vendor ril */
  11. pRI->token = token; /* 设置token */
  12. pRI->pCI = &(s_commands[request]); /* 设置请求 */
  13. ret = pthread_mutex_lock(&s_pendingRequestsMutex);
  14. assert (ret == 0);
  15. pRI->p_next = s_pendingRequests; /* 添加到s_pendingRequests请求链表中 */
  16. s_pendingRequests = pRI;
  17. ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
  18. assert (ret == 0);
  19. /* sLastDispatchedToken = token; */
  20. pRI->pCI->dispatchFunction(p, pRI); /* 执行事件回调,到这里开始进入vender ril了 */
  21.  
  22. return 0;
  23. }

 

我们仍然以获取SIM卡状态为例,pRI->pCI->dispatchFunction(p, pRI)对应调用了dispatchVoid()
hardware/ril/libril/ril.cpp

  1. static void
  2. dispatchVoid (Parcel& p, RequestInfo *pRI) {
  3. clearPrintBuf;
  4. printRequest(pRI->token, pRI->pCI->requestNumber);
  5. s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI);
  6. }

 

        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

  1. RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
  2. ... ...
  3. p.writeInt32 (RESPONSE_SOLICITED);
  4. p.writeInt32 (pRI->token);
  5. errorOffset = p.dataPosition();
  6. p.writeInt32 (e);
  7. if (response != NULL) {
  8. // there is a response payload, no matter success or not.
  9. ret = pRI->pCI->responseFunction(p, response, responselen);
  10. ... ...
  11. }
  12. ... ...
  13. sendResponse(p);
  14. ... ...
  15. }
  16. static int
  17. sendResponse (Parcel &p) {
  18. printResponse;
  19. return sendResponseRaw(p.data(), p.dataSize());
  20. }
  21. static int
  22. sendResponseRaw (const void *data, size_t dataSize) {
  23. ... ...
  24. ret = blockingWrite(fd, (void *)&header, sizeof(header)); /* 先写4字节数据长度 */
  25.  
  26. if (ret < 0) {
  27. pthread_mutex_unlock(&s_writeMutex);
  28. return ret;
  29. }
  30. ret = blockingWrite(fd, data, dataSize); /* 再写数据 */
  31. ... ...
  32. }

 

        最终是通过sendResponseRaw()直接通过写socket回复RILJ。对于主动上报的处理是类似的,也是通过sendResponseRaw()
上报给RILJ。可以参考RIL_onUnsolicitedResponse()函数。

        到此,RILJ与RILD之间的通信流程已经分析完,后续分析libreference-ril。libreference-ril中先关接口的实现方式,每个modem厂商都不一样。
BC72是通过串口/USB发送AT的方式控制,实现通话、短信、上网等功能。

 

谢谢!

 

原文链接:http://www.cnblogs.com/hackfun/p/11693444.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号