RIL层的作用大体上就是将上层的命令转换成相应的AT指令,控制modem工作。生产modem的厂家有很多:Qualcomm, STE, Infineon... 不同的厂家都有各自的特点,当然也会有各自不同的驱动,但驱动代码的公开多少会涉及到modem厂家的技术细节,所以,Android系统开源了绝大部分代码,对于 部分驱动(Reference-RIL) 允许厂家以二进制Lib的形式成为一套完整Android系统的一部分。
有Lib就需要有加载的概念,能够加载各种驱动说明驱动们都遵从一个统一的接口。这个接口是什么?RILC又是如何接收并处理RILJ向下传来的请求?
进入hardware\ril\rild\rild.c,一切从main开始。
int main(int argc, char **argv) { ... ... dlHandle = dlopen(rilLibPath, RTLD_NOW); if (dlHandle == NULL) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); exit(-1); } RIL_startEventLoop(); // ril_event 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); } ... ... funcs = rilInit(&s_rilEnv, argc, rilArgv); // Reference-RIL 获得 LibRIL 的Interface RIL_register(funcs); // LibRIL 获得 Reference-RIL 的Interface }
从dlopen看到了动态加载的痕迹,加载Reference-RIL之后便启动了监听线程,也就在RIL_startEventLoop。每一次从上层传来的请求都是一个event,可见要了解该层的消息传输,关键是要了解 结构体 ril_event。
与其相关的文件是ril_event.h、ril_event.cpp,对于文件的分析还是引用ACE1985兄台的博文为好,抱拳为敬。
// 每次监视的最大的文件描述符句柄数,可以根据需要自行修改 #define MAX_FD_EVENTS 8 // ril_event的回调函数 typedef void (*ril_event_cb)(int fd, short events, void *userdata); struct ril_event { // 用于将ril_event串成双向链表的前向指针和后向指针 struct ril_event *next; struct ril_event *prev; //ril事件相关的文件描述符句柄(可以是文件、管道、Socket等) int fd; //这个事件在监控列表中的索引 int index; //当一个事件处理完后(即从watch_table移到pending_list中等待处理), //persist参数决定这个事件是否一直存在于监控列表watch_table[]中 bool persist; //事件的超时时间 struct timeval timeout; //回调函数及其传入的参数 ril_event_cb func; void *param; }; //以下是ril事件相关的一些操作函数 // 初始化内部数据结构 void ril_event_init(); // 初始化一个ril事件 void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param); // 将事件添加到监控列表watch_table[]中 void ril_event_add(struct ril_event * ev); // 增加一个timer事件到timer_list链表中 void ril_timer_add(struct ril_event * ev, struct timeval * tv); // 将指定的事件从监控列表watch_table[]中移除 void ril_event_del(struct ril_event * ev); // 事件循环 void ril_event_loop();
#define LOG_TAG "RILC" #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <utils/Log.h> #include <ril_event.h> #include <string.h> #include <sys/time.h> #include <time.h> #include <pthread.h> // 使用互斥量mutex进行线程同步,可参见《Linux程序设计》相关章节 static pthread_mutex_t listMutex; #define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex) #define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex) #define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL) #define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex) // 两个timeval类型的值相加 #ifndef timeradd #define timeradd(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ if ((vvp)->tv_usec >= 1000000) { \ (vvp)->tv_sec++; \ (vvp)->tv_usec -= 1000000; \ } \ } while (0) #endif // 两个timeval类型的值进行比较 #ifndef timercmp #define timercmp(a, b, op) \ ((a)->tv_sec == (b)->tv_sec \ ? (a)->tv_usec op (b)->tv_usec \ : (a)->tv_sec op (b)->tv_sec) #endif // 两个timeval类型的值相减 #ifndef timersub #define timersub(a, b, res) \ do { \ (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((res)->tv_usec < 0) { \ (res)->tv_usec += 1000000; \ (res)->tv_sec -= 1; \ } \ } while(0); #endi // 保存Rild中所有设备文件句柄,便于使用select函数完成事件的监听 static fd_set readFds; // 记录readFds中最大fd值+1 static int nfds = 0; // 为了统一管理ril事件,Android提供如下三个队列: // 监控事件列表,需要检测的事件都需要先存入该列表中 static struct ril_event * watch_table[MAX_FD_EVENTS]; // timer事件队列,事件超时后即移入pending_list队列中 static struct ril_event timer_list; // 待处理的事件队列,即事件已经触发,后续需要调用事件的回调函数 static struct ril_event pending_list; #define DEBUG 0 #if DEBUG #define dlog(x...) LOGD( x ) static void dump_event(struct ril_event * ev) { dlog("~~~~ Event %x ~~~~", (unsigned int)ev); dlog(" next = %x", (unsigned int)ev->next); dlog(" prev = %x", (unsigned int)ev->prev); dlog(" fd = %d", ev->fd); dlog(" pers = %d", ev->persist); dlog(" timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec); dlog(" func = %x", (unsigned int)ev->func); dlog(" param = %x", (unsigned int)ev->param); dlog("~~~~~~~~~~~~~~~~~~"); } #else #define dlog(x...) do {} while(0) #define dump_event(x) do {} while(0) #endif // 获取此刻timeval值 static void getNow(struct timeval * tv) { #ifdef HAVE_POSIX_CLOCKS struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec/1000; #else gettimeofday(tv, NULL); #endif } // 初始化指定的ril_event链表 static void init_list(struct ril_event * list) { memset(list, 0, sizeof(struct ril_event)); list->next = list; list->prev = list; list->fd = -1; } // 增加一个ril_event事件到ril_event队列头 static void addToList(struct ril_event * ev, struct ril_event * list) { ev->next = list; ev->prev = list->prev; ev->prev->next = ev; list->prev = ev; dump_event(ev); } // 从ril_event队列中移除指定的ril_event static void removeFromList(struct ril_event * ev) { dlog("~~~~ Removing event ~~~~"); dump_event(ev); ev->next->prev = ev->prev; ev->prev->next = ev->next; ev->next = NULL; ev->prev = NULL; } // 从watch_table[]中移除指定索引的事件 static void removeWatch(struct ril_event * ev, int index) { // 索引index对应的事件置为空,同时事件ev的索引设为无效值-1 watch_table[index] = NULL; ev->index = -1; // 将该事件对应的文件描述符句柄从readFds中清除 FD_CLR(ev->fd, &readFds); if (ev->fd+1 == nfds) { int n = 0; for (int i = 0; i < MAX_FD_EVENTS; i++) { struct ril_event * rev = watch_table[i]; if ((rev != NULL) && (rev->fd > n)) { n = rev->fd; } } nfds = n + 1; dlog("~~~~ nfds = %d ~~~~", nfds); } } // 遍历timer_list队列中的事件,当事件超时时间到时 // 将事件移除,并添加到pending_list队列中 static void processTimeouts() { dlog("~~~~ +processTimeouts ~~~~"); MUTEX_ACQUIRE(); struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); // walk list, see if now >= ev->timeout for any events dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { // Timer expired dlog("~~~~ firing timer ~~~~"); next = tev->next; removeFromList(tev); addToList(tev, &pending_list); tev = next; } MUTEX_RELEASE(); dlog("~~~~ -processTimeouts ~~~~"); } // 遍历监控列表watch_table[]中的事件,并将有数据可读的事件 // 添加到pending_list链表中,同时如果事件的persist不为true // 则将该事件从watch_table[]中移除 static void processReadReadies(fd_set * rfds, int n) { dlog("~~~~ +processReadReadies (%d) ~~~~", n); MUTEX_ACQUIRE(); 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); if (rev->persist == false) { removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); dlog("~~~~ -processReadReadies (%d) ~~~~", n); } // 依次调用待处理队列pending_list中的事件的回调函数 static void firePending() { dlog("~~~~ +firePending ~~~~"); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { struct ril_event * next = ev->next; removeFromList(ev); ev->func(ev->fd, 0, ev->param); ev = next; } dlog("~~~~ -firePending ~~~~"); } // 计算timer_list链表中下一个事件的新的超时时间 static int calcNextTimeout(struct timeval * tv) { struct ril_event * tev = timer_list.next; struct timeval now; getNow(&now); // Sorted list, so calc based on first node if (tev == &timer_list) { // no pending timers return -1; } dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); dlog("~~~~ next = %ds + %dus ~~~~", (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec); if (timercmp(&tev->timeout, &now, >)) { timersub(&tev->timeout, &now, tv); } else { // timer already expired. tv->tv_sec = tv->tv_usec = 0; } return 0; } // 初始化内部数据结构(互斥量、FD集合、三个事件队列) void ril_event_init() { MUTEX_INIT(); FD_ZERO(&readFds); init_list(&timer_list); init_list(&pending_list); memset(watch_table, 0, sizeof(watch_table)); } // 初始化一个ril事件 void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param) { dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev); memset(ev, 0, sizeof(struct ril_event)); ev->fd = fd; ev->index = -1; ev->persist = persist; ev->func = func; ev->param = param; //linux的文件上锁函数,给文件描述符fd上非阻塞的文件锁 fcntl(fd, F_SETFL, O_NONBLOCK); } // 将事件添加到监控列表watch_table[]中 void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { 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); if (ev->fd >= nfds) nfds = ev->fd+1; dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); } // 增加一个timer事件到timer_list链表中 void ril_timer_add(struct ril_event * ev, struct timeval * tv) { dlog("~~~~ +ril_timer_add ~~~~"); MUTEX_ACQUIRE(); struct ril_event * list; if (tv != NULL) { // add to timer list list = timer_list.next; ev->fd = -1; // make sure fd is invalid struct timeval now; getNow(&now); timeradd(&now, tv, &ev->timeout); // 根据timeout值从小到大在链表中排序 while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) { list = list->next; } // 循环结束后,list指向链表中第一个timeout值大于ev的事件 // 将新加入的事件ev加到list此刻指向的事件前面 addToList(ev, list); } MUTEX_RELEASE(); dlog("~~~~ -ril_timer_add ~~~~"); } // 将事件从watch_table[]中移除 void ril_event_del(struct ril_event * ev) { dlog("~~~~ +ril_event_del ~~~~"); MUTEX_ACQUIRE(); if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) { MUTEX_RELEASE(); return; } removeWatch(ev, ev->index); MUTEX_RELEASE(); dlog("~~~~ -ril_event_del ~~~~"); } #if DEBUG // 打印监控列表中可用的事件 static void printReadies(fd_set * rfds) { for (int i = 0; (i < MAX_FD_EVENTS); i++) { struct ril_event * rev = watch_table[i]; if (rev != NULL && FD_ISSET(rev->fd, rfds)) { dlog("DON: fd=%d is ready", rev->fd); } } } #else #define printReadies(rfds) do {} while(0) #endif void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { // make local copy of read fd_set memcpy(&rfds, &readFds, sizeof(fd_set)); // 根据timer_list来计算select函数的等待时间 // timer_list之前已按事件的超时时间排好序了 if (-1 == calcNextTimeout(&tv)) { // no pending timers; block indefinitely dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } printReadies(&rfds); // 使用select函数实现多路IO复用 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); // bail? return; } // Check for timeouts processTimeouts(); // Check for read-ready processReadReadies(&rfds, n); // Fire away firePending(); } }
若干ril_event构成watch_table数组,同时也被两个双向链表timer_list、pending_list串起来,不禁想起了内核链表。select对watch_table数组上的ril_event们进行监听。
RILJ与RILC通过socket连接,前者为client,后者为server。
server通过select监听对外开放的socket端口fd,若RILJ请求连接,则回调listenCallback(),accept()出一个s_fdCommand,加入select监听数组,这个s_fdCommand便成为了上层传入请求的通道,RILC通过这个通道接收具体的command,而后转化为AT指令。
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;
以上便是大致的思路,select+socket连接的经典模式。通道打通后,从s_fdCommand中到底会接收到什么?
ril_event_set (&s_commands_event, s_fdCommand, 1, processCommandsCallback, p_rs);
函数层层嵌套,终会有一个办实事的命令。
static int processCommandBuffer(void *buffer, size_t buflen) { Parcel p; status_t status; int32_t request; int32_t token; RequestInfo *pRI; //构造该结构体,尤其是其中的pCI int ret; p.setData((uint8_t *) buffer, buflen); //获得有效p // status checked at end status = p.readInt32(&request); //取得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); // FIXME this should perhaps return a response return 0; } pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); pRI->token = token; pRI->pCI = &(s_commands[request]); //确定早已待命的command号 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); /* sLastDispatchedToken = token; */ pRI->pCI->dispatchFunction(p, pRI); //命令,发射! return 0; }
Ok,这个办实事的命令就是s_comands数组第request个结构体中的dispatchFunction().
s_comands数组是个啥?
static CommandInfo s_commands[] = { #include "ril_commands.h" };
typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int (*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;
Ref: http://blog.csdn.net/ace1985/article/details/7051522
1 {0, NULL, NULL}, //none 2 {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, 3 {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts}, 4 {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts}, 5 {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts}, 6 {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts}, 7 {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts}, 8 {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts}, 9 {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts}, 10 {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList}, 11 {RIL_REQUEST_DIAL, dispatchDial, responseVoid}, 12 {RIL_REQUEST_GET_IMSI, dispatchVoid, responseString}, 13 {RIL_REQUEST_HANGUP, dispatchInts, responseVoid}, 14 {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid}, 15 {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid}, 16 {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid}, 17 {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid}, 18 {RIL_REQUEST_UDUB, dispatchVoid, responseVoid}, 19 {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, 20 {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength}, 21 {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings}, 22 {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings}, 23 {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings}, 24 {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid}, 25 {RIL_REQUEST_DTMF, dispatchString, responseVoid}, 26 {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS}, 27 {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS}, 28 {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}, 29 {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO}, 30 {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid}, 31 {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid}, 32 {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts}, 33 {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid}, 34 {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards}, 35 {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid}, 36 {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts}, 37 {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid}, 38 {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid}, 39 {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString}, 40 {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString}, 41 {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid}, 42 {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid}, 43 {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts}, 44 {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts}, 45 {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid}, 46 {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts}, 47 {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid}, 48 {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid}, 49 {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings}, 50 {RIL_REQUEST_DTMF_START, dispatchString, responseVoid}, 51 {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid}, 52 {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString}, 53 {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid}, 54 {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid}, 55 {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts}, 56 {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts}, 57 {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, 58 {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList}, 59 {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid}, 60 {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw}, 61 {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings}, 62 {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid}, 63 {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid}, 64 {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts}, 65 {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid}, 66 {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid}, 67 {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts}, 68 {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString}, 69 {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid}, 70 {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString}, 71 {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid}, 72 {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid}, 73 {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid}, 74 {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid}, 75 {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts}, 76 {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList}, 77 {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid}, 78 {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid}, 79 {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid}, 80 {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts}, 81 {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid}, 82 {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts}, 83 {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid}, 84 {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts}, 85 {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid}, 86 {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid}, 87 {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid}, 88 {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS}, 89 {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid}, 90 {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf}, 91 {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid}, 92 {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, 93 {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf}, 94 {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid}, 95 {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, 96 {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings}, 97 {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts}, 98 {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid}, 99 {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings}, 100 {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid}, 101 {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString}, 102 {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid}, 103 {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid}, 104 {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid}, 105 {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchVoid, responseInts}, 106 {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString}
RIL中有两种Response类型:
一是Solicited Response(经过请求的回复),应用的场景是AP主动向BP发送一个AT指令,请求BP进行相应处理并在处理结束时回复一个AT指令通知AP执行的结果。源码中对应的文件是ril_commands.h。
一是Unsolicited Response(未经请求的回复),应用场景是BP主动向AP发送AT指令,用于通知AP当前系统发生的与Telephony相关的事件,例如网络信号变化,有电话呼入等。源码中对应的文件是ril_unsol_commands.h。
static UnsolResponseInfo s_unsolResponses[] = { #include "ril_unsol_commands.h" }; typedef struct { int requestNumber; int (*responseFunction) (Parcel &p, void *response, size_t responselen); WakeType wakeType; } UnsolResponseInfo;
面对这上百的s_command元素们,顿觉代码的流程并非难点,难在对每一个s_command的理解。
Ref:hardware\ril\include\telephony\Ril.h
1 {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, 2 {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, 3 {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, 4 {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL}, 5 {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL}, 6 {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL}, 7 {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL}, 8 {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE}, 9 {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL}, 10 {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE}, 11 {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL}, 12 {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL}, 13 {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL}, 14 {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL}, 15 {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL}, 16 {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL}, 17 {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, 18 {RIL_UNSOL_SIM_REFRESH, responseInts, WAKE_PARTIAL}, 19 {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL}, 20 {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL}, 21 {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL}, 22 {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL}, 23 {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, 24 {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL}, 25 {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, 26 {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL}, 27 {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL}, 28 {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL}, 29 {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL}, 30 {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL}, 31 {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL}, 32 {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL}, 33 {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL}, 34 {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, 35 {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL}
打电话,则调用的是:
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
看来dispatchDial才是办实事的好同志,而dispatchDial中最终调用了s_callbacks,即之前通过 RIL_register(funcs),LibRIL 获得 Reference-RIL 的Interface 。
s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);
至此,终于进入了Reference-RIL。
中场休息,做个简单的回顾:
1. 我们构造了RequestInfo,pCI指向了对应的s_commands:
typedef struct RequestInfo { int32_t token; //this is not RIL_Token CommandInfo *pCI; struct RequestInfo *p_next; char cancelled; char local; // responses to local commands do not go back to command process } RequestInfo;
2. CommandInfo中的dispatchFunction最终调用了Reference-RIL提供的接口。
typedef struct { int requestNumber; void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI); int(*responseFunction) (Parcel &p, void *response, size_t responselen); } CommandInfo;
3. RIL_RadioFunctions 便是RIL对Reference-RIL的实现要求。
typedef struct { int version; /* set to RIL_VERSION */ RIL_RequestFunc onRequest; RIL_RadioStateRequest onStateRequest; RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion; } RIL_RadioFunctions;
4. onRequest 根据request号做出对应的处理,也就是ril_commands.h。
/** * RIL_Request Function pointer * * @param request is one of RIL_REQUEST_* * @param data is pointer to data defined for that RIL_REQUEST_* * data is owned by caller, and should not be modified or freed by callee * @param t should be used in subsequent call to RIL_onResponse * @param datalen the length of data * */ typedef void (*RIL_RequestFunc) (int request, void *data, size_t datalen, RIL_Token t);
RIL_RadioFunctions需要实现ril_commands.h中定义的request,当然,不一定全部支持。
OK,继续 dialing...
case RIL_REQUEST_DIAL: requestDial(data, datalen, t);
终于要见到AT的影子:
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*/ } asprintf(&cmd, "ATD%s%s;", p_dial->address, clir); ret = at_send_command(cmd, NULL); free(cmd); /* 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); }
之后的事情便是将AT string通过某种通道发送给BP。至于这个通道的建立,可能是串口也可能是其他,但最终都会表现为一个文件描述符,这就是 rilInit 的事儿了。
以上便是基于Dial的流程浏览,到这一层,重点还是对ril_commands.h, ril_unsol_commands.h的理解,"得此二物者得RIL"!
NEXT, LET'S GO INTO BP.