目录
4.3.2 setResponseFunctions重要对象获取
1、概述
RIL是Radio Interface Layer 的简称,中文叫无线电接口层。针对Android系统,硬件上多采用双cpu的架构,一个是基带处理器,主要处理数字信号、语音信号的编码解码以及GSM通信协议;另一个是应用处理器,运行操作系统。而基带和应用处理器如何通信,Google针对此问题设计了RIL这样的一套框架,方便其他基带芯片厂家快速开发。本文档主要讲RILJ和RILD框架代码,RILJ是指RIL JAVA层的代码,RILD是指RIL C层的代码。
2、流程图
从流程图可以看出,RILJ和RILD的进程间通信是HIDL,早期他两通信是通过Socket。
- RILJ用于组装RILRequest消息,然后向RILD发送;
- RadioResponse用于处理RILRequest消息发送后,RILD处理后,回复的内容;
- RadioIndication用于RILD主动上报的消息;
- RILD是个进程,由init进程拉起来,向上跟RILJ通信,向下跟Modem通信;
- libril.so 这里创建了HIDL服务,跟RILJ通信,同时调用libreference-ril.so提供的接口进行消息处理;
- libreference-ril.so 在so收到RILJ消息后,把消息转到这来具体处理,同时此so也是跟Modem通信的地方。
3、RILJ
代码路径:$Android_root\frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java
RIL的初始化是在PhoneFactory.java类完成,具体是在函数makeDefaultPhone里。
从类图可以看到RIL.java继承BaseCommands.java,他们双共同实现CommandsInterface接口。这个操作我还是第一次见,从代码来看,其实就是有些CommandsInterface接口由父类BaseCommands完成,其他由子类RIL来完成。BaseCommands类的作用很单一,通过Registrant类来完成相关消息的注册和去注册。比如
RadioResponse和RadioIndication 是RIL消息收发的处理类。
OemHookResponse和OemHookIndication 是开放定制的消息收发处理类。
3.1初始化
- RIL消息处理类创建:此处获取RIL消息处理类的对象。
- 创建唤醒锁:当RIL消息有下发时,RIL会持有唤醒锁,保持RIL消息正常处理到结束。
- 获取HIDL服务:服务名是radio,服务由RILD创建,RILJ通过getService拿到此服务,后面通过此服务就可以直接调用RILD提供的接口。以getRadioProxy函数为例:
因为随功能扩展,radio服务也会增加新的功能,这些新的功能通过新版本来支持,继承关系。RILD支持radio哪个版本,相应RILJ获取到的是哪个版本。比如RILD支持的radio版本是1.3,那么上面代码就跑到1.3分支获取得到。此处的HIDL服务名是HIDL_SERVICE_NAME,见下面定义:
static final String[] HIDL_SERVICE_NAME = {"slot1", "slot2", "slot3"};
HIDL接口都是在$Android_root\hardware\interfaces里面定义,如radio定义见如下图。
3.2 Response消息处理机制
类RadioResponse.java是处理消息的同步机制,在获取HIDL接口后,会把此对象传给RILD,代码:mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
获取信号强度时序图:
RIL实现的接口是CommandsInterface.java,里面定义的接口都有共同的参数,
此Message参数是用来RIL消息的回复,下面通过讲解示例来学习处理机制。
如RIL.java向外提供了getSignalStrength获取信号强度的函数,外界调用的方式见frameworks\opt\telephony\src\java\com\android\internal\telephony\ServiceStateTracker.java的updatePhoneType函数调用:mCi.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));在此类ServiceStateTracker中,Handler注册了EVENT_GET_SIGNAL_STRENGTH消息的监听,通过Handler.obtainMessage函数把消息传到RILJ。
RILJ拿到这个消息后,通过obtainRequest组装RILRequest,并把这个RILRequest放到mRequestList里:
这样当radioProxy.getSignalStrength(rr.mSerial)处理完后,就也就是RILD处理完,RILD调用RadioResponse的getSignalStrengthResponse函数。最终调用responseSignalStrength
然后通过processResponse找到mRequestList对应的RILRequest,此处是通过RILRequest类里面的mSerial成员找到,因为这个成员RILD和RILJ都知道,过程不在这分析。找到RILRequest之后,也就能找回Message,最后调用如下函数把Message发出去,这样ServiceStateTracker类中的Handler就能监听到了,并处理相应结果。
3.3 Indication消息处理机制
RILD的主动消息上报是通过RadioIndication.java类完成。而RILD拿到此对象是通过mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
主动上报的消息处理机制: RILD通过调用mRadioIndication提供的接口,然后调用notifyRegistrants或notifyRegistrant发出通知,而通知给谁,就是谁监听就通知给谁,而能监听的哪些内容都在BaseCommands.java里面实现了。以NITZ监听为例:
监听NITZ函数:
1. public void setOnNITZTime(Handler h, int what, Object obj) { 2. mNITZTimeRegistrant = new Registrant (h, what, obj); 3. } |
解除NITZ监听函数:
1. public void unSetOnNITZTime(Handler h) { 2. if (mNITZTimeRegistrant != null && mNITZTimeRegistrant.getHandler() == h) { 3. mNITZTimeRegistrant.clear(); 4. mNITZTimeRegistrant = null; 5. } 6. } |
收到RILD消息上报后发出通知相关处理函数:
1. public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) { 2. mRil.processIndication(indicationType); 3. 4. if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); 5. 6. // todo: Clean this up with a parcelable class for better self-documentation 7. Object[] result = new Object[2]; 8. result[0] = nitzTime; 9. result[1] = receivedTime; 10. 11. boolean ignoreNitz = TelephonyProperties.ignore_nitz().orElse(false); 12. 13. if (ignoreNitz) { 14. if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); 15. } else { 16. if (mRil.mNITZTimeRegistrant != null) { 17. mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null)); 18. } 19. // in case NITZ time registrant isn't registered yet, or a new registrant 20. // registers later 21. mRil.mLastNITZTimeInfo = result; 22. } 23. } |
notifyRegistrant的处理过程是根据注册监听时,传入的handle和msg消息进行调用处理。
4、RILD
RILD是个进程,由init进程拉起来。上面有提到过,他的作用是向上跟RILJ通信,向下跟modem通信,代码路径$Android_root/hardware/ril。要剖析rild结构,可分三个功能块:事件处理、reference定制、ril_server服务。
RILD的main入口是在rild.c里,main里面做了三件事:事件初始化、reference初始化、ril服务注册。
代码路径:代码路径:$android\hardware\ril\rild\rild.c
接下来具体解剖这三个功能块。
4.1 事件处理
事件处理是在ril_event.cpp此文件实现,用于集中管理和处理两种事件,分别是fd事件和超时事件。
代码路径:$android\hardware\ril\libril\ril_event.cpp
流程图如下:
4.1.1 事件初始化
跟踪事件初始化入口函数RIL_startEventLoop,最终只做了一个功能,启了一个线程,并回调eventLoop函数,eventLoop代码如下:
1. static void * 2. eventLoop(void *param) { 3. int ret; 4. int filedes[2]; 5. 6. ril_event_init(); //事件的初始化 7. 8. pthread_mutex_lock(&s_startupMutex); 9. 10. s_started = 1; 11. pthread_cond_broadcast(&s_startupCond); 12. 13. pthread_mutex_unlock(&s_startupMutex); 14. 15. ret = pipe(filedes); //创建管道 16. 17. if (ret < 0) { 18. RLOGE("Error in pipe() errno:%d", errno); 19. return NULL; 20. } 21. 22. s_fdWakeupRead = filedes[0]; //管道读 23. s_fdWakeupWrite = filedes[1]; //管道写 24. 25. fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); 26. 27. ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true, 28. processWakeupCallback, NULL); //初始化一个event 29. 30. rilEventAddWakeup (&s_wakeupfd_event); //向watch_table添加event 31. 32. // Only returns on error 33. ril_event_loop(); //循环监听事件 34. RLOGE ("error in event_loop_base errno:%d", errno); 35. // kill self to restart on error 36. kill(0, SIGKILL); 37. 38. return NULL; 39. } |
ril_event_init分别初始化了三个双向链表,分别为:
- timer_list:超时事件链表
- watch_table:fd事件链表,自从RIL采用HIDL进程间通信后,此链表用的不多,以前还用于Socket事件的监听。
- pending_list:待处理事件链表,如timer_list watch_table有事件要处理后,把事件放到这个队列来进行一一处理。
链表结构体:
1. struct ril_event { 2. struct ril_event *next; 3. struct ril_event *prev; 4. 5. int fd; 6. int index; 7. bool persist; // event是否可被移除,true不可被移除 8. struct timeval timeout; 9. ril_event_cb func; 10. void *param; 11. }; |
ril_event_init函数:
1. void ril_event_init() 2. { 3. MUTEX_INIT(); 4. 5. FD_ZERO(&readFds); 6. init_list(&timer_list); 7. init_list(&pending_list); 8. memset(watch_table, 0, sizeof(watch_table)); 9. } |
接下来创建filedes管道,然后把这个管道fd给watch_table链表,见rilEventAddWakeup函数。
4.1.2 事件监听
ril_event_loop函数,用于循环监听timer_list和watch_table事件,代码如下:
1. void ril_event_loop() 2. { 3. int n; 4. fd_set rfds; 5. struct timeval tv; 6. struct timeval * ptv; 7. 8. for (;;) { 9. // make local copy of read fd_set 10. memcpy(&rfds, &readFds, sizeof(fd_set)); 11. //获取下一个超时的时间 12. if (-1 == calcNextTimeout(&tv)) { 13. // no pending timers; block indefinitely 14. dlog("~~~~ no timers; blocking indefinitely ~~~~"); 15. ptv = NULL; 16. } else { 17. dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); 18. ptv = &tv; 19. } 20. printReadies(&rfds); 21. 22. //监听fd事件及超时设置,这里的fd和超时完全没有对应关系,fd是watch_table事件,而ptv是time_list事件,但2者巧妙的结合起来用了,监听互不影响。 23. n = select(nfds, &rfds, NULL, NULL, ptv); 24. printReadies(&rfds); 25. dlog("~~~~ %d events fired ~~~~", n); 26. if (n < 0) { 27. if (errno == EINTR) continue; 28. 29. RLOGE("ril_event: select error (%d)", errno); 30. // bail? 31. return; 32. } 33. // Check for timeouts 34. processTimeouts(); // 检测timer_list是否有触发 35. // Check for read-ready 36. processReadReadies(&rfds, n); //检测watch_table事件是否有触发 37. // Fire away 38. firePending(); //处理timer_list watch_table添加到pending_list的事件 39. } 40. } |
检测timer_list是否有触发代码如下,如果timer_list列表里面的事件如果超时了,通过调用addToList函数,把事件给到pending_list。
1. static void processTimeouts() 2. { 3. dlog("~~~~ +processTimeouts ~~~~"); 4. MUTEX_ACQUIRE(); 5. struct timeval now; 6. struct ril_event * tev = timer_list.next; 7. struct ril_event * next; 8. 9. getNow(&now); 10. // walk list, see if now >= ev->timeout for any events 11. 12. dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); 13. while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { 14. // Timer expired 15. dlog("~~~~ firing timer ~~~~"); 16. next = tev->next; 17. removeFromList(tev); 18. addToList(tev, &pending_list); 19. tev = next; 20. } 21. MUTEX_RELEASE(); 22. dlog("~~~~ -processTimeouts ~~~~"); 23. } |
检测watch_table事件是否有触发的函数代码如下,如果fd被触发了,就把fd对应的事件给到pending_list
1. static void processReadReadies(fd_set * rfds, int n) 2. { 3. dlog("~~~~ +processReadReadies (%d) ~~~~", n); 4. MUTEX_ACQUIRE(); 5. 6. for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { 7. struct ril_event * rev = watch_table[i]; 8. if (rev != NULL && FD_ISSET(rev->fd, rfds)) { 9. addToList(rev, &pending_list); 10. if (rev->persist == false) { //这里如果persist为true的话,fd不会被移除。 11. removeWatch(rev, i); 12. } 13. n--; 14. } 15. } 16. 17. MUTEX_RELEASE(); 18. dlog("~~~~ -processReadReadies (%d) ~~~~", n); 19. } |
最后通过while执行pending_list列表的回调函数,代码如下。
1. static void firePending() 2. { 3. dlog("~~~~ +firePending ~~~~"); 4. struct ril_event * ev = pending_list.next; 5. while (ev != &pending_list) { 6. struct ril_event * next = ev->next; 7. removeFromList(ev); 8. ev->func(ev->fd, 0, ev->param); 9. ev = next; 10. } 11. dlog("~~~~ -firePending ~~~~"); 12. } |
时序图流程如下:
4.1.3 事件添加
上面介绍的都是事件初始化和事件处理过程,那事件是怎么发出来?此处以超时事件为例简单讲一下:
超时事件对外提供的接口是RILC_requestTimedCallback,由下面的时序图可知,重点是ril_event_set和ril_timer_add两函数,ril_event_set是用于ril_event事件的封装,ril_timer_add函数用于把事件添加到timer_list表里,这样就完成了超时事件的添加处理。
4.2 reference-ril定制
reference定是由基带厂家来根据自家模块进行定制,最终生成libreference_ril.so库。
我司这块的代码目录如下,通过目录可了解RIL支持的功能。其中红色部分是我司添加,黑色的是google原生自带。
adapter 适配层
|–android Android的适配
|–module 模块的适配
|–platform 上位机的适配
custmer 客户定制
NWY-CM QMI拨号相关文件
Android.mk 编译配置文件
at_tok.c AT解析
atchannel.c AT读取及处理
chat.c AT收发及处理
dhcpclient_ext.c dhcp 处理
udhcpc_ext.c dhcp 处理
gsm0710muxd.c 串口cmux功能,目前已不再维护,逐渐废弃。
ip-down.c pppd down后的相关处理
ip-up.c pppd up后的相关处理
misc.c 算法相关
nwy-gps.c 协助GPS库发送AT指令
nwy-ndis.c ndis拨号进程
nwy-pppd.c pppd拨号进程
nwy-rndis.c rndis拨号进程
nwy-thread-do-configfile-cmd.c 客户自行定制初始化AT
reference-ril.c ril处理逻辑
4.2.1 RIL_Init函数实现
在rild.c的main函数里面,reference是通过调用如下函数进行初始化。
funcs = rilInit(&s_rilEnv, argc, rilArgv);
而rilInit的由来从main中也可以看到,是通过dlsym打开libreference_ril库来获取RIL_Init函数地址,代码如下:
rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
此函数主要是完成一些属性/参数的配置或读取。
1. const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) { 2. LOGD("Neoway RIL_Init started......"); 3. int ret; 4. pthread_attr_t attr; 5. //modify usb permission 6. #ifdef SET_USB_PORT_PERMISSION_FOR_GET_MODEM_LOG 7. chmod_usb_port_permission(); //修改USB权限,定制功能 8. #endif 9. //check pwd 10. check_pwd(); //检查rild是否拥有root权限 11. char prop_value[PROPERTY_VALUE_MAX] = {'\0'}; 12. LOGD("Neoway RIL Version: %s", nwy_get_version()); 13. //get android version 14. int android_version = get_android_version(prop_value); //获取android版本属性 15. //save android version 16. nwy_set_android_char_version(android_version); //设置android版本号 17. //set ril version 18. set_ril_version(android_version); //设置reference_ril支持的RIL版本号 19. //set s_callbacks version 20. s_callbacks.version = NWY_RIL_VERSION; 21. print_some_property(prop_value); //打印一些rild参数信息 22. //turn off the cdma phone 23. property_set("telephony.lteOnCdmaDevice", "0"); // "1" will make PhoneFactory.java create CDMALTEPhone 24. //bind env 25. s_rilenv = env; 26. module_factory_init(); //我司模块工厂设计模式初始化 27. if (OPERATOR_OK != init_modem_port_para(argc, argv, prop_value)) { //参数解析 28. return NULL; 29. } 30. if (nwy_mux_enabled == 0 && access(NWY_DEBUG_LOG_PATH, W_OK) == 0) { //CMUX功能 31. //first adb forward tcp:9000 tcp:9000, second QSPT(127.0.0.1:9000) & QXDM 32. nwy_tty2tcp("s:9000", "c:/dev/ttyUSB0", 512*1024); 33. } 34. pthread_attr_init (&attr); 35. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 36. ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); //创建线程处理其他问题 37. LOGD("RIL_Init end, CMUX_AT_PORT:%s, CMUX_PPP_PORT:%s", CMUX_AT_PORT, CMUX_PPP_PORT); 38. return &s_callbacks; //返回CB结构体,结构体携带相关接口。见RIL_RadioFunctions 39. } |
返回RIL_RadioFunctions的结构体,用于向外提供的接口。代码如下:
1. static RIL_RadioFunctions s_callbacks = { 2. RIL_VERSION, 3. onRequest, //重点是这个,用于RIL消息的请求 4. currentState, 5. onSupports, 6. onCancel, 7. getVersion 8. }; |
4.2.2 mainLoop函数实现
此函数主要是完成AT口路径获取及open read处理。
1. static void *mainLoop(void *param) 2. { 3. int fd; 4. int ret; 5. ...... 6. LOGI("mainLoop Start"); 7. ...... 8. for (;;) { 9. LOGD("nwy_mux_enabled s_device_path is %s, nwy_mux_enabled:%d", s_device_path, nwy_mux_enabled); 10. if (nwy_mux_enabled) { 11. ...... 12. } else { 13. if (s_device_path == nwy_ttyAT) { 14. char atdevice[64]={0}; 15. if (!nwy_get_ttyAT(atdevice)) { //获取AT口的路径,代码是根据获取模块名字,然后通过模块对应的pid vid进行驱动解析来获取路径。 16. sleep(2); 17. continue; //如果获取不到,继续循环。 18. } 19. sprintf(nwy_ttyAT, "/dev/%s", atdevice); 20. LOGD("neoway at port is %s", nwy_ttyAT); 21. } 22. } 23. 24. fd = -1; 25. while (fd < 0) { 26. if (s_device_path != NULL) { 27. if (nwy_mux_enabled) { 28. fd = open (CMUX_AT_PORT, O_RDWR); 29. } else { 30. fd = open (s_device_path, O_RDWR); //打开AT口 31. } 32. if ( fd >= 0 ) { 33. ...... 34. } 35. } 36. ...... 37. } 38. } 39. 40. s_closed = 0; 41. ret = at_open(fd, onUnsolicited); //完成fd的读取线程创建,onUnsolicited函数是用于主动上报的指令处理。 42. 43. if (ret < 0) { 44. LOGE ("AT error %d on at_open\n", ret); 45. return 0; 46. } 47. 48. RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); //通过定时完成initializeCallback调用 49. waitForClose(); 50. LOGI("Re-opening after close"); 51. } 52. } |
4.2.3 initializeCallback函数实现
此函数主要是完成AT的一些初始化,模块工厂初始化及SIM卡状态检测。
1. static void initializeCallback(void *param) 2. { 3. ATResponse *p_response = NULL; 4. int err = 0; 5. int count = 0; 6. 7. if (s_recovery_mode && currentNwyState() == RADIO_STATE_SIM_READY) { 8. //maybe only usb disconnect 9. } else { 10. setRadioState (RADIO_STATE_OFF); //初始化radio的状态 11. } 12. sleep(2); // here need about 2 seconds to wait mode OK if do setRadioState 13. err = at_handshake(); //和模块进行AT握手 14. if(err != 0){ 15. LOGE("%s:handshake failed,err is ==>%d", __func__,err); 16. onATReaderClosed(); //AT握手失败的话,关闭AT口 17. return ; 18. } 19. /* close at commod echo*/ 20. at_send_command("ATE0", NULL); //关闭回显 21. //init product module 22. err = init_product_module(); //获取当前使用的哪个模块,并完成相应的初始化工作。 23. if (err != OPERATOR_OK) { 24. onATReaderClosed(); 25. LOGE("%s init product module faild", __func__); 26. return ; 27. } 28. // get modem type 29. while(count < MAX_RETRY_COUNT){ 30. err = init_nwy_product(); //获取模块名 31. if(err == 0){ 32. break; 33. } 34. count = count + 1; 35. usleep(100*1000); 36. } 37. if(err != 0){ 38. onATReaderClosed(); //模块名获取不到的话,进行关闭AT口 39. LOGE("%s faild", __func__); 40. return ; 41. } 42. ...... //初始化一些AT 43. 44. if (isRadioOn() > 0) { 45. // radio的状态检测及初始化 46. if (s_recovery_mode && (currentNwyState() == RADIO_STATE_SIM_READY)) {//maybe only usb disconnect 47. if (getSIMStatus() == SIM_READY) 48. onSIMReady(); 49. else 50. setRadioState (RADIO_STATE_SIM_NOT_READY); 51. 52. //之所以上报这些信息,是想让android下发一些RIL消息进行更新android侧的状态。 53. RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0); 54. RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0); 55. RIL_onUnsolicitedResponse (RIL_UNSOL_DATA_CALL_LIST_CHANGED, NULL, 0); 56. } else { 57. setRadioState (RADIO_STATE_SIM_NOT_READY); 58. } 59. } 60. s_recovery_mode = 0; 61. ...... 62. nwy_start_config_file_thread(); // 扩展功能,用于客户指定发送一些初始化AT指令。 63. } |
至此,reference-ril模块的初始化功能就已完成。剩余的工作就是收到onRequest请求时,根据对应的RIL消息进行处理就行,以拨号为例。
1. static void onRequest (int request, void *data, size_t datalen, RIL_Token t) 2. { 3. ATResponse *p_response = NULL; 4. int err; 5. 6. LOGD("onRequest: %s", requestToString(request)); 7. 8. ...... 9. case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: { 10. requestLastPDPFailCause(t); 11. break; 12. } 13. 14. case RIL_REQUEST_SETUP_DATA_CALL: //收到拨号请求 15. requestSetupDataCall(data, datalen, t); 16. break; 17. ...... 18. } |
收到RIL_REQUEST_SETUP_DATA_CALL拨号请求后,我们根据模块准备好拨号初始化工作,客户要的拨号方式等进行拨号。
另外,关于模块如何适配的工作问题,可参考链接:关于RIL库的模块适配优化
4.3 ril_server服务
此功能用于注册HIDL服务,并提供相关接口供客户端RILJ调用。
代码路径:$android\hardware\ril\libril\ril_service.cpp
4.3.1 服务注册
服务注册是在rild.c的main函数里通过调用RIL_register(funcs)来完成。
1. funcs = rilInit(&s_rilEnv, argc, rilArgv); 2. RLOGD("RIL_Init rilInit completed"); 3. 4. RIL_register(funcs); |
通过代码跟踪,最后registerAsService来实现hidl的服务注册,这里涉及到hidl的原理,只需要了解怎么回事就行。
1. void radio::registerService(RIL_RadioFunctions *callbacks, CommandInfo *commands) { 2. using namespace android::hardware; 3. int simCount = 1; 4. const char *serviceNames[] = { 5. android::RIL_getServiceName() 6. #if (SIM_COUNT >= 2) 7. , RIL2_SERVICE_NAME 8. #if (SIM_COUNT >= 3) 9. , RIL3_SERVICE_NAME 10. #if (SIM_COUNT >= 4) 11. , RIL4_SERVICE_NAME 12. #endif 13. #endif 14. #endif 15. }; 16. 17. #if (SIM_COUNT >= 2) 18. simCount = SIM_COUNT; 19. #endif 20. 21. s_vendorFunctions = callbacks; 22. s_commands = commands; 23. 24. configureRpcThreadpool(1, true /* callerWillJoin */); 25. for (int i = 0; i < simCount; i++) { 26. pthread_rwlock_t *radioServiceRwlockPtr = getRadioServiceRwlock(i); 27. int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr); 28. assert(ret == 0); 29. 30. radioService[i] = new RadioImpl; 31. radioService[i]->mSlotId = i; 32. RLOGD("registerService: starting android::hardware::radio::V1_1::IRadio %s", 33. serviceNames[i]); 34. android::status_t status = radioService[i]->registerAsService(serviceNames[i]); 35. 36. if (kOemHookEnabled) { 37. oemHookService[i] = new OemHookImpl; 38. oemHookService[i]->mSlotId = i; 39. status = oemHookService[i]->registerAsService(serviceNames[i]); 40. } 41. 42. ret = pthread_rwlock_unlock(radioServiceRwlockPtr); 43. assert(ret == 0); 44. } 45. } |
4.3.2 setResponseFunctions重要对象获取
此函数作用是拿到JAVA侧的response 和indication的对象,用于RILD有消息向RILJ上报。前面讲到过,response是消息的查询上报,indication是RILD有消息主动上报给RILJ。
1. Return<void> RadioImpl::setResponseFunctions( 2. const ::android::sp<IRadioResponse>& radioResponseParam, 3. const ::android::sp<IRadioIndication>& radioIndicationParam) { 4. RLOGD("setResponseFunctions"); 5. 6. pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock(mSlotId); 7. int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr); 8. assert(ret == 0); 9. 10. mRadioResponse = radioResponseParam; 11. mRadioIndication = radioIndicationParam; 12. mRadioResponseV1_1 = V1_1::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr); 13. mRadioIndicationV1_1 = V1_1::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr); 14. if (mRadioResponseV1_1 == nullptr || mRadioIndicationV1_1 == nullptr) { 15. mRadioResponseV1_1 = nullptr; 16. mRadioIndicationV1_1 = nullptr; 17. } 18. 19. mCounterRadio[mSlotId]++; 20. 21. ret = pthread_rwlock_unlock(radioServiceRwlockPtr); 22. assert(ret == 0); 23. 24. // client is connected. Send initial indications. 25. android::onNewCommandConnect((RIL_SOCKET_ID) mSlotId); 26. 27. return Void(); 28. } |
然后再调用onNewCommandConnect函数,向RILJ发出RIL_UNSOL_RIL_CONNECTED和RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED消息。RIL_UNSOL_RIL_CONNECTED是用于告知RILJ已完成建立,RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED是用于告知RILJ下发radio有变化,上层收到此消息后进行网络相关查询动作。
1. void onNewCommandConnect(RIL_SOCKET_ID socket_id) { 2. // Inform we are connected and the ril version 3. int rilVer = s_callbacks.version; 4. RIL_UNSOL_RESPONSE(RIL_UNSOL_RIL_CONNECTED, 5. &rilVer, sizeof(rilVer), socket_id); 6. 7. // implicit radio state changed 8. RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, 9. NULL, 0, socket_id); 10. 11. // Send last NITZ time data, in case it was missed 12. if (s_lastNITZTimeData != NULL) { 13. resendLastNITZTimeData(socket_id); 14. } 15. 16. // Get version string 17. if (s_callbacks.getVersion != NULL) { 18. const char *version; 19. version = s_callbacks.getVersion(); 20. RLOGI("RIL Daemon version: %s\n", version); 21. 22. property_set(PROPERTY_RIL_IMPL, version); 23. } else { 24. RLOGI("RIL Daemon version: unavailable\n"); 25. property_set(PROPERTY_RIL_IMPL, "unavailable"); 26. } 27. 28. } |
4.3.3 消息请求分析
关于RILJ已分析过JAVA侧的消息请求处理流程,而到了RILD收到RILJ的消息请求后,RILD是如何处理,请看下面的时序图分析,仍以获取信号强度为例。
RILJ有消息请求时,可能未等当前处理完成,下一条请求消息又接着来,为了及时处理当前消息,google使用了一个单向链表RequestInfo来保存这些请求信息,一旦有请求消息来后,就会调用dispatchVoid这函数,把消息类型和相关参数传下去进行封装,放入RequestInfo链表里。
1. Return<void> RadioImpl::getSignalStrength(int32_t serial) { 2. #if VDBG 3. RLOGD("getSignalStrength: serial %d", serial); 4. #endif 5. dispatchVoid(serial, mSlotId, RIL_REQUEST_SIGNAL_STRENGTH); 6. return Void(); 7. } 8. 9. bool dispatchVoid(int serial, int slotId, int request) { 10. RequestInfo *pRI = android::addRequestToList(serial, slotId, request); 11. if (pRI == NULL) { 12. return false; 13. } 14. CALL_ONREQUEST(request, NULL, 0, pRI, slotId); 15. return true; 16. } 17. |
存入链表RequestInfo的函数是addRequestToList,代码如下。
1. RequestInfo * 2. addRequestToList(int serial, int slotId, int request) { 3. RequestInfo *pRI; 4. int ret; 5. RIL_SOCKET_ID socket_id = (RIL_SOCKET_ID) slotId; 6. /* Hook for current context */ 7. /* pendingRequestsMutextHook refer to &s_pendingRequestsMutex */ 8. pthread_mutex_t* pendingRequestsMutexHook = &s_pendingRequestsMutex; 9. /* pendingRequestsHook refer to &s_pendingRequests */ 10. RequestInfo** pendingRequestsHook = &s_pendingRequests; \\ s_pendingRequests链表名 11. 12. #if (SIM_COUNT >= 2) 13. if (socket_id == RIL_SOCKET_2) { 14. pendingRequestsMutexHook = &s_pendingRequestsMutex_socket2; 15. pendingRequestsHook = &s_pendingRequests_socket2; 16. } 17. #if (SIM_COUNT >= 3) 18. else if (socket_id == RIL_SOCKET_3) { 19. pendingRequestsMutexHook = &s_pendingRequestsMutex_socket3; 20. pendingRequestsHook = &s_pendingRequests_socket3; 21. } 22. #endif 23. #if (SIM_COUNT >= 4) 24. else if (socket_id == RIL_SOCKET_4) { 25. pendingRequestsMutexHook = &s_pendingRequestsMutex_socket4; 26. pendingRequestsHook = &s_pendingRequests_socket4; 27. } 28. #endif 29. #endif 30. 31. pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); 32. if (pRI == NULL) { 33. RLOGE("Memory allocation failed for request %s", requestToString(request)); 34. return NULL; 35. } 36. 37. pRI->token = serial; //本次消息的密令 pRI->pCI = &(s_commands[request]); //在ril_commands.h中定义 38. pRI->socket_id = socket_id; // 哪个卡槽 39. 40. ret = pthread_mutex_lock(pendingRequestsMutexHook); 41. assert (ret == 0); 42. 43. pRI->p_next = *pendingRequestsHook; 44. *pendingRequestsHook = pRI; //请求消息存入到s_pendingRequests 45. 46. ret = pthread_mutex_unlock(pendingRequestsMutexHook); 47. assert (ret == 0); 48. 49. return pRI; 50. } |
ril_commands.h相关定义内容如下:
1. {0, NULL}, //none 2. {RIL_REQUEST_GET_SIM_STATUS, radio::getIccCardStatusResponse}, 3. {RIL_REQUEST_ENTER_SIM_PIN, radio::supplyIccPinForAppResponse}, 4. {RIL_REQUEST_ENTER_SIM_PUK, radio::supplyIccPukForAppResponse}, 5. {RIL_REQUEST_ENTER_SIM_PIN2, radio::supplyIccPin2ForAppResponse}, 6. {RIL_REQUEST_ENTER_SIM_PUK2, radio::supplyIccPuk2ForAppResponse}, 7. {RIL_REQUEST_CHANGE_SIM_PIN, radio::changeIccPinForAppResponse}, 8. {RIL_REQUEST_CHANGE_SIM_PIN2, radio::changeIccPin2ForAppResponse}, 9. {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, radio::supplyNetworkDepersonalizationResponse}, 10. {RIL_REQUEST_GET_CURRENT_CALLS, radio::getCurrentCallsResponse}, 11. {RIL_REQUEST_DIAL, radio::dialResponse}, 12. {RIL_REQUEST_GET_IMSI, radio::getIMSIForAppResponse}, 13. {RIL_REQUEST_HANGUP, radio::hangupConnectionResponse}, 14. {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, radio::hangupWaitingOrBackgroundResponse}, 15. {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, radio::hangupForegroundResumeBackgroundResponse}, 16. {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, radio::switchWaitingOrHoldingAndActiveResponse}, 17. {RIL_REQUEST_CONFERENCE, radio::conferenceResponse}, 18. {RIL_REQUEST_UDUB, radio::rejectCallResponse}, 19. {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, radio::getLastCallFailCauseResponse}, 20. {RIL_REQUEST_SIGNAL_STRENGTH, radio::getSignalStrengthResponse}, |
完成请求消息组装后,再调用CALL_ONREQUEST函数,此函数通过跟踪,就是reference_ril.c提供的onRequest函数,也就是最终的请求消息分发到reference_ril.c里处理。当onRequest处理完成后,通过调用RIL_onRequestComplete把结果返回。
1. extern "C" void 2. RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { 3. RequestInfo *pRI; 4. int ret; 5. RIL_SOCKET_ID socket_id = RIL_SOCKET_1; 6. 7. pRI = (RequestInfo *)t; 8. 9. if (!checkAndDequeueRequestInfoIfAck(pRI, false)) { \\从s_pendingRequests链表删除当前的节点 10. RLOGE ("RIL_onRequestComplete: invalid RIL_Token"); 11. return; 12. } 13. 14. socket_id = pRI->socket_id; 15. #if VDBG 16. RLOGD("RequestComplete, %s", rilSocketIdToString(socket_id)); 17. #endif 18. 19. if (pRI->local > 0) { 20. // Locally issued command...void only! 21. // response does not go back up the command socket 22. RLOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber)); 23. 24. free(pRI); 25. return; 26. } 27. 28. appendPrintBuf("[%04d]< %s", 29. pRI->token, requestToString(pRI->pCI->requestNumber)); 30. 31. if (pRI->cancelled == 0) { 32. int responseType; 33. if (s_callbacks.version >= 13 && pRI->wasAckSent == 1) { 34. // If ack was already sent, then this call is an asynchronous response. So we need to 35. // send id indicating that we expect an ack from RIL.java as we acquire wakelock here. 36. responseType = RESPONSE_SOLICITED_ACK_EXP; 37. grabPartialWakeLock(); 38. } else { 39. responseType = RESPONSE_SOLICITED; 40. } 41. 42. // there is a response payload, no matter success or not. 43. #if VDBG 44. RLOGE ("Calling responseFunction() for token %d", pRI->token); 45. #endif 46. 47. pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock((int) socket_id); 48. int rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr); 49. assert(rwlockRet == 0); 50. 51. ret = pRI->pCI->responseFunction((int) socket_id, //函数调用,在ril_commands.h中定义 52. responseType, pRI->token, e, response, responselen); 53. 54. rwlockRet = pthread_rwlock_unlock(radioServiceRwlockPtr); 55. assert(rwlockRet == 0); 56. } 57. free(pRI); 58. } |
从ril_commands.h中可以看出,此处的responseFunction处理函数是getSignalStrengthResponse。这样就完成了RILJ消息的请求处理过程。
4.3.4 消息主动上报分析
主动上报用到modem有状态变化需要主动告知RILJ时会用到,比如网络状态发生变化就会使用到此流程。
在ril.cpp可以看到,主动上报RILD提供的接口是RIL_onUnsolicitedResponse,原型void RIL_onUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen),unsolResponse参数是消息类型,data是数据内容。函数实现也很容易看懂,通过在ril_unsol_commands.h文件里根据消息类型查找到对应的执行函数进行调用。另从这个.h文件可以看到,最后一个参数是否进行唤醒系统,这里以前就碰到一个问题,系统一直被RIL唤醒,无法休眠,最终从这里找到了原因。ril_unsol_commands.h部分内容如下
1. {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, radio::radioStateChangedInd, WAKE_PARTIAL}, 2. {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, radio::callStateChangedInd, WAKE_PARTIAL}, 3. {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, radio::networkStateChangedInd, WAKE_PARTIAL}, 4. {RIL_UNSOL_RESPONSE_NEW_SMS, radio::newSmsInd, WAKE_PARTIAL}, 5. {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, radio::newSmsStatusReportInd, WAKE_PARTIAL}, 6. {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, radio::newSmsOnSimInd, WAKE_PARTIAL}, 7. {RIL_UNSOL_ON_USSD, radio::onUssdInd, WAKE_PARTIAL}, 8. {RIL_UNSOL_ON_USSD_REQUEST, radio::onUssdInd, DONT_WAKE}, 9. {RIL_UNSOL_NITZ_TIME_RECEIVED, radio::nitzTimeReceivedInd, WAKE_PARTIAL}, 10. {RIL_UNSOL_SIGNAL_STRENGTH, radio::currentSignalStrengthInd, DONT_WAKE}, 11. {RIL_UNSOL_DATA_CALL_LIST_CHANGED, radio::dataCallListChangedInd, WAKE_PARTIAL}, 12. {RIL_UNSOL_SUPP_SVC_NOTIFICATION, radio::suppSvcNotifyInd, WAKE_PARTIAL}, |
5、log分析
RIL库从启动到拨号的LOG如下,因RILJ消息挺多,这里重点过滤关键log信息。见如下内容。
1. Line 1717: 09-14 14:43:30.915 344 344 D RILC : Neoway RIL_Init started...... //ril启动 2. Line 1718: 09-14 14:43:30.915 344 344 D RILC : Neoway RIL Version: Neoway_Android_X_RIL_V3.07.66_T2 //ril库版本号 3. Line 1723: 09-14 14:43:30.915 344 344 D RILC : NWY_RIL_VERSION is 12 //android版本号 4. Line 1724: 09-14 14:43:30.915 344 344 D RILC : [ro.build.description]: [rk3566_roc_pc-userdebug 11 RQ1D.210105.003 eng.wangch.20230912.202446 release-keys] 5. Line 1938: 09-14 14:43:33.938 344 354 D ATC : AT> AT //AT握手 6. Line 1939: 09-14 14:43:33.943 344 412 D ATC : AT< OK 7. Line 1950: 09-14 14:43:34.500 344 354 D ATC : AT> ATE0 //关闭回显 8. Line 1951: 09-14 14:43:34.506 344 412 D ATC : AT< OK 9. Line 1954: 09-14 14:43:34.507 344 354 D ATC : AT> AT+CGMM //查询模块名 10. Line 1955: 09-14 14:43:34.514 344 412 D ATC : AT< N725 11. Line 1956: 09-14 14:43:34.514 344 412 D ATC : AT< OK 12. Line 5491: 09-14 14:43:40.840 787 933 D RILJ : [UNSL]< UNSOL_RIL_CONNECTED [PHONE0] //通知RILJ已完成初始化 13. Line 5496: 09-14 14:43:40.853 787 933 D RILJ : [0001]> RADIO_POWER on = true forEmergencyCall= false preferredForEmergencyCall=false [PHONE0] //打开射频 14. 15. Line 5545: 09-14 14:43:40.952 344 344 D RILC : getSIMStatus(). sState: 4 //获取卡的状态 16. Line 5546: 09-14 14:43:40.952 344 344 D ATC : AT> AT+CPIN? 17. Line 5551: 09-14 14:43:40.959 344 412 D ATC : AT< +CPIN: READY 18. Line 5552: 09-14 14:43:40.959 344 412 D ATC : AT< OK 19. //获取SIM信息 20. Line 6770: 09-14 14:43:42.247 787 787 D RILJ : [0071]> iccIO: SIM_IO command = 0xb2 fileId = 0x6fc9 path = 3F007F20 p1 = 1 p2 = 4 p3 = data = null aid = [PHONE0] 21. Line 6775: 09-14 14:43:42.256 344 344 D RILC : onRequest: SIM_IO 22. Line 6777: 09-14 14:43:42.256 344 344 D ATC : AT> AT+CRSM=192,28618,0,0,0 23. Line 6782: 09-14 14:43:42.264 344 412 D ATC : AT< +CRSM: 4,"6A82" 24. Line 6783: 09-14 14:43:42.264 344 412 D ATC : AT< OK 25. Line 6778: 09-14 14:43:42.256 787 933 D RILJ : [0044]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 Payload: 000000046FAD040000FFBB01020000 [PHONE0] 26. //获取运营商信息,data voice状态 27. Line 6579: 09-14 14:43:42.132 787 787 D RILJ : [0064]> OPERATOR [PHONE0] 28. Line 6582: 09-14 14:43:42.134 787 787 D RILJ : [0065]> QUERY_NETWORK_SELECTION_MODE [PHONE0] 29. Line 6583: 09-14 14:43:42.135 787 1022 D RILJ : [0066]> DATA_REGISTRATION_STATE [PHONE0] 30. Line 6591: 09-14 14:43:42.137 787 1022 D RILJ : [0067]> VOICE_REGISTRATION_STATE [PHONE0] 31. Line 7017: 09-14 14:43:42.155 344 344 D RILC : onRequest: OPERATOR 32. Line 6629: 09-14 14:43:42.155 344 344 D ATC : AT> AT+COPS=3,1 33. Line 6634: 09-14 14:43:42.159 344 412 D ATC : AT< OK 34. Line 6635: 09-14 14:43:42.159 344 344 D ATC : AT> AT+COPS? 35. Line 6637: 09-14 14:43:42.165 344 412 D ATC : AT< +COPS: 0,1,"CMCC",7 36. Line 6638: 09-14 14:43:42.165 344 412 D ATC : AT< OK 37. Line 6640: 09-14 14:43:42.165 344 344 D ATC : AT> AT+COPS=3,2 38. Line 6642: 09-14 14:43:42.169 344 412 D ATC : AT< OK 39. Line 6643: 09-14 14:43:42.170 344 344 D ATC : AT> AT+COPS? 40. Line 6650: 09-14 14:43:42.175 344 412 D ATC : AT< +COPS: 0,2,"46000",7 41. Line 6651: 09-14 14:43:42.175 344 412 D ATC : AT< OK 42. Line 6656: 09-14 14:43:42.176 787 933 D RILJ : [0018]< OPERATOR {CHINA MOBILE, CMCC, 46000} [PHONE0] 43. Line 7017: 09-14 14:43:42.467 344 344 D RILC : onRequest: QUERY_NETWORK_SELECTION_MODE 44. Line 7026: 09-14 14:43:42.474 787 933 D RILJ : [0065]< QUERY_NETWORK_SELECTION_MODE {0} [PHONE0] 45. Line 7023: 09-14 14:43:42.473 344 344 D RILC : onRequest: DATA_REGISTRATION_STATE 46. Line 7052: 09-14 14:43:42.491 344 344 D ATC : AT> AT+CEREG? 47. Line 7053: 09-14 14:43:42.497 344 412 D ATC : AT< +CEREG: 2,1,"90f3","07828c01",7 48. Line 7054: 09-14 14:43:42.497 344 412 D ATC : AT< OK 49. Line 7064: 09-14 14:43:42.504 787 933 D RILJ : [0066]< DATA_REGISTRATION_STATE {.regState = REG_HOME, .rat = 14, .reasonDataDenied = -1, .maxDataCalls = 1, .cellIdentity = {.cellInfoType = LTE, .cellIdentityGsm = [], .cellIdentityWcdma = [], .cellIdentityCdma = [], .cellIdentityLte = [{.mcc = , .mnc = , .ci = -1, .pci = -1, .tac = -1, .earfcn = -1}], .cellIdentityTdscdma = []}} [PHONE0] 50. Line 7023: 09-14 14:43:42.508 344 344 D RILC : onRequest: VOICE_REGISTRATION_STATE 51. Line 7072: 09-14 14:43:42.508 344 344 D ATC : AT> AT+CREG? 52. Line 7073: 09-14 14:43:42.514 344 412 D ATC : AT< +CREG: 2,1,"90f3","07828c01",7 53. Line 7074: 09-14 14:43:42.514 344 412 D ATC : AT< OK 54. Line 7079: 09-14 14:43:42.516 787 933 D RILJ : [0067]< VOICE_REGISTRATION_STATE {.regState = REG_HOME, .rat = 3, .cssSupported = false, .roamingIndicator = -1, .systemIsInPrl = 0, .defaultRoamingIndicator = 0, .reasonForDenial = 0, .cellIdentity = {.cellInfoType = WCDMA, .cellIdentityGsm = [], .cellIdentityWcdma = [{.mcc = , .mnc = , .lac = 37107, .cid = 125996033, .psc = -1, .uarfcn = -1}], .cellIdentityCdma = [], .cellIdentityLte = [], .cellIdentityTdscdma = []}} [PHONE0] 55. 56. //开始拨号 57. Line 9360: 09-14 14:43:45.397 787 1023 D RILJ : [0092]> SETUP_DATA_CALL,dataRat=14,isRoaming=false,allowRoaming=false,DataProfile=-1/0/0/cmnet///0/0/0/0/true/21/0/0/0/0/false/true [PHONE0] 58. Line 9365: 09-14 14:43:45.402 344 344 D RILC : onRequest: SETUP_DATA_CALL 59. Line 9410: 09-14 14:43:45.432 344 344 D ATC : AT> AT+CGDCONT=1,"IP","cmnet" 60. Line 9420: 09-14 14:43:45.445 344 412 D ATC : AT< OK 61. Line 9440: 09-14 14:43:45.455 344 1200 D ATC : AT> AT+NETSHAREACT=1,0,0 62. Line 9472: 09-14 14:43:45.491 344 412 D ATC : AT< +CME ERROR: 4 63. Line 10506: 09-14 14:43:46.492 344 1200 D ATC : AT> AT+NETSHAREACT=1,1,0 64. Line 12231: 09-14 14:43:51.197 344 412 D ATC : AT< OK 65. Line 12806: 09-14 14:43:54.504 344 344 D ATC : AT> AT+CGDCONT? 66. Line 12807: 09-14 14:43:54.510 344 412 D ATC : AT< +CGDCONT: 1,"IP","","10.108.163.170",0,0,0,2,0,0 67. Line 12808: 09-14 14:43:54.513 344 412 D ATC : AT< +CGDCONT: 2,"IP","","",0,0,0,2,0,0 68. Line 12809: 09-14 14:43:54.522 344 412 D ATC : AT< +CGDCONT: 3,"IP","","",0,0,0,2,0,0 69. Line 12810: 09-14 14:43:54.525 344 412 D ATC : AT< +CGDCONT: 4,"IP","","",0,0,0,2,0,0 70. Line 12811: 09-14 14:43:54.528 344 412 D ATC : AT< +CGDCONT: 5,"IP","","",0,0,0,2,0,0 71. Line 12812: 09-14 14:43:54.532 344 412 D ATC : AT< +CGDCONT: 6,"IP","","",0,0,0,2,0,0 72. Line 12813: 09-14 14:43:54.544 344 412 D ATC : AT< +CGDCONT: 8,,"","254.128.0.0.0.0.0.0.0.2.0.1.25.79.249.245",0,0,0,2,1,1 73. Line 12814: 09-14 14:43:54.560 344 412 D ATC : AT< OK 74. Line 12817: 09-14 14:43:54.561 344 344 D RILC : addresses: 192.168.225.102 75. Line 12818: 09-14 14:43:54.561 344 344 D RILC : dnses: 192.168.225.1 192.168.225.1 76. Line 12821: 09-14 14:43:54.561 344 344 D RILC : gateways: 192.168.225.1 77. Line 12831: 09-14 14:43:54.568 787 933 D RILJ : [0092]< SETUP_DATA_CALL DataCallResponse: { cause=0 retry=-1 cid=1 linkStatus=1 protocolType=0 ifname=usb0 addresses=[192.168.225.102/32] dnses=[/192.168.225.1, /192.168.225.1] gateways=[/192.168.225.1] pcscf=[] mtu=0 mtuV4=0 mtuV6=0} [PHONE0] |
6、总结
本文档讲述了RIL从java到c的流程分析,这块整理结构很清晰,但是跨了两门语言。如果一个刚入门要接手RIL框架,个人认为RIL的难点分别在:RILD的事件处理和RILJ的Handle原理,因为对于一个搞android的来说,他没接触过事件处理,而对于一个搞linux的人来说,他不知道handle的处理流程。而RIL的工作量是在libreference_ril.so这个库上,然而要想更好更准确的实现这个库的功能,还得需要了解telephony相关内容,因为控制都在telephony。所以光知道RILD而不懂telephony是很难维护这块工作,因为这是带屏的产品,不能光把参数上报给RILJ就完事,有时候界面显示这块不对,还得了解Telephony逻辑去修改libreference_ril.so这个库。
7、附表
模块 | 路径 |
RILJ | frameworks\opt\telephony\src\java\com\android\internal\telephony\RIL.java frameworks\opt\telephony\src\java\com\android\internal\telephony\RadioResponse.java frameworks\opt\telephony\src\java\com\android\internal\telephony\RadioIndication.java frameworks\opt\telephony\src\java\com\android\internal\telephony\BaseCommands.java frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneFactory.java frameworks\opt\telephony\src\java\com\android\internal\telephony\CommandsInterface.java |
RILD | hardware\ril\rild\rild.c hardware\ril\libril\ril.cpp hardware\ril\libril\ril_event.cpp hardware\ril\libril\ril_service.cpp hardware\ril\reference-ril\reference-ril.c |