RIL daemon
RILD
rild.c, ril.cpp, ril_event.cpp,reference-ril.c(),qcril.c(以Qualcomm verdor 提供的qcril.c取代reference_ril.c)以上是相關的.c or .cpp檔
RILD上承RILJ,也就是ril.java,往下是將AT command我們用QMI送給modem
所以簡單來說,RILD的功能就是將RIL request轉成AT command
這個daemon在開機的時候就會init起來,其參數的定義放在init.rc裡面
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
首先,先看rild.c中的main()
RIL_startEventLoop()這個function的實作放在ril.cpp中
RIL_startEventLoop(void) {
....
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
他會create一個thread, 入口是eventLoop(),同樣實作在ril.cpp
static void *
eventLoop(void *param) {
...
ril_event_init();
....
ril_event_loop();
...
}
RILD裡頭有一套event的機制來處理上層送下來的request.
ril_event_init()用來init所需的event queue,總共有三種: timer list, pending list, watch_table
main()中的rilInit(&s_rilEnv, argc, rilArgv)
這個function會參照到reference-ril.c中的RIL_Init()
這裡頭又會create "mainLoop"這個thread
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
看一下mainLoop裡頭做的事情
有一部分的事情是要透過socket跟qemud溝通?? 這一部分還沒看熟
另外
ret = at_open(fd, onUnsolicited);
這個function內部會create "readLoop"這個thread,它用來讀從channel送上來的AT command,並且註冊用來處理unsolicited AT command的function
還有
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0)這個function會將會新增一event,並且填入callback function: initializeCallback(),看一下此callback做的事情
at_send_command("ATE0Q0V1", NULL);
...
/* No auto-answer */
at_send_command("ATS0=0", NULL);
...
/* Extended errors */
at_send_command("AT+CMEE=1", NULL);
...
看樣子是要intialize AT command channel
rilInit()所回傳的pointer是指向s_callbacks,定義在reference-ril.c
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
此pointer接著會被丟到RIL_register(),定義在ril.cpp中
看一下RIL_register()中所做的事情
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
...
ret = listen(s_fdListen, 4);
...
ril_event_set (&s_listen_event, s_fdListen, false,
listenCallback, NULL);
...
rilEventAddWakeup (&s_listen_event);
android_get_control_socket()取得rild socket的file descriptor,這邊的rild也就是之前提到定義在init.rc內的rild
接著,透過ril_event_set()新增一event,填入此rild的fd與callback function
ril_event_set (&s_listen_event, s_fdListen, false,
listenCallback, NULL);
rilEventAddWakeup()會把event放入watch_table裡面
下圖是關於以上說明的簡單示意圖
所以會有3個thread被create出來,mainLoop, readLoop, eventLoop
藍色部分是會被set的RIL event. 到時候會被排入ril event loop中執行
event說明
1. ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
2. ril_event_set (&s_commands_event, s_fdCommand, 1,
processCommandsCallback, p_rs);
for (;;) {
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
// read data from s_fdCommand
...
processCommandBuffer(p_record, recordlen);
// data 在此function裡面會被打包成RequestInfo,也就是pRI
}
看一下processCommandBuffer()內所做的事情,它定義在ril.cpp中
先介紹兩種資料結構,Parcel與RequestInfo
1. Parcel: http://developer.android.com/reference/android/os/Parcel.html
用來放data的容器(資料結構),RILJ要往RILD送的data都會先封裝在Parcel裡面再透過socket傳送
2. RequestInfo:
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;
token: ril request (from RILJ)的sequence number
pCI: callback function for this ril request
typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int(*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;
requestNumber: ril request ID
dipspatchFunction: callback function to handle request
responseFunction: callback function to handle response
首先,拿ril request ID與sequence number出來
status = p.readInt32(&request);
status = p.readInt32 (&token);
將token與查表取得callback function填入
pRI->token = token;
pRI->pCI = &(s_commands[request]);
s_commands內的值定義在ril_commands.h
example:
{RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
{RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
{RIL_REQUEST_DTMF, dispatchString, responseVoid},
接下來便會去執行dispatch function
pRI->pCI->dispatchFunction(p, pRI);
ril request ID: RIL_REQUEST_SEND_SMS
dispatch function: dispatchStrings
response function: responseSMS
進入dispatchStrings後Parcel內的data會被取出,最後會呼叫
s_callbacks.onRequest(pRI->pCI->requestNumber, pStrings, datalen, pRI);
onRequest定義在reference-ril.c,此時就會轉成AT command往modem送
** ril request的interface定義在ril.h中
rild.c, ril.cpp, ril_event.cpp,
RILD上承RILJ,也就是ril.java,往下是將
所以簡單來說,RILD的功能就是將RIL request轉成
這個daemon在開機的時候就會init起來,其參數的定義放在init.rc裡面
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
首先,先看rild.c中的main()
RIL_startEventLoop()這個function的實作放在ril.cpp中
RIL_startEventLoop(void) {
....
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
...
}他會create一個thread, 入口是eventLoop(),同樣實作在ril.cpp
static void *
eventLoop(void *param) {
...
ril_event_init();
....
ril_event_loop();
...
}
RILD裡頭有一套event的機制來處理上層送下來的request.
ril_event_init()用來init所需的event queue,總共有三種: timer list, pending list, watch_table
main()中的rilInit(&s_rilEnv, argc, rilArgv)
這個function會參照到reference-ril.c中的RIL_Init()
這裡頭又會create "mainLoop"這個thread
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
看一下mainLoop裡頭做的事情
有一部分的事情是要透過socket跟qemud溝通?? 這一部分還沒看熟
另外
ret = at_open(fd, onUnsolicited);
這個function內部會create "readLoop"這個thread,它用來讀從channel送上來的AT command,並且註冊用來處理unsolicited AT command的function
還有
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0)這個function會將會新增一event,並且填入callback function: initializeCallback(),看一下此callback做的事情
at_send_command("ATE0Q0V1", NULL);
...
/* No auto-answer */
at_send_command("ATS0=0", NULL);
...
/* Extended errors */
at_send_command("AT+CMEE=1", NULL);
...
看樣子是要intialize AT command channel
rilInit()所回傳的pointer是指向s_callbacks,定義在reference-ril.c
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
此pointer接著會被丟到RIL_register(),定義在ril.cpp中
看一下RIL_register()中所做的事情
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
...
ret = listen(s_fdListen, 4);
...
ril_event_set (&s_listen_event, s_fdListen, false,
listenCallback, NULL);
...
rilEventAddWakeup (&s_listen_event);
android_get_control_socket()取得rild socket的file descriptor,這邊的rild也就是之前提到定義在init.rc內的rild
接著,透過ril_event_set()新增一event,填入此rild的fd與callback function
ril_event_set (&s_listen_event, s_fdListen, false,
listenCallback, NULL);
rilEventAddWakeup()會把event放入watch_table裡面
下圖是關於以上說明的簡單示意圖
所以會有3個thread被create出來,mainLoop, readLoop, eventLoop
藍色部分是會被set的RIL event. 到時候會被排入ril event loop中執行
event說明
1. ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
// accept a connection並且取得new socket的file descriptor,此s_fd_Command接著會被傳入
// s_commands_event裡面,用來read從RIL.java送下來的ril request
ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK);
// 設定s_fdCommand的屬性 (??)
p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
// read data from s_fdCommand
processCommandsCallback, p_rs);
for (;;) {
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
// read data from s_fdCommand
...
processCommandBuffer(p_record, recordlen);
// data 在此function裡面會被打包成RequestInfo,也就是pRI
}
看一下processCommandBuffer()內所做的事情,它定義在ril.cpp中
先介紹兩種資料結構,Parcel與RequestInfo
1. Parcel: http://developer.android.com/reference/android/os/Parcel.html
用來放data的容器(資料結構),RILJ要往RILD送的data都會先封裝在Parcel裡面再透過socket傳送
2. RequestInfo:
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;
token: ril request (from RILJ)的sequence number
pCI: callback function for this ril request
typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int(*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;
requestNumber: ril request ID
dipspatchFunction: callback function to handle request
responseFunction: callback function to handle response
首先,拿ril request ID與sequence number出來
status = p.readInt32(&request);
status = p.readInt32 (&token);
將token與查表取得callback function填入
pRI->token = token;
pRI->pCI = &(s_commands[request]);
s_commands內的值定義在ril_commands.h
example:
{RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
{RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
{RIL_REQUEST_DTMF, dispatchString, responseVoid},
接下來便會去執行dispatch function
pRI->pCI->dispatchFunction(p, pRI);
以send SMS為例
{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS}
ril request ID: RIL_REQUEST_SEND_SMS
dispatch function: dispatchStrings
response function: responseSMS
進入dispatchStrings後Parcel內的data會被取出,最後會呼叫
s_callbacks.onRequest(pRI->pCI->requestNumber, pStrings, datalen, pRI);
onRequest定義在reference-ril.c,此時就會轉成AT command往modem送
** ril request的interface定義在ril.h中