Android 通信Ril

Android 通信Ril1 总体框架 Rild 是 Init 进程启动的一个本地服务 这个本地服务并没有使用 Binder 之类的通讯手段 而是采用了 socket 通讯这种方式 Andoid 将 RIL 层分为两个代码空间 RILD 管理框架 rild libril so AT 相关的 xxxril so 动态链接库 libreference ril so rild 把 libril so 和 libreference ril so 联系起来

Andoid将RIL层分为两个代码空间:RILD管理框架(rild、libril.so),AT相关的xxxril.so动态链接库(libreference-ril.so)。rild把libril.so和libreference-ril.so联系起来,libril.so对上是java的socket通信,对下是把java层的命名分发到libreference-ril.so,而libreference-ril.so则把命名转换层AT的命令,通过串口发送给Modem。将RIL独立成一个动态链接库的好处就是Android系统适应不同的Modem,不同的Mode可以有一个独立的Ril与之对应。

     而ril是具体的AT指令合成者和应答解析者。从最基本的功能来讲,ril建立了一个侦听Socket,等待客户端的连接,然后从该连接上读取RIL-Java成传递来的命令并转化成AT指令发送到Modem。并等待Modem的回应,然后将结果通过套接口传回到Ril-Java层。下图是Ril-D的基本框架:

Android 通信Ril

下面的数据流传递描述图表描述了RIL-JAVA层发出一个电话指令的5 步曲:

Android 通信Ril

 

Android 通信Ril

 

① JAVA层通过socket发送命令到RILD

② RILD在EventLoop线程监听到socket消息,读取后封装成AT指令,通过串口发送给

     Modem。并等待Modem的回应命令

③ ReaderLoop线程不断读取串口端口数据,得到回应。回应信息分为两种,一种是对

于第二步AT指令的回应,另一种是主动上报信息,即URC消息,例如短信送达的

消息。

④ 判断是回应AT命令的回应信息,将消息传送到ril再次处理

⑤ 通过socket,将AT回应消息发送到JAVA

⑥ URC消息通过socket,通知到JAVA。

Ril-d的整体数据流及其控制流示意图:

4.1response调用关系图

Android 通信Ril

 

 




Android的通话RIL通信由浅到深跨越了三个层次:

 

1.ITelephony,提供给上层应用程序用户与telephony进行操作,交互的接口,在packages/apps/Phone中由PhoneInterfaceManager.java实现。

 

 

1. rild:仅实现一main函数作为整个ril层的入口点,负责完成初始化。

2. libril.so:与rild结合相当紧密,是其共享库,编译时就已经建立了这一关系。组成部分为ril.cpp,ril_event.cpp。libril.so驻留在rild这一守护进程中,主要完成同上层通信的工作,接受ril请求并传递给librefrence_ril.so, 同时把来自librefrence_ril.so的反馈回传给调用进程。

3. librefrence_ril.so:rild通过手动的dlopen方式加载,结合稍微松散,这也是因为librefrence.so主要负责跟Modem硬件通信的缘故。这样做更方便替换或修改以适配更多的Modem种类。它转换来自libril.so的请求为AT命令,同时监控Modem的反馈信息,并传递回libril.so。在初始化时, rild通过符号RIL_Init获取一组函数指针并以此与之建立联系。

int main(int argc, char argv) { const char * rilLibPath = NULL; const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char ); RIL_setRilSocketName("rild"); //通过属性系统获取lib路径:rild.libpath property_get(LIB_PATH_PROPERTY, rilLibPath, NULL); //动态加载链接库返回句柄 dlclose卸载掉动态链接库 dlHandle = dlopen(rilLibPath, RTLD_NOW); //创建客户端事件监听线程 RIL_startEventLoop(); //通过dlsym定位到需要执行的函数指针    rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char ))dlsym(dlHandle, "RIL_Init"); //通过属性系统获取参数:rild.libargs property_get(LIB_ARGS_PROPERTY, args, ""); argc = make_argv(args, s_argv); //reference-ril.so初始化 处理客户端请求的模块reference-ril.c //s_rilEnv建立应答回调机制 //返回处理请求的相关接口 funcs_inst[0] = rilInit(&s_rilEnv, argc, s_argv); //多卡模式 if (isMultiSimEnabled() && !isMultiRild()) { } RIL_setMaxNumClients(numClients); //注册客户端事件处理接口,并创建socket监听事件 for (i = 0; i < numClients; i++) { RIL_register(funcs_inst[i], i); }   done: while(1) { // sleep(UINT32_MAX) seems to return immediately on bionic sleep(0x00ffffff); } }
enum WakeType {DONT_WAKE, WAKE_PARTIAL, WAKE_FULL};  /*一次请求的dispatch和response函数*/  typedef struct {  int requestNumber;  void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);  //只有成功了才回调,主要功能是处理返回值,把返回的数据写到Parcel里面  int(*responseFunction) (Parcel &p, void *response, size_t responselen);  } CommandInfo;  typedef struct {  int requestNumber;  int (*responseFunction) (Parcel &p, void *response, size_t responselen);  WakeType wakeType;  } UnsolResponseInfo;  /* 一次请求的信息,保包含了token */  typedef struct RequestInfo {  int32_t token;      //this is not RIL_Token ,是一个整形值  CommandInfo *pCI; //包含了request号,处理函数和处理返回值的函数  struct RequestInfo *p_next;//链表的下一个元素  char cancelled; //是否已经cancel了  /* responses to local commands do not go back to command process 如果是本地发起的一个request,就不要再将回复发到command进程 */  char local;           } RequestInfo;  /*timeout的event使用的,和RequestInfo对应,RequestInfo里面存的是一个 来自客户端(或者debug)的请求信息,UserCallbackInfo存的是一个来自内部 的请求(不是local,local对应于debug事件) */  typedef struct UserCallbackInfo{  RIL_TimedCallback p_callback;  void *userParam;  struct ril_event event;  struct UserCallbackInfo *p_next;  } UserCallbackInfo;

 

