歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android 打電話 RIL 中的事件監聽

Android 打電話 RIL 中的事件監聽

日期:2017/3/1 10:51:30   编辑:Linux編程

在Android 的ril.cpp中文名可以看到關乎RIL初始化流程第一個--建立基於event隊列的消息循環,可以接受上層發來的的請求。

該流程的主要函數RIL_startEventLoop().

該函數主要創建一個以eventlopp為入口的dispatch線程。下面是該函數的代碼:

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);

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

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;

}

}

pthread_mutex_lock(&s_startupMutex)與pthread_mutex_unlock(&s_startupMutex)之間是線程的創建,加鎖與解鎖是為了多線程的沖突。

pthread_attr_init (&attr)與 pthread_create()為線程的創建,在創建時 pthread庫會自動地為線程設定棧大小,我們通常不用明顯地指定。當發生了內存分配不足時,就必須我們自已動手來指定棧大小。這裡我們可以看到eventLoop的入口。

在創建之前初始化線程,我們可以利用pthread_attr_getstacksize來得到默認分配大小,注意到必須先調用pthread_attr_init初始化函數,才能得到正確的值,否則得到的值是不正確的。 其中用pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)來使線程達到detach狀態。

這裡就是dispatch線程的創建過程。

開始分析Android源代碼中的RIL部分。

又上圖,以及其他相關資料,我得知在Android中有一個叫rild的守護進程。我猜測此進程與電話的撥打接聽有莫大關系。

而且在Android系統中存在這麼一個rild的可執行文件,源代碼中的"hardware/ril/rild"目錄下有rild.c的文件 ,且在rild.c中,我們找到了main函數,即我們已經找到了rild守護進程的程序入口啦~

自贊一個先~

開始分析rild守護進程的代碼。

在代碼開始部分,有一些關於參數解析的片段,暫時先撇開一邊,先講一下rild守護進程的關於RIL的一些重要流程:

main()

{//省略n行

RIL_startEventLoop();

//省略n行

}

從名字上看就應該覺得這應該是一個起點——"startEventLoop"——一個開始進入時間循環的一點,讓我們跟蹤進去看看^_^

在"rild.c"中有這麼一行:extern void RIL_startEventLoop();

說明RIL_startEventLoop函數的代碼還在別處,經查找,發現是在這裡:

"hardware\ril\libril"目錄下的Ril.cpp文件中。

Get it~

在Ril.cpp中的RIL_startEventLoop中有這麼一行:

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

看來Android是在這裡開辟一個線程來執行eventLoop循環,

這個eventLoop函數也在這個文件裡(Ril.cpp)。

eventLoop中,主要執行了:
ril_event_init();
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);

ril_event_add (&s_wakeupfd_event);

ril_event_loop();

由函數名可猜測:

ril_event_set使用了新建一個ril事件的,

而ril_event_add 將該新事件添加進某執行隊列中。

最後,在循環ril_event_loop中進行一個輪詢,捕獲事件,進而完成事件處理。

經過對ril_event_set和ril_event_add的代碼閱讀,證實了之前的兩點猜測,

(ril_event_set和ril_event_add以及ril_event_loop函數代碼在"hardware\ril\libril"目錄下的ril_event.cpp中)

新事件加入了一個叫watch_table的數組中。

而 ril_event_loop則調用了一個select函數,目前還在分析該函數中~~(猜測是unix類系統的系統調用,暫時先放過)

重新從eventloop的流程開始分析起:
首先,是那個ril_event_init函數。ril_event_init函數在Ril_event.cpp("hardware\ril\libril"),Ril_event.cpp中有一個timer_list的ril_event結構體,這個結構體充當待處理的事件隊列(I guest)

而ril_event_init就是在做事件隊列的初始化工作(通過init_list(&timer_list),當然還有另外還初始化了pending_list)

然後,就是ril_event_set一個事件結構s_wakeupfd_event

接著,就是ril_event_add該s_wakeupfd_event結構體添加到Ril_event.cpp的watch_table數組中。

最後就是執行ril_event_loop循環了。

請注意,以上步驟中並沒有將事件添加到事件隊列(timer_list)中的部分,但是ril_event_loop的運作就是要基於timer_list的,那事件隊列不是空的嗎?怎麼會這樣呢?

在查看了相關代碼之後,發現了有一個叫ril_timer_add的函數執行了addToList函數,即猜測應該是某個函數調用了ril_timer_add?是什麼函數呢?通過用Source Insight查找函數的caller,發現了internalRequestTimedCallback函數調用了ril_timer_add。從名字我想起了關鍵一點:當前流程只是用來“處理”電話事件而已,並不是自己生成一個電話事件啊,電話事件應該是由此流程外的對象生成的(比如有來電了,又如要打電話了),用中斷來進行事件隊列的事件添加。

到此為止,我們已經確認了rild的主要監聽功能就是在ril_event_loop中:

其中在ril_event_loop的for (;;)循環中,我們看到了if (-1 == calcNextTimeout(&tv)),這裡就是在嘗試處理電話事件啦^_^。

Copyright © Linux教程網 All Rights Reserved