深入分析RIL通信原理

目录

1、概述

2、流程图

3、RILJ

3.1初始化

3.2 Response消息处理机制

3.3 Indication消息处理机制

4、RILD

4.1 事件处理

4.1.1 事件初始化

4.1.2 事件监听

4.1.3 事件添加

4.2 reference-ril定制

4.2.1 RIL_Init函数实现

4.2.2 mainLoop函数实现

4.2.3 initializeCallback函数实现

4.3 ril_server服务

4.3.1 服务注册

4.3.2 setResponseFunctions重要对象获取

4.3.3 消息请求分析

4.3.4 消息主动上报分析

5、log分析

6、总结

7、附表


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

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值