RIL_RadioFunctions s_callbacks = {0, NULL, NULL, NULL, NULL, NULL};  static int s_registerCalled = 0; //RIL_Register已经调用,s_callbacks已经赋值  static pthread_t s_tid_dispatch;   static pthread_t s_tid_reader; //本文件的这个线程值没有使用  static int s_started = 0; //用于标识event_loop已经开始了  static int s_fdListen = -1; //监听客户端连接的server句柄,连接以后会得到s_fdCommand句柄  static int s_fdCommand = -1; //接收来自客户端命令的句柄,所有的request都来自这个句柄  static int s_fdDebug = -1;//监听Debug命令的句柄,连接以后会生成另外一个fd,不过是临时变量  //下面两个是唤醒多路复用(select)的pipe的两端句柄  static int s_fdWakeupRead;   static int s_fdWakeupWrite;  static struct ril_event s_commands_event;  static struct ril_event s_wakeupfd_event;  static struct ril_event s_listen_event;  static struct ril_event s_wake_timeout_event; //这个没有使用  static struct ril_event s_debug_event;  static const struct timeval TIMEVAL_WAKE_TIMEOUT = {1,0};  static pthread_mutex_t s_pendingRequestsMutex = PTHREAD_MUTEX_INITIALIZER;  static pthread_mutex_t s_writeMutex = PTHREAD_MUTEX_INITIALIZER;  static pthread_mutex_t s_startupMutex = PTHREAD_MUTEX_INITIALIZER;  static pthread_cond_t s_startupCond = PTHREAD_COND_INITIALIZER;  static pthread_mutex_t s_dispatchMutex = PTHREAD_MUTEX_INITIALIZER;  static pthread_cond_t s_dispatchCond = PTHREAD_COND_INITIALIZER;  static RequestInfo *s_pendingRequests = NULL; //挂起的请求队列,也就是待处理的请求  static RequestInfo *s_toDispatchHead = NULL;  static RequestInfo *s_toDispatchTail = NULL;  static UserCallbackInfo *s_last_wake_timeout_info = NULL;  static void *s_lastNITZTimeData = NULL;  static size_t s_lastNITZTimeDataSize;  #if RILC_LOG  static char printBuf[PRINTBUF_SIZE];  #endif


 

 

[系统漏洞]模拟耳机广播实现来电自动接听和拒接

 

来电拒接这个应用的比较广泛,通讯录黑名单用的比较多,而来电自动接听由于安全性,4.1以上的系统已经被禁用了.但是android系统还是有漏洞,这里给大家分析下原理,请勿用于不法操作!
低版本实现来电接听和拒接:
新建ITelephony.aidl文件:




[Java] 纯文本查看 复制代码

// ITelephony.aidl package com.android.internal.telephony; // Declare any non-default types here with import statements interface ITelephony {     /      * Demonstrates some basic types that you can use as parameters      * and return values in AIDL.      */     boolean void answerRingingCall(); }
Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE}); ITelephony telephony = ITelephony.Stub.asInterface(binder);
//获取电话服务 mTelephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); mTelephonyManager.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);

