Android源碼目錄hardware/ril/libril目錄中總共包含5個C/CPP檔案,它們分別是ril_commands.h、ril_unsol_commands.h、ril_event.h、ril_event.cpp和ril.cpp。這篇文章主要分析ril_event的相關代碼。
ril_event主要處理電話模組涉及的連接埠、modem等產生的事件,並將多個事件按時間順序進行組織,並儲存在事件隊別中,主要使用了三個隊列,分別是:watch_table[],timer_list和pending_list。代碼是以C語言方式實現的,先來看標頭檔ril_event.h:
// 每次監視的最大的檔案描述項控制代碼數,可以根據需要自行修改<br />#define MAX_FD_EVENTS 8</p><p>// ril_event的回呼函數<br />typedef void (*ril_event_cb)(int fd, short events, void *userdata);</p><p>struct ril_event {<br />// 用於將ril_event串成雙向鏈表的前向指標和後向指標<br /> struct ril_event *next;<br />struct ril_event *prev;</p><p>//ril事件相關的檔案描述項控制代碼(可以是檔案、管道、Socket等)<br />int fd;</p><p>//這個事件在監控列表中的索引<br />int index;</p><p>//當一個事件處理完後(即從watch_table移到pending_list中等待處理),<br />//persist參數決定這個事件是否一直存在於監控列表watch_table[]中<br />bool persist;</p><p>//事件的逾時時間<br />struct timeval timeout;</p><p>//回呼函數及其傳入的參數<br /> ril_event_cb func;<br /> void *param;<br />};</p><p>//以下是ril事件相關的一些操作函數<br />// 初始化內部資料結構<br />void ril_event_init();</p><p>// 初始化一個ril事件<br />void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param);</p><p>// 將事件添加到監控列表watch_table[]中<br />void ril_event_add(struct ril_event * ev);</p><p>// 增加一個timer事件到timer_list鏈表中<br />void ril_timer_add(struct ril_event * ev, struct timeval * tv);</p><p>// 將指定的事件從監控列表watch_table[]中移除<br />void ril_event_del(struct ril_event * ev);</p><p>// 事件迴圈<br />void ril_event_loop();
接著分析ril_event .cpp檔案:
#define LOG_TAG "RILC"</p><p>#include <stdlib.h><br />#include <unistd.h><br />#include <errno.h><br />#include <fcntl.h><br />#include <utils/Log.h><br />#include <ril_event.h><br />#include <string.h><br />#include <sys/time.h><br />#include <time.h></p><p>#include <pthread.h></p><p>// 使用互斥量mutex進行線程同步,可參見《Linux程式設計》相關章節<br />static pthread_mutex_t listMutex;<br />#define MUTEX_ACQUIRE() pthread_mutex_lock(&listMutex)<br />#define MUTEX_RELEASE() pthread_mutex_unlock(&listMutex)<br />#define MUTEX_INIT() pthread_mutex_init(&listMutex, NULL)<br />#define MUTEX_DESTROY() pthread_mutex_destroy(&listMutex)</p><p>// 兩個timeval類型的值相加<br />#ifndef timeradd<br />#define timeradd(tvp, uvp, vvp)\<br />do {\<br />(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;\<br />(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \<br />if ((vvp)->tv_usec >= 1000000) {\<br />(vvp)->tv_sec++;\<br />(vvp)->tv_usec -= 1000000;\<br />}\<br />} while (0)<br />#endif</p><p>// 兩個timeval類型的值進行比較<br />#ifndef timercmp<br />#define timercmp(a, b, op) \<br /> ((a)->tv_sec == (b)->tv_sec \<br /> ? (a)->tv_usec op (b)->tv_usec \<br /> : (a)->tv_sec op (b)->tv_sec)<br />#endif</p><p>// 兩個timeval類型的值相減<br />#ifndef timersub<br />#define timersub(a, b, res) \<br /> do { \<br /> (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \<br /> (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \<br /> if ((res)->tv_usec < 0) { \<br /> (res)->tv_usec += 1000000; \<br /> (res)->tv_sec -= 1; \<br /> } \<br /> } while(0);<br />#endi</p><p>// 儲存Rild中所有裝置檔案控制代碼,便於使用select函數完成事件的監聽<br />static fd_set readFds;<br />// 記錄readFds中最大fd值+1<br />static int nfds = 0;</p><p>// 為了統一管理ril事件,Android提供如下三個隊列:<br />// 監控事件列表,需要檢測的事件都需要先存入該列表中<br />static struct ril_event * watch_table[MAX_FD_EVENTS];</p><p>// timer事件隊列,事件逾時後即移入pending_list隊列中<br />static struct ril_event timer_list;</p><p>// 待處理的事件隊列,即事件已經觸發,後續需要呼叫事件的回呼函數<br />static struct ril_event pending_list;</p><p>#define DEBUG 0</p><p>#if DEBUG<br />#define dlog(x...) LOGD( x )<br />static void dump_event(struct ril_event * ev)<br />{<br /> dlog("~~~~ Event %x ~~~~", (unsigned int)ev);<br /> dlog(" next = %x", (unsigned int)ev->next);<br /> dlog(" prev = %x", (unsigned int)ev->prev);<br /> dlog(" fd = %d", ev->fd);<br /> dlog(" pers = %d", ev->persist);<br /> dlog(" timeout = %ds + %dus", (int)ev->timeout.tv_sec, (int)ev->timeout.tv_usec);<br /> dlog(" func = %x", (unsigned int)ev->func);<br /> dlog(" param = %x", (unsigned int)ev->param);<br /> dlog("~~~~~~~~~~~~~~~~~~");<br />}<br />#else<br />#define dlog(x...) do {} while(0)<br />#define dump_event(x) do {} while(0)<br />#endif</p><p>// 擷取此刻timeval值<br />static void getNow(struct timeval * tv)<br />{<br />#ifdef HAVE_POSIX_CLOCKS<br /> struct timespec ts;<br /> clock_gettime(CLOCK_MONOTONIC, &ts);<br /> tv->tv_sec = ts.tv_sec;<br /> tv->tv_usec = ts.tv_nsec/1000;<br />#else<br /> gettimeofday(tv, NULL);<br />#endif<br />}</p><p>// 初始化指定的ril_event鏈表<br />static void init_list(struct ril_event * list)<br />{<br /> memset(list, 0, sizeof(struct ril_event));<br /> list->next = list;<br /> list->prev = list;<br /> list->fd = -1;<br />}</p><p>// 增加一個ril_event事件到ril_event隊列頭<br />static void addToList(struct ril_event * ev, struct ril_event * list)<br />{<br /> ev->next = list;<br /> ev->prev = list->prev;<br /> ev->prev->next = ev;<br /> list->prev = ev;<br /> dump_event(ev);<br />}</p><p>// 從ril_event隊列中移除指定的ril_event<br />static void removeFromList(struct ril_event * ev)<br />{<br /> dlog("~~~~ Removing event ~~~~");<br /> dump_event(ev);</p><p> ev->next->prev = ev->prev;<br /> ev->prev->next = ev->next;<br /> ev->next = NULL;<br /> ev->prev = NULL;<br />}</p><p>// 從watch_table[]中移除指定索引的事件<br />static void removeWatch(struct ril_event * ev, int index)<br />{<br />// 索引index對應的事件置為空白,同時事件ev的索引設為無效值-1<br /> watch_table[index] = NULL;<br /> ev->index = -1;</p><p>// 將該事件對應的檔案描述項控制代碼從readFds中清除<br /> FD_CLR(ev->fd, &readFds);</p><p> if (ev->fd+1 == nfds) {<br /> int n = 0;</p><p> for (int i = 0; i < MAX_FD_EVENTS; i++) {<br /> struct ril_event * rev = watch_table[i];</p><p> if ((rev != NULL) && (rev->fd > n)) {<br /> n = rev->fd;<br /> }<br /> }<br /> nfds = n + 1;<br /> dlog("~~~~ nfds = %d ~~~~", nfds);<br /> }<br />}</p><p>// 遍曆timer_list隊列中的事件,當事件逾時時間到時<br />// 將事件移除,並添加到pending_list隊列中<br />static void processTimeouts()<br />{<br /> dlog("~~~~ +processTimeouts ~~~~");<br /> MUTEX_ACQUIRE();<br /> struct timeval now;<br /> struct ril_event * tev = timer_list.next;<br /> struct ril_event * next;</p><p> getNow(&now);<br /> // walk list, see if now >= ev->timeout for any events</p><p> dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);<br /> while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {<br /> // Timer expired<br /> dlog("~~~~ firing timer ~~~~");<br /> next = tev->next;<br /> removeFromList(tev);<br /> addToList(tev, &pending_list);<br /> tev = next;<br /> }<br /> MUTEX_RELEASE();<br /> dlog("~~~~ -processTimeouts ~~~~");<br />}</p><p>// 遍曆監控列表watch_table[]中的事件,並將有資料可讀的事件<br />// 添加到pending_list鏈表中,同時如果事件的persist不為true<br />// 則將該事件從watch_table[]中移除<br />static void processReadReadies(fd_set * rfds, int n)<br />{<br /> dlog("~~~~ +processReadReadies (%d) ~~~~", n);<br /> MUTEX_ACQUIRE();</p><p> for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {<br /> struct ril_event * rev = watch_table[i];<br /> if (rev != NULL && FD_ISSET(rev->fd, rfds)) {<br /> addToList(rev, &pending_list);<br /> if (rev->persist == false) {<br /> removeWatch(rev, i);<br /> }<br /> n--;<br /> }<br /> }</p><p> MUTEX_RELEASE();<br /> dlog("~~~~ -processReadReadies (%d) ~~~~", n);<br />}</p><p>// 依次調用待處理隊列pending_list中的事件的回呼函數<br />static void firePending()<br />{<br /> dlog("~~~~ +firePending ~~~~");<br /> struct ril_event * ev = pending_list.next;<br /> while (ev != &pending_list) {<br /> struct ril_event * next = ev->next;<br /> removeFromList(ev);<br /> ev->func(ev->fd, 0, ev->param);<br /> ev = next;<br /> }<br /> dlog("~~~~ -firePending ~~~~");<br />}</p><p>// 計算timer_list鏈表中下一個事件的新的逾時時間<br />static int calcNextTimeout(struct timeval * tv)<br />{<br /> struct ril_event * tev = timer_list.next;<br /> struct timeval now;</p><p> getNow(&now);</p><p> // Sorted list, so calc based on first node<br /> if (tev == &timer_list) {<br /> // no pending timers<br /> return -1;<br /> }</p><p> dlog("~~~~ now = %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);<br /> dlog("~~~~ next = %ds + %dus ~~~~",<br /> (int)tev->timeout.tv_sec, (int)tev->timeout.tv_usec);<br /> if (timercmp(&tev->timeout, &now, >)) {<br /> timersub(&tev->timeout, &now, tv);<br /> } else {<br /> // timer already expired.<br /> tv->tv_sec = tv->tv_usec = 0;<br /> }<br /> return 0;<br />}</p><p>// 初始化內部資料結構(互斥量、FD集合、三個事件隊列)<br />void ril_event_init()<br />{<br /> MUTEX_INIT();</p><p> FD_ZERO(&readFds);<br /> init_list(&timer_list);<br /> init_list(&pending_list);<br /> memset(watch_table, 0, sizeof(watch_table));<br />}</p><p>// 初始化一個ril事件<br />void ril_event_set(struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)<br />{<br /> dlog("~~~~ ril_event_set %x ~~~~", (unsigned int)ev);<br /> memset(ev, 0, sizeof(struct ril_event));<br /> ev->fd = fd;<br /> ev->index = -1;<br /> ev->persist = persist;<br /> ev->func = func;<br />ev->param = param;</p><p>//linux的檔案上鎖函數,給檔案描述符fd上非阻塞的檔案鎖<br /> fcntl(fd, F_SETFL, O_NONBLOCK);<br />}</p><p>// 將事件添加到監控列表watch_table[]中<br />void ril_event_add(struct ril_event * ev)<br />{<br /> dlog("~~~~ +ril_event_add ~~~~");<br /> MUTEX_ACQUIRE();<br /> for (int i = 0; i < MAX_FD_EVENTS; i++) {<br /> if (watch_table[i] == NULL) {<br /> watch_table[i] = ev;<br /> ev->index = i;<br /> dlog("~~~~ added at %d ~~~~", i);<br /> dump_event(ev);<br /> FD_SET(ev->fd, &readFds);<br /> if (ev->fd >= nfds) nfds = ev->fd+1;<br /> dlog("~~~~ nfds = %d ~~~~", nfds);<br /> break;<br /> }<br /> }<br /> MUTEX_RELEASE();<br /> dlog("~~~~ -ril_event_add ~~~~");<br />}</p><p>// 增加一個timer事件到timer_list鏈表中<br />void ril_timer_add(struct ril_event * ev, struct timeval * tv)<br />{<br /> dlog("~~~~ +ril_timer_add ~~~~");<br /> MUTEX_ACQUIRE();</p><p> struct ril_event * list;<br /> if (tv != NULL) {<br /> // add to timer list<br /> list = timer_list.next;<br /> ev->fd = -1; // make sure fd is invalid</p><p> struct timeval now;<br /> getNow(&now);<br /> timeradd(&now, tv, &ev->timeout);</p><p> // 根據timeout值從小到大在鏈表中排序<br /> while (timercmp(&list->timeout, &ev->timeout, < )<br /> && (list != &timer_list)) {<br /> list = list->next;<br /> }<br /> // 迴圈結束後,list指向鏈表中第一個timeout值大於ev的事件<br />// 將新加入的事件ev加到list此刻指向的事件前面<br /> addToList(ev, list);<br /> }</p><p> MUTEX_RELEASE();<br /> dlog("~~~~ -ril_timer_add ~~~~");<br />}</p><p>// 將事件從watch_table[]中移除<br />void ril_event_del(struct ril_event * ev)<br />{<br /> dlog("~~~~ +ril_event_del ~~~~");<br /> MUTEX_ACQUIRE();</p><p> if (ev->index < 0 || ev->index >= MAX_FD_EVENTS) {<br /> MUTEX_RELEASE();<br /> return;<br /> }</p><p> removeWatch(ev, ev->index);</p><p> MUTEX_RELEASE();<br /> dlog("~~~~ -ril_event_del ~~~~");<br />}</p><p>#if DEBUG<br />// 列印監控列表中可用的事件<br />static void printReadies(fd_set * rfds)<br />{<br /> for (int i = 0; (i < MAX_FD_EVENTS); i++) {<br /> struct ril_event * rev = watch_table[i];<br /> if (rev != NULL && FD_ISSET(rev->fd, rfds)) {<br /> dlog("DON: fd=%d is ready", rev->fd);<br /> }<br /> }<br />}<br />#else<br />#define printReadies(rfds) do {} while(0)<br />#endif</p><p>void ril_event_loop()<br />{<br /> int n;<br /> fd_set rfds;<br /> struct timeval tv;<br /> struct timeval * ptv;</p><p> for (;;) {<br /> // make local copy of read fd_set<br /> memcpy(&rfds, &readFds, sizeof(fd_set));<br />// 根據timer_list來計算select函數的等待時間<br />// timer_list之前已按事件的逾時時間排好序了<br /> if (-1 == calcNextTimeout(&tv)) {<br /> // no pending timers; block indefinitely<br /> dlog("~~~~ no timers; blocking indefinitely ~~~~");<br /> ptv = NULL;<br /> } else {<br /> dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);<br /> ptv = &tv;<br /> }<br /> printReadies(&rfds);<br />// 使用select函數實現多路IO複用<br /> n = select(nfds, &rfds, NULL, NULL, ptv);<br /> printReadies(&rfds);<br /> dlog("~~~~ %d events fired ~~~~", n);<br /> if (n < 0) {<br /> if (errno == EINTR) continue;</p><p> LOGE("ril_event: select error (%d)", errno);<br /> // bail?<br /> return;<br /> }</p><p> // Check for timeouts<br /> processTimeouts();<br /> // Check for read-ready<br /> processReadReadies(&rfds, n);<br /> // Fire away<br /> firePending();<br /> }<br />}