在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP。AP与BP之间有两种通信方式:
1.Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:
{数组中的索引号,请求回调函数,响应回调函数}
{0, NULL, NULL}, //none {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts}, {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList}, {RIL_REQUEST_DIAL, dispatchDial, responseVoid}, {RIL_REQUEST_GET_IMSI, dispatchStrings, responseString}, {RIL_REQUEST_HANGUP, dispatchInts, responseVoid}, {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid}, {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid}, {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid}, {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid}, {RIL_REQUEST_UDUB, dispatchVoid, responseVoid}, {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength}, {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings}, {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings}, {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings}, {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid}, {RIL_REQUEST_DTMF, dispatchString, responseVoid}, {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS}, {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS}, {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}, {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO}, {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid}, {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid}, {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts}, {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards}, {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid}, {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts}, {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid}, {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString}, {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString}, {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid}, {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid}, {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts}, {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid}, {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid}, {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid}, {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings}, {RIL_REQUEST_DTMF_START, dispatchString, responseVoid}, {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid}, {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString}, {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid}, {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts}, {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts}, {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList}, {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid}, {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw}, {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings}, {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid}, {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid}, {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts}, {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid}, {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString}, {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid}, {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString}, {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid}, {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid}, {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid}, {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts}, {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList}, {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts}, {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid}, {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid}, {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid}, {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS}, {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid}, {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf}, {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid}, {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf}, {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid}, {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings}, {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts}, {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid}, {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings}, {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid}, {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString}, {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid}, {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid}, {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid}, {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchCdmaSubscriptionSource, responseInts}, {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString}, {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, dispatchStrings, responseVoid}, {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, dispatchString, responseSIM_IO}, {RIL_REQUEST_VOICE_RADIO_TECH, dispatchVoiceRadioTech, responseInts},
2.unSolicited Response:Bp主动给Ap发送事件,该类型的AT指令及其回调函数以数组的形式存放在ril_unsol_commands.h文件中:
{数组中的索引号,响应回调函数,类型}
{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL}, {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE}, {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL}, {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE}, {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL}, {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL}, {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL}, {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL}, {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_SIM_REFRESH, responseSimRefresh, WAKE_PARTIAL}, {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL}, {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL}, {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, responseInts, WAKE_PARTIAL},
不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。
RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:
1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:
2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:
3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so
Android的电话系统主要分为三个部分,java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:
Android电话系统设计框架图:
由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。
Android电话系统代码结构图:
在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是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进程启动的时序图:
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库通信桥梁;
建立多路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执行时序图:
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; //待处理事件队列,事件已经触发,需要所回调处理的事件
1.添加Wakeup 事件
static void rilEventAddWakeup(struct ril_event *ev) { ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件 triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环 }
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.添加定时事件
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 ~~~~"); }
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); } }
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工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:
首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。
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 ~~~~"); }
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); }
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 ~~~~"); }
hardware\ril\include\telephony\ril.h
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变量定义:
static struct RIL_Env s_rilEnv = { RIL_onRequestComplete, RIL_onUnsolicitedResponse, RIL_requestTimedCallback };
在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数
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将底层响应传给客户进程
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从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。
extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { internalRequestTimedCallback (callback, param, relativeTime); }
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; }
客户端向Rild发送请求的接口,由各手机厂商实现。
hardware\ril\include\telephony\Ril.h
typedef struct { int version; //Rild版本 RIL_RequestFunc onRequest; //AP请求接口 RIL_RadioStateRequest onStateRequest;//BP状态查询 RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion;//动态库版本 } RIL_RadioFunctions;
变量定义:
static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion };
在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数
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的最终响应后,线程被唤醒,将响应传给客户端进程。
static RIL_RadioState currentState() { return sState; }
static int onSupports (int requestCode) { //@@@ todo return 1; }
static void onCancel (RIL_Token t) { //@@@todo }
static const char * getVersion(void) { return "android reference-ril 1.0"; }
由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。
RIL_Init的主要任务:
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
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: 转自:http://www.xuebuyuan.com/1487968.html