[Java] 纯文本查看 复制代码

 /*      * 继承PhoneStateListener类,我们可以重新其内部的各种监听方法      *然后通过手机状态改变时,系统自动触发这些方法来实现我们想要的功能      */     private class MyPhoneStateListener extends PhoneStateListener {         @Override         public void onCallStateChanged(int state, String incomingNumber) {             switch (state) {                 case TelephonyManager.CALL_STATE_IDLE:                     result = "手机空闲起来了";                     break;                 case TelephonyManager.CALL_STATE_RINGING:                     result = "手机铃声响了,来电号码:" + incomingNumber;                     break;                 case TelephonyManager.CALL_STATE_OFFHOOK:                     result = "电话被挂起了";                 default:                     break;             }             //Toast.makeText(MyBroadCast.this, ""+result, Toast.LENGTH_SHORT).show();             //textView.setText(result);             super.onCallStateChanged(state, incomingNumber);         }
//注册模拟耳机接听电话广播 IntentFilter mediaButtonIntentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON); registerReceiver(mMediaButtonReceiver, mediaButtonIntentFilter);
Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK); meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); sendOrderedBroadcast(meidaButtonIntent, null);
protected class MediaButtonBroadcastReceiver extends BroadcastReceiver {         @Override         public void onReceive(Context context, Intent intent) {             KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);             if ((event != null) && (event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {                 //boolean consumed = PhoneUtils.handleHeadsetHook(phone, event);                 //answerCall(phone.getRingingCall());                 Method method = null;                 try {                     method = Class.forName("android.os.ServiceManager")                             .getMethod("getService", String.class);                 } catch (NoSuchMethodException e) {                     e.printStackTrace();                 } catch (ClassNotFoundException e) {                     e.printStackTrace();                 }                 IBinder binder = null;                 try {                     binder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE});                 } catch (IllegalAccessException e) {                     e.printStackTrace();                 } catch (InvocationTargetException e) {                     e.printStackTrace();                 }                 ITelephony telephony = ITelephony.Stub.asInterface(binder);                 try {                     telephony.answerRingingCall();                 } catch (RemoteException e) {                     e.printStackTrace();                 }             } else {             }         }     }

 

不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。

Android 通信Ril

Android 通信Ril

RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:

  1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:

 Android 通信Ril

 2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:

 Android 通信Ril

3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so

Android 通信Ril

Android的电话系统主要分为三个部分,java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:

Android 通信Ril

Android电话系统设计框架图:

Android 通信Ril

由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。

 

Android电话系统代码结构图:

Android 通信Ril

 

RILD框架设计

在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是RILD的设计框架图:

Android 通信Ril

 

RILD源码分析

接下来通过源码对RILD的整个框架进行详细介绍。

在kernel启动完成后,将启动第一个应用进程Init进程,在android之Init进程启动过程源码分析一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。

service ril-daemon /system/bin/rild       class main       socket rild stream 660 root radio       socket rild-debug stream 660 radio system       user root       group radio cache inet misc audio sdcard_rw log  

RILD进程入口函数分析

接下来给出的是RILD进程启动的时序图:

Android 通信Ril

hardware\ril\rild\rild.c

int main(int argc, char argv) { const char * rilLibPath = NULL; char rilArgv; void *dlHandle; const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char ); const RIL_RadioFunctions *funcs; char libPath[PROPERTY_VALUE_MAX]; unsigned char hasLibArgs = 0; int i;   umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);   //rild启动无参数 for (i = 1; i < argc ;) { if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) { rilLibPath = argv[i + 1]; i += 2; } else if (0 == strcmp(argv[i], "--")) { i++; hasLibArgs = 1; break; } else { usage(argv[0]); } }   if (rilLibPath == NULL) {    //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径 if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) { goto done; } else { rilLibPath = libPath; }   } # 判断是否为模拟器 # #if 1 { static char* arg_overrides[3]; static char arg_device[32]; int done = 0; #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so" /* first, read /proc/cmdline into memory */ char buffer[1024], *p, *q; int len; int fd = open("/proc/cmdline",O_RDONLY); if (fd < 0) { LOGD("could not open /proc/cmdline:%s", strerror(errno)); goto OpenLib; } //读取/proc/cmdline文件中的内容 do { len = read(fd,buffer,sizeof(buffer)); } while (len == -1 && errno == EINTR); if (len < 0) { LOGD("could not read /proc/cmdline:%s", strerror(errno)); close(fd); goto OpenLib; } close(fd); //判断是否为模拟器,对于真机,此处条件为false if (strstr(buffer, "android.qemud=") != NULL) { int tries = 5; #define QEMUD_SOCKET_NAME "qemud" while (1) { int fd; sleep(1); fd = socket_local_client(QEMUD_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM ); if (fd >= 0) { close(fd); snprintf( arg_device, sizeof(arg_device), "%s/%s", ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME ); arg_overrides[1] = "-s"; arg_overrides[2] = arg_device; done = 1; break; } LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno)); if (--tries == 0) break; } if (!done) { LOGE("could not connect to %s socket (giving up): %s", QEMUD_SOCKET_NAME, strerror(errno)); while(1) sleep(0x00ffffff); } } /* otherwise, try to see if we passed a device name from the kernel */ if (!done) do { //true #define KERNEL_OPTION "android.ril=" #define DEV_PREFIX "/dev/" //判断/proc/cmdline中的内容是否包含"android.ril=" p = strstr( buffer, KERNEL_OPTION ); if (p == NULL) break; p += sizeof(KERNEL_OPTION)-1; q = strpbrk( p, " \t\n\r" ); if (q != NULL) *q = 0; snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p ); arg_device[sizeof(arg_device)-1] = 0; arg_overrides[1] = "-d"; arg_overrides[2] = arg_device; done = 1; } while (0); if (done) { //false argv = arg_overrides; argc = 3; i = 1; hasLibArgs = 1; rilLibPath = REFERENCE_RIL_PATH; LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]); } } OpenLib: #endif # 动态库装载 #   switchUser();//设置Rild进程的组用户为radio   //加载厂商自定义的库 ①dlHandle = dlopen(rilLibPath, RTLD_NOW); if (dlHandle == NULL) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); exit(-1);   }   //创建客户端事件监听线程   ②RIL_startEventLoop();   //通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针 ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char ))dlsym(dlHandle, "RIL_Init"); if (rilInit == NULL) { fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath); exit(-1); } if (hasLibArgs) { //false rilArgv = argv + i - 1; argc = argc -i + 1; } else { static char * newArgv[MAX_LIB_ARGS]; static char args[PROPERTY_VALUE_MAX]; rilArgv = newArgv; property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值 argc = make_argv(args, rilArgv); } // Make sure there's a reasonable argv[0]   rilArgv[0] = argv[0];   //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址   ④funcs = rilInit(&s_rilEnv, argc, rilArgv);   //注册客户端事件处理接口RIL_RadioFunctions,并创建socket监听事件 ⑤RIL_register(funcs); done: while(1) { // sleep(UINT32_MAX) seems to return immediately on bionic sleep(0x00ffffff); } } 

在main函数中主要完成以下工作:

1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;

2.使用dlopen手动装载libreference-ril.so库;

3.启动事件循环处理;

4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;

启动事件循环处理eventLoop工作线程

建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。

hardware\ril\libril\Ril.cpp 

extern "C" void RIL_startEventLoop(void) { int ret; pthread_attr_t attr; /* spin up eventLoop thread and wait for it to get started */ s_started = 0; pthread_mutex_lock(&s_startupMutex); pthread_attr_init (&attr);   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);   //创建一个工作线程eventLoop   ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);   //确保函数返回前eventLoop线程启动运行 while (s_started == 0) { pthread_cond_wait(&s_startupCond, &s_startupMutex); } pthread_mutex_unlock(&s_startupMutex); if (ret < 0) { LOGE("Failed to create dispatch thread errno:%d", errno); return; } } 

eventLoop执行时序图:

Android 通信Ril

static void * eventLoop(void *param) { int ret; int filedes[2]; ril_event_init(); //初始化请求队列 pthread_mutex_lock(&s_startupMutex); s_started = 1; //eventLoop线程运行标志位 pthread_cond_broadcast(&s_startupCond);   pthread_mutex_unlock(&s_startupMutex);   //创建匿名管道 ret = pipe(filedes); if (ret < 0) { LOGE("Error in pipe() errno:%d", errno); return NULL;   }   //s_fdWakeupRead为管道读端   s_fdWakeupRead = filedes[0];   //s_fdWakeupWrite为管道写端   s_fdWakeupWrite = filedes[1];   //设置管道读端为O_NONBLOCK非阻塞   fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);   //初始化s_wakeupfd_event结构体的内容,句柄为s_fdWakeupRead,回调函数为 processWakeupCallback ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL); ①rilEventAddWakeup (&s_wakeupfd_event); // Only returns on error ②ril_event_loop(); LOGE ("error in event_loop_base errno:%d", errno); return NULL; } 

在rild中定义了event的概念,Rild支持两种类型的事件:

1. 定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中

2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。

事件定义如下:

struct ril_event { struct ril_event *next; struct ril_event *prev; int fd; //文件句柄 int index; //该事件在监控表中的索引 bool persist; //如果是保持的,则不从watch_list 中删除 struct timeval timeout; //任务执行时间 ril_event_cb func; //回调事件处理函数 void *param; //回调时参数 }; 

在Rild进程中的几个重要事件有

static struct ril_event s_commands_event; ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs) static struct ril_event s_wakeupfd_event; ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL) static struct ril_event s_listen_event; ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL) static struct ril_event s_wake_timeout_event; ril_timer_add(&(p_info->event), &myRelativeTime); static struct ril_event s_debug_event; ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL) 

在RILD中定义了三个事件队列,用于处理不同的事件:

/事件监控队列

static struct ril_event * watch_table[MAX_FD_EVENTS];

//定时事件队列

static struct ril_event timer_list;

//处理事件队列

static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件

Android 通信Ril

添加事件

1.添加Wakeup 事件

static void rilEventAddWakeup(struct ril_event *ev) { ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件 triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环 } [cpp] view plaincopy void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中 watch_table[i] = ev; //向监控表中添加事件 ev->index = i; //事件的索引设置为在监控表中的索引 dlog("~~~~ added at %d ~~~~", i); dump_event(ev); FD_SET(ev->fd, &readFds); //将添加的事件对应的句柄添加到句柄池readFds中 if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值 dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); } 2.添加定时事件 [cpp] view plaincopy void ril_timer_add(struct ril_event * ev, struct timeval * tv) { dlog("~~~~ +ril_timer_add ~~~~"); MUTEX_ACQUIRE(); struct ril_event * list; if (tv != NULL) { list = timer_list.next; ev->fd = -1; // make sure fd is invalid struct timeval now; getNow(&now); timeradd(&now, tv, &ev->timeout); // keep list sorted while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) { list = list->next; } // list now points to the first event older than ev addToList(ev, list); } MUTEX_RELEASE(); dlog("~~~~ -ril_timer_add ~~~~"); } 
触发事件 [cpp] view plaincopy static void triggerEvLoop() { int ret;   if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID do { ret = write (s_fdWakeupWrite, " ", 1); //向管道写端写入值1来触发eventLoop事件循环 } while (ret < 0 && errno == EINTR); } } 处理事件 [cpp] view plaincopy void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。 printReadies(&rfds); n = select(nfds, &rfds, NULL, NULL, ptv); printReadies(&rfds); dlog("~~~~ %d events fired ~~~~", n); if (n < 0) { if (errno == EINTR) continue; LOGE("ril_event: select error (%d)", errno); return; } processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中 processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除 //遍历pending_list,调用事件处理回调函数处理所有事件 firePending(); } } 

在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:

Android 通信Ril

首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。

 

1.超时事件查询

static void processTimeouts() { dlog("~~~~ +processTimeouts ~~~~"); MUTEX_ACQUIRE(); struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); //获取当前时间   dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);   //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { dlog("~~~~ firing timer ~~~~"); next = tev->next; removeFromList(tev); //从timer_list中移除事件 addToList(tev, &pending_list); //将事件添加到pending_list tev = next; } MUTEX_RELEASE(); dlog("~~~~ -processTimeouts ~~~~"); } 2.可读事件查询 [cpp] view plaincopy static void processReadReadies(fd_set * rfds, int n) { dlog("~~~~ +processReadReadies (%d) ~~~~", n);   MUTEX_ACQUIRE();   //遍历watch_table数组,根据select返回的句柄n查找对应的事件 for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct ril_event * rev = watch_table[i]; //得到相应的事件 if (rev != NULL && FD_ISSET(rev->fd, rfds)) { addToList(rev, &pending_list); //将该事件添加到pending_list中 if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除 removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); dlog("~~~~ -processReadReadies (%d) ~~~~", n); } 3.事件处理 [cpp] view plaincopy static void firePending() { dlog("~~~~ +firePending ~~~~"); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件 struct ril_event * next = ev->next; removeFromList(ev); //将处理完的事件从pending_list中移除 ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数 ev = next; } dlog("~~~~ -firePending ~~~~"); } RIL_Env定义 hardware\ril\include\telephony\ril.h [cpp] view plaincopy struct RIL_Env { //动态库完成请求后通知处理结果的接口   void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen); //动态库unSolicited Response通知接口   void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen); //向Rild提交一个超时任务的接口 void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime); }; hardware\ril\rild\rild.c s_rilEnv变量定义: [cpp] view plaincopy static struct RIL_Env s_rilEnv = { RIL_onRequestComplete, RIL_onUnsolicitedResponse, RIL_requestTimedCallback }; 在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数 1.RIL_onRequestComplete [cpp] view plaincopy extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RequestInfo *pRI; int ret; size_t errorOffset; pRI = (RequestInfo *)t; if (!checkAndDequeueRequestInfo(pRI)) { LOGE ("RIL_onRequestComplete: invalid RIL_Token"); return; } if (pRI->local > 0) { // Locally issued command...void only! // response does not go back up the command socket LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber)); goto done; } appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber)); if (pRI->cancelled == 0) { Parcel p; p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) { // there is a response payload, no matter success or not. ret = pRI->pCI->responseFunction(p, response, responselen); /* if an error occurred, rewind and mark it */ if (ret != 0) { p.setDataPosition(errorOffset); p.writeInt32 (ret); } } if (e != RIL_E_SUCCESS) { appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e)); } if (s_fdCommand < 0) { LOGD ("RIL onRequestComplete: Command channel closed"); } sendResponse(p); } done: free(pRI); } 通过调用responseXXX将底层响应传给客户进程 2.RIL_onUnsolicitedResponse [cpp] view plaincopy extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) { int unsolResponseIndex; int ret; int64_t timeReceived = 0; bool shouldScheduleTimeout = false; if (s_registerCalled == 0) { // Ignore RIL_onUnsolicitedResponse before RIL_register LOGW("RIL_onUnsolicitedResponse called before RIL_register"); return; } unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE; if ((unsolResponseIndex < 0) || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) { LOGE("unsupported unsolicited response code %d", unsolResponse); return; } // Grab a wake lock if needed for this reponse, // as we exit we'll either release it immediately // or set a timer to release it later. switch (s_unsolResponses[unsolResponseIndex].wakeType) { case WAKE_PARTIAL: grabPartialWakeLock(); shouldScheduleTimeout = true; break; case DONT_WAKE: default: // No wake lock is grabed so don't set timeout shouldScheduleTimeout = false; break; } // Mark the time this was received, doing this // after grabing the wakelock incase getting // the elapsedRealTime might cause us to goto // sleep. if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { timeReceived = elapsedRealtime(); } appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse)); Parcel p; p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen); if (ret != 0) { // Problem with the response. Don't continue; goto error_exit; } // some things get more payload switch(unsolResponse) { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: p.writeInt32(s_callbacks.onStateRequest()); appendPrintBuf("%s {%s}", printBuf, radioStateToString(s_callbacks.onStateRequest())); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: // Store the time that this was received so the // handler of this message can account for // the time it takes to arrive and process. In // particular the system has been known to sleep // before this message can be processed. p.writeInt64(timeReceived); break; } ret = sendResponse(p); if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { // Unfortunately, NITZ time is not poll/update like everything // else in the system. So, if the upstream client isn't connected, // keep a copy of the last NITZ response (with receive time noted // above) around so we can deliver it when it is connected if (s_lastNITZTimeData != NULL) { free (s_lastNITZTimeData); s_lastNITZTimeData = NULL; } s_lastNITZTimeData = malloc(p.dataSize()); s_lastNITZTimeDataSize = p.dataSize(); memcpy(s_lastNITZTimeData, p.data(), p.dataSize()); } // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT // FIXME The java code should handshake here to release wake lock if (shouldScheduleTimeout) { // Cancel the previous request if (s_last_wake_timeout_info != NULL) { s_last_wake_timeout_info->userParam = (void *)1; } s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT); } return; error_exit: if (shouldScheduleTimeout) { releaseWakeLock(); } } 这个函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。 3.RIL_requestTimedCallback [cpp] view plaincopy extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { internalRequestTimedCallback (callback, param, relativeTime); } [cpp] view plaincopy static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { struct timeval myRelativeTime; UserCallbackInfo *p_info; p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo)); p_info->p_callback = callback; p_info->userParam = param; if (relativeTime == NULL) { /* treat null parameter as a 0 relative time */ memset (&myRelativeTime, 0, sizeof(myRelativeTime)); } else { /* FIXME I think event_add's tv param is really const anyway */ memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime)); } ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info); ril_timer_add(&(p_info->event), &myRelativeTime); triggerEvLoop(); return p_info; } RIL_RadioFunctions定义 客户端向Rild发送请求的接口,由各手机厂商实现。 hardware\ril\include\telephony\Ril.h [cpp] view plaincopy typedef struct { int version; //Rild版本 RIL_RequestFunc onRequest; //AP请求接口 RIL_RadioStateRequest onStateRequest;//BP状态查询 RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion;//动态库版本 } RIL_RadioFunctions; 变量定义: [cpp] view plaincopy static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion }; 在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数 1.onRequest [cpp] view plaincopy static void onRequest (int request, void *data, size_t datalen, RIL_Token t) { ATResponse *p_response; int err; LOGD("onRequest: %s", requestToString(request)); /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS * when RADIO_STATE_UNAVAILABLE. */ if (sState == RADIO_STATE_UNAVAILABLE && request != RIL_REQUEST_GET_SIM_STATUS ) { RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); return; } /* Ignore all non-power requests when RADIO_STATE_OFF * (except RIL_REQUEST_GET_SIM_STATUS) */ if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER || request == RIL_REQUEST_GET_SIM_STATUS) ) { RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); return; } switch (request) { case RIL_REQUEST_GET_SIM_STATUS: { RIL_CardStatus *p_card_status; char *p_buffer; int buffer_size; int result = getCardStatus(&p_card_status); if (result == RIL_E_SUCCESS) { p_buffer = (char *)p_card_status; buffer_size = sizeof(*p_card_status); } else { p_buffer = NULL; buffer_size = 0; } RIL_onRequestComplete(t, result, p_buffer, buffer_size); freeCardStatus(p_card_status); break; } case RIL_REQUEST_GET_CURRENT_CALLS: requestGetCurrentCalls(data, datalen, t); break; case RIL_REQUEST_DIAL: requestDial(data, datalen, t); break; case RIL_REQUEST_HANGUP: requestHangup(data, datalen, t); break; case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: // 3GPP 22.030 6.5.5 // "Releases all held calls or sets User Determined User Busy // (UDUB) for a waiting call." at_send_command("AT+CHLD=0", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: // 3GPP 22.030 6.5.5 // "Releases all active calls (if any exist) and accepts // the other (held or waiting) call." at_send_command("AT+CHLD=1", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: // 3GPP 22.030 6.5.5 // "Places all active calls (if any exist) on hold and accepts // the other (held or waiting) call." at_send_command("AT+CHLD=2", NULL); #ifdef WORKAROUND_ERRONEOUS_ANSWER s_expectAnswer = 1; #endif /* WORKAROUND_ERRONEOUS_ANSWER */ /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_ANSWER: at_send_command("ATA", NULL); #ifdef WORKAROUND_ERRONEOUS_ANSWER s_expectAnswer = 1; #endif /* WORKAROUND_ERRONEOUS_ANSWER */ /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_CONFERENCE: // 3GPP 22.030 6.5.5 // "Adds a held call to the conversation" at_send_command("AT+CHLD=3", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_UDUB: /* user determined user busy */ /* sometimes used: ATH */ at_send_command("ATH", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_SEPARATE_CONNECTION: { char cmd[12]; int party = ((int*)data)[0]; // Make sure that party is in a valid range. // (Note: The Telephony middle layer imposes a range of 1 to 7. // It's sufficient for us to just make sure it's single digit.) if (party > 0 && party < 10) { sprintf(cmd, "AT+CHLD=2%d", party); at_send_command(cmd, NULL); RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } } break; case RIL_REQUEST_SIGNAL_STRENGTH: requestSignalStrength(data, datalen, t); break; case RIL_REQUEST_REGISTRATION_STATE: case RIL_REQUEST_GPRS_REGISTRATION_STATE: requestRegistrationState(request, data, datalen, t); break; case RIL_REQUEST_OPERATOR: requestOperator(data, datalen, t); break; case RIL_REQUEST_RADIO_POWER: requestRadioPower(data, datalen, t); break; case RIL_REQUEST_DTMF: { char c = ((char *)data)[0]; char *cmd; asprintf(&cmd, "AT+VTS=%c", (int)c); at_send_command(cmd, NULL); free(cmd); RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; } case RIL_REQUEST_SEND_SMS: requestSendSMS(data, datalen, t); break; case RIL_REQUEST_SETUP_DATA_CALL: requestSetupDataCall(data, datalen, t); break; case RIL_REQUEST_SMS_ACKNOWLEDGE: requestSMSAcknowledge(data, datalen, t); break; case RIL_REQUEST_GET_IMSI: p_response = NULL; err = at_send_command_numeric("AT+CIMI", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_GET_IMEI: p_response = NULL; err = at_send_command_numeric("AT+CGSN", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_SIM_IO: requestSIM_IO(data,datalen,t); break; case RIL_REQUEST_SEND_USSD: requestSendUSSD(data, datalen, t); break; case RIL_REQUEST_CANCEL_USSD: p_response = NULL; err = at_send_command_numeric("AT+CUSD=2", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: at_send_command("AT+COPS=0", NULL); break; case RIL_REQUEST_DATA_CALL_LIST: requestDataCallList(data, datalen, t); break; case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: requestQueryNetworkSelectionMode(data, datalen, t); break; case RIL_REQUEST_OEM_HOOK_RAW: // echo back data RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); break; case RIL_REQUEST_OEM_HOOK_STRINGS: { int i; const char cur; LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen); for (i = (datalen / sizeof (char *)), cur = (const char )data ; i > 0 ; cur++, i --) { LOGD("> '%s'", *cur); } // echo back strings RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); break; } case RIL_REQUEST_WRITE_SMS_TO_SIM: requestWriteSmsToSim(data, datalen, t); break; case RIL_REQUEST_DELETE_SMS_ON_SIM: { char * cmd; p_response = NULL; asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]); err = at_send_command(cmd, &p_response); free(cmd); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); } at_response_free(p_response); break; } case RIL_REQUEST_ENTER_SIM_PIN: case RIL_REQUEST_ENTER_SIM_PUK: case RIL_REQUEST_ENTER_SIM_PIN2: case RIL_REQUEST_ENTER_SIM_PUK2: case RIL_REQUEST_CHANGE_SIM_PIN: case RIL_REQUEST_CHANGE_SIM_PIN2: requestEnterSimPin(data, datalen, t); break; case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION: requestSmsBroadcastActivation(0,data, datalen, t); break; case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG: LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG"); requestSetSmsBroadcastConfig(0,data, datalen, t); break; case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG: requestGetSmsBroadcastConfig(0,data, datalen, t); break; default: RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); break; } } 对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。 2.currentState [cpp] view plaincopy static RIL_RadioState currentState() { return sState; } 3.onSupports [cpp] view plaincopy static int onSupports (int requestCode) { //@@@ todo return 1; } 4.onCancel [cpp] view plaincopy static void onCancel (RIL_Token t) { //@@@todo } 5.getVersion [cpp] view plaincopy static const char * getVersion(void) { return "android reference-ril 1.0"; 

注册RIL_Env接口

Android 通信Ril

 

1. 向librefrence.so注册libril.so提供的接口RIL_Env;

2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;

3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;

4. 创建一个readLoop工作线程,用于从AT串口中读取数据;

5.返回librefrence.so提供的接口RIL_RadioFunctions;

hardware\ril\reference-ril\reference-ril.c

hardware\ril\reference-ril\reference-ril.c

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char argv)   {       int ret;       int fd = -1;       int opt;       pthread_attr_t attr;     s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv       while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {           switch (opt) {               case 'p':                   s_port = atoi(optarg);                   if (s_port == 0) {                       usage(argv[0]);                       return NULL;                   }                   LOGI("Opening loopback port %d\n", s_port);               break;               case 'd':                   s_device_path = optarg;                   LOGI("Opening tty device %s\n", s_device_path);               break;               case 's':                   s_device_path   = optarg;                   s_device_socket = 1;                   LOGI("Opening socket %s\n", s_device_path);               break;               default:                   usage(argv[0]);                   return NULL;           }       }       if (s_port < 0 && s_device_path == NULL) {           usage(argv[0]);           return NULL;       }       pthread_attr_init (&attr);     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);     //创建一个mainLoop线程     ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);     //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks       return &s_callbacks;   }

mainLoop工作线程是用来初始化并监控AT模块的,一旦AT模块被关闭,就自动打开。

static void * mainLoop(void *param)   {       int fd;       int ret;     AT_DUMP("== ", "entering mainLoop()", -1 );     //为AT模块设置回调函数       at_set_on_reader_closed(onATReaderClosed);       at_set_on_timeout(onATTimeout);       for (;;) {           fd = -1;           while  (fd < 0) { //获得串口AT模块的设备文件描述符               if (s_port > 0) {                   fd = socket_loopback_client(s_port, SOCK_STREAM);               } else if (s_device_socket) {                   if (!strcmp(s_device_path, "/dev/socket/qemud")) {                       /* Qemu-specific control socket */                       fd = socket_local_client( "qemud",                    ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );                       if (fd >= 0 ) {                           char  answer[2];                           if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||                                memcmp(answer, "OK", 2) != 0)                           {                               close(fd);                               fd = -1;                           }                      }                   }                   else                       fd = socket_local_client( s_device_path,    ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );               } else if (s_device_path != NULL) {                   fd = open (s_device_path, O_RDWR);                   if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {                       /* disable echo on serial ports */                       struct termios  ios;                       tcgetattr( fd, &ios );                       ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */                       tcsetattr( fd, TCSANOW, &ios );                   }               }               if (fd < 0) {                   perror ("opening AT interface. retrying...");                   sleep(10);               }           }           s_closed = 0;           //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄           ret = at_open(fd, onUnsolicited);           if (ret < 0) {               LOGE ("AT error %d on at_open\n", ret);               return 0;           }           //向Rild提交超时任务           RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);           sleep(1);           //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞           waitForClose();           LOGI("Re-opening after close");       }   }  

1.打开AT模块

通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler 

int at_open(int fd, ATUnsolHandler h)   {       int ret;       pthread_t tid;       pthread_attr_t attr;       s_fd = fd;       s_unsolHandler = h;       s_readerClosed = 0;       s_responsePrefix = NULL;       s_smsPDU = NULL;       sp_response = NULL;       /* Android power control ioctl */   #ifdef HAVE_ANDROID_OS   #ifdef OMAP_CSMI_POWER_CONTROL       ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);       if(ret == 0) {           int ack_count;           int read_count;           int old_flags;           char sync_buf[256];           old_flags = fcntl(fd, F_GETFL, 0);           fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);           do {               ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);               read_count = 0;               do {                   ret = read(fd, sync_buf, sizeof(sync_buf));                   if(ret > 0)                       read_count += ret;               } while(ret > 0 || (ret < 0 && errno == EINTR));               ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);            } while(ack_count > 0 || read_count > 0);           fcntl(fd, F_SETFL, old_flags);           s_readCount = 0;           s_ackPowerIoctl = 1;       }       else           s_ackPowerIoctl = 0;   #else // OMAP_CSMI_POWER_CONTROL           s_ackPowerIoctl = 0;   #endif // OMAP_CSMI_POWER_CONTROL   #endif /*HAVE_ANDROID_OS*/       pthread_attr_init (&attr);     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);     //创建readerLoop工作线程,该线程用于从串口读取数据       ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);       if (ret < 0) {           perror ("pthread_create");           return -1;       }       return 0;   }  

2.添加定时事件RIL_requestTimedCallback

RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);      #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)  

向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT指令来初始化BP的modem。

3.readLoop工作线程

Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。

Android 通信Ril

static void *readerLoop(void *arg)   {       for (;;) {           const char * line;           line = readline();           if (line == NULL) {               break;           }           if(isSMSUnsolicited(line)) { //判断是否是SMS 通知               char *line1;               const char *line2;               line1 = strdup(line);               line2 = readline();               if (line2 == NULL) {                   break;               }               if (s_unsolHandler != NULL) {                   s_unsolHandler (line1, line2); //回调通知SMS               }               free(line1);           } else {               processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数           }   #ifdef HAVE_ANDROID_OS           if (s_ackPowerIoctl > 0) {               /* acknowledge that bytes have been read and processed */               ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);               s_readCount = 0;           }   #endif /*HAVE_ANDROID_OS*/       }       onReaderClosed();       return NULL;   }  

注册RIL_RadioFunctions接口

hardware\ril\libril\ril.cpp

extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {       int ret;     int flags;     //版本验证       if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {            return;       }       if (callbacks->version < RIL_VERSION) {           LOGE ("RIL_register: upgrade RIL to version %d current version=%d",                 RIL_VERSION, callbacks->version);       }       if (s_registerCalled > 0) {           LOGE("RIL_register has been called more than once. "Subsequent call ignored");           return;     }       //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中       memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));       s_registerCalled = 1;       for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {           assert(i == s_commands[i].requestNumber); //序号验证       }       for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {           assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber);       }       // old standalone impl wants it here.       if (s_started == 0) {           RIL_startEventLoop();       }     // 得到名为rild的socket句柄     s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);       if (s_fdListen < 0) {           LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");           exit(-1);     }     // 监听该socket       ret = listen(s_fdListen, 4);       if (ret < 0) {           LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));           exit(-1);       }       /* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/     ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);       /* 添加s_listen_event事件,并触发eventLoop工作线程 */       rilEventAddWakeup (&s_listen_event);   #if 1       // 得到调试socket的句柄rild-debug       s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);       if (s_fdDebug < 0) {           LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);           exit(-1);     }     //监听该socket       ret = listen(s_fdDebug, 4);       if (ret < 0) {           LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));           exit(-1);     }       /* 设置s_debug_event事件 */       ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);       /* 添加s_debug_event事件,并触发eventLoop工作线程  */       rilEventAddWakeup (&s_debug_event);   #endif   }  

打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。

1.客户端连接处理

s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:

static void listenCallback (int fd, short flags, void *param) {       int ret;       int err;       int is_phone_socket;       RecordStream *p_rs;       commthread_data_t *user_data = NULL;       user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));       struct sockaddr_un peeraddr;       socklen_t socklen = sizeof (peeraddr);       struct ucred creds;       socklen_t szCreds = sizeof(creds);       struct passwd *pwd = NULL;       assert (s_fdCommand < 0);     assert (fd == s_fdListen);     //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中       s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);       if (s_fdCommand < 0 ) {           LOGE("Error on accept() errno:%d", errno);           /* start listening for new connections again */           rilEventAddWakeup(&s_listen_event);             return;       }       /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/       errno = 0;       is_phone_socket = 0;       err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);       if (err == 0 && szCreds > 0) {           errno = 0;           pwd = getpwuid(creds.uid);           if (pwd != NULL) {               if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {                   is_phone_socket = 1;               } else {                   LOGE("RILD can't accept socket from process %s", pwd->pw_name);               }           } else {               LOGE("Error on getpwuid() errno: %d", errno);           }       } else {           LOGD("Error on getsockopt() errno: %d", errno);       }              if ( !is_phone_socket ) {         LOGE("RILD must accept socket from %s", PHONE_PROCESS);         close(s_fdCommand);         s_fdCommand = -1;         onCommandsSocketClosed();         /* start listening for new connections again */         rilEventAddWakeup(&s_listen_event);         return;       }   #if 0       if(s_dualSimMode) {           if(s_sim_num == 0) {               property_get(SIM_POWER_PROPERTY, prop, "0");               if(!strcmp(prop, "0")) {                   property_set(SIM_POWER_PROPERTY, "1");                   s_callbacks.powerSIM(NULL);               }           } else if(s_sim_num == 1) {               property_get(SIM_POWER_PROPERTY1, prop, "0");               if(!strcmp(prop, "0")) {                   property_set(SIM_POWER_PROPERTY1, "1");                   s_callbacks.powerSIM(NULL);               }           }       } else {           property_get(SIM_POWER_PROPERTY, prop, "0");           if(!strcmp(prop, "0")) {               property_set(SIM_POWER_PROPERTY, "1");               s_callbacks.powerSIM(NULL);           }       }   #endif       //p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据     p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);     //添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求       ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);       rilEventAddWakeup (&s_commands_event);       onNewCommandConnect();   }  

2.客户端通信处理

在listenCallback中首先接收客户端的连接请求,并验证客户端的权限,同时将该客户端以事件的形式添加到eventLoop工作线程中进行监控,当该客户端有数据请求时,eventLoop工作线程从select中返回,并自动调用processCommandsCallback回调函数:

static void processCommandsCallback(int fd, short flags, void *param) {       RecordStream *p_rs;       void *p_record;       size_t recordlen;       int ret;       assert(fd == s_fdCommand);       p_rs = (RecordStream *)param;     for (;;) { //循环处理客户端发送过来的AT命令         //读取一条AT命令           ret = record_stream_get_next(p_rs, &p_record, &recordlen);           if (ret == 0 && p_record == NULL) {               break;           } else if (ret < 0) {               break;           } else if (ret == 0) { /* && p_record != NULL */               //处理客户端发送过来的AT命令               processCommandBuffer(p_record, recordlen);           }       }       if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {           if (ret != 0) {               LOGE("error on reading command socket errno:%d\n", errno);           } else {               LOGW("EOS.  Closing command socket.");           }           close(s_fdCommand);           s_fdCommand = -1;           ril_event_del(&s_commands_event);           record_stream_free(p_rs);           rilEventAddWakeup(&s_listen_event);           onCommandsSocketClosed();       }   }  

通过processCommandBuffer函数来处理每一条AT命令:

static int processCommandBuffer(void *buffer, size_t buflen) {       Parcel p;       status_t status;       int32_t request;       int32_t token;       RequestInfo *pRI;       int ret;       p.setData((uint8_t *) buffer, buflen);       // status checked at end       status = p.readInt32(&request);       status = p.readInt32 (&token);       if (status != NO_ERROR) {           LOGE("invalid request block");           return 0;       }       if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {           LOGE("unsupported request code %d token %d", request, token);           return 0;       }       pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));       pRI->token = token; //AT命令标号       pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令       ret = pthread_mutex_lock(&s_pendingRequestsMutex);       assert (ret == 0);       pRI->p_next = s_pendingRequests;       s_pendingRequests = pRI;       ret = pthread_mutex_unlock(&s_pendingRequestsMutex);     assert (ret == 0);     //调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。       pRI->pCI->dispatchFunction(p, pRI);       return 0;   }  

打电话的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},

3.电话拨打流程

Android 通信Ril

static void dispatchDial (Parcel &p, RequestInfo *pRI) {     RIL_Dial dial; //RIL_Dial存储了打电话的所有信息       RIL_UUS_Info uusInfo;        int32_t sizeOfDial;       int32_t t;       .................. //初始化dial变量       s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);     .................       return;   }  

s_callbacks.onRequest其实就是调用RIL_RadioFunctions中的onRequest函数,该函数在前面已介绍过了。

static void onRequest (int request, void *data, size_t datalen, RIL_Token t)   {       switch (request) {           case RIL_REQUEST_DIAL:               requestDial(data, datalen, t);               break;       }   }  
static void requestDial(void *data, size_t datalen, RIL_Token t)   {       RIL_Dial *p_dial;       char *cmd;       const char *clir;       int ret;       p_dial = (RIL_Dial *)data;       switch (p_dial->clir) {           case 1: clir = "I"; break;  /*invocation*/           case 2: clir = "i"; break;  /*suppression*/           default:           case 0: clir = ""; break;   /*subscription default*/     }     //向串口发送AT指令       ret = at_send_command(cmd, NULL);     free(cmd);     //通知请求结果       RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);   }  

向AT发送完拨号指令后,通过RIL_onRequestComplete返回处理结果,RIL_onRequestComplete实际上是RIL_Env中的OnRequestComplete函数,在前面我们也介绍过了

extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {       RequestInfo *pRI;       int ret;       size_t errorOffset;     pRI = (RequestInfo *)t;     //该请求已经处理,需要从请求队列中移除该请求       if (!checkAndDequeueRequestInfo(pRI)) {           LOGE ("RIL_onRequestComplete: invalid RIL_Token");           return;       }       if (pRI->local > 0) {           ...........           sendResponse(p);       }   done:       free(pRI);   }   
static int sendResponse (Parcel &p) {       return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端   }

 

static int sendResponseRaw (const void *data, size_t dataSize) {       int fd = s_fdCommand;       int ret;       uint32_t header;       if (s_fdCommand < 0) {           return -1;       }       if (dataSize > MAX_COMMAND_BYTES) {           return -1;       }       pthread_mutex_lock(&s_writeMutex);       header = htonl(dataSize);       ret = blockingWrite(fd, (void *)&header, sizeof(header));       if (ret < 0) {           pthread_mutex_unlock(&s_writeMutex);           return ret;       }       ret = blockingWrite(fd, data, dataSize);       if (ret < 0) {           pthread_mutex_unlock(&s_writeMutex);           return ret;       }       pthread_mutex_unlock(&s_writeMutex);       return 0;   }  

拨打电话的时序图如下:Android 通信Ril
 

Rild通过onRequest向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/207606.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午1:29
下一篇 2026年3月19日 下午1:30


相关推荐

  • LR测试心得

    LR测试心得

    2021年9月8日
    49
  • ODS简介_医学ods是什么意思

    ODS简介_医学ods是什么意思什么是ODS操作数据存储ODS(OperationalDataStore)是数据仓库体系结构中的一个可选部分,由业务系统产生的报表、细节数据的查询自然能够从ODS中进行,从而降低业务系统的查询压力。ODS设计与DW设计在着眼点上有所不同,ODS重点考虑业务系统数据是什么样子的,关系如何,在业务流程处理的哪个环节,以及数据抽取接口等问题。ODS是一个将面向主题的,动态增长的,非实时的,消除了原

    2026年4月14日
    5
  • php iconv_strlen,iconv详解

    php iconv_strlen,iconv详解头文件 inconv h iconv 命令可以将一种已知的字符集文件转换成另一种已知的字符集文件 它的作用是在多种国际编码格式之间进行文本内码的转换 作为编程接口的 iconv 包括 3 个函数 iconv open 函数用于初始化用于转换的内部缓冲区 需要指明需要从何种编码方式转换到哪一种 iconv 函数进行实际的转换 需要给出两个间接缓冲区指针和剩余字节数指针 该函数需要更新所有相关信息 因此将不可改写

    2026年3月17日
    2
  • 直线段检测法(LSD)

    直线段检测法(LSD)直线段检测法(LSD)1简介2算法介绍3.算法简述感谢观看:)本文仅用于个人学习/复习1简介LSD是一种线段检测算法,该方法号称是能在线性时间(linear-time)内得到亚像素级准确度的直线段检测算法。LSD的目标在于检测图像中局部的直的轮廓,这也是我们称之为直线分割的原因。2算法介绍LSD直线检测方法首先计算每个像素点的水平线(level-Line)角度,从而形成了一个水平线场,即单位矢量场,这里像素点的水平线角度就是该点梯度方向的垂直角度,如下图所示,而水平线场就是一个与图像中的点一一对应

    2022年4月30日
    52
  • 走近代码之Python–爬虫框架Portia | 艾伯特

    走近代码之Python–爬虫框架Portia | 艾伯特Portia nbsp 基于 Scrapy 的可视化数据采集框架走近代码之 Python 爬虫框架 Scrapy1 框架特性基于 scrapy 内核可视化爬取内容 不需要任何开发专业知识动态匹配相同模板的内容 2 安装 Windows 推荐使用 Docker 安装安装 DockerToolBo 启动 nbsp dockerrun v F pywp portia app data projects

    2026年3月18日
    3
  • java OA开源办公系统源码下载

    java OA开源办公系统源码下载javaOA 开源办公系统源码下载源代码下载地址 http www zuidaima com share 155046368126 htm

    2026年3月18日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号