Android8.0 Rild守護程序
電話是一種開放的通訊渠道,任何人都可以隨時向任何電話號碼致電或者傳送簡訊,因此 Android 使用者需要能夠輕鬆遮蔽騷擾電話和簡訊。在 Android N 推出之前,Android 使用者只能依靠下載的應用來限制來自騷擾電話號碼的來電和簡訊。但是,由於沒有適當的 API 來遮蔽來電和簡訊,這些應用大部分要麼達不到預期效果,要麼使用者體驗不佳。
一些製造商可能會提供他們自己的開箱即用型遮蔽解決方案,但是如果使用者更換裝置,由於缺乏互用性,他們的遮蔽列表可能會完全丟失。最後,即便使用者採用了提供此類功能的撥號應用和簡訊客戶端,他們可能仍需在每個應用中執行遮蔽操作,才能有效遮蔽來電和簡訊。Android 7.0 版本引入了 BlockedNumberProvider 內容提供程式,該程式可以儲存使用者指定的無法通過電話通訊(通話、簡訊、彩信)與他們聯絡的電話號碼列表。系統會參考遮蔽列表中的號碼,限制來自這些號碼的來電和簡訊。Android 7.0 不僅會顯示遮蔽號碼列表,還可讓使用者新增和刪除號碼。
1. 啟動Rild後臺程序
hardware\ril\rild\rild.c
int main(int argc, char **argv) {
// vendor ril lib path either passed in as -l parameter, or read from rild.libpath property
const char *rilLibPath = NULL;
// ril arguments either passed in as -- parameter, or read from rild.libargs property
char **rilArgv;
//廠商ril庫控制代碼
void *dlHandle;
//廠商ril庫回撥
const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
// Pointer to sap init function in vendor ril
RIL_RadioFunctions *(*rilUimInit)(const struct RIL_Env *, int, char **);
const char *err_str = NULL;
// functions returned by ril init function in vendor ril
const RIL_RadioFunctions *funcs;
......
//打開廠商庫
dlHandle = dlopen(rilLibPath, RTLD_NOW);
//啟動事件迴圈
RIL_startEventLoop();
//呼叫系統庫
rilInit =(const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
rilUimInit =(RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_SAP_Init");
//初始化rilInit
funcs = rilInit(&s_rilEnv, argc, rilArgv);
//註冊回撥函式
RIL_register(funcs);
//註冊套接
if (rilUimInit) {
RIL_register_socket(rilUimInit, RIL_SAP_SOCKET, argc, rilArgv);
}
done:
.....
rilc_thread_pool();
.....
}
2. 啟動事件迴圈
hardware\ril\libril\ril.cpp
extern "C" void
RIL_startEventLoop(void) {
......
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//啟動執行緒,執行 eventLoop
int result = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}
......
hardware\ril\libril\ril.cpp
static void *
eventLoop(void *param) {
int ret;
int filedes[2];
//初始化事件連結串列
ril_event_init();
//建立管道
ret = pipe(filedes);
//讀寫喚醒描述符
s_fdWakeupRead = filedes[0];
s_fdWakeupWrite = filedes[1];
//執行
fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
//設定事件描述符和事件處理函式
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);
rilEventAddWakeup (&s_wakeupfd_event);
//開始ril事件迴圈
ril_event_loop();
......
return NULL;
}
hardware\ril\libril\ril_event.cpp
void ril_event_init()
{
MUTEX_INIT();
FD_ZERO(&readFds);
init_list(&timer_list); //初始化事件連結串列
init_list(&pending_list);
memset(watch_table, 0, sizeof(watch_table));
}
static void init_list(struct ril_event * list)
{
memset(list, 0, sizeof(struct ril_event));
list->next = list;
list->prev = list;
list->fd = -1; //儲存檔案描述符
}
hardware\ril\libril\ril_event.cpp
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
for (;;) {
......
n = select(nfds, &rfds, NULL, NULL, ptv); //開始select
......
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
}
}
static void processReadReadies(fd_set * rfds, int 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); //新增到掛起列表
if (rev->persist == false) {
removeWatch(rev, i); //從描述符觀察表中移除
}
n--;
}
}
}
static void 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); //執行函式 processWakeupCallback
ev = next;
}
}
hardware\ril\libril\ril.cpp
static void processWakeupCallback(int fd, short flags, void *param) {
char buff[16];
int ret;
//迴圈從套接端讀取
do {
ret = read(s_fdWakeupRead, &buff, sizeof(buff));
} while (ret > 0 || (ret < 0 && errno == EINTR));
}
hardware\ril\libril\ril.cpp
static void rilEventAddWakeup(struct ril_event *ev) {
ril_event_add(ev);
triggerEvLoop();
}
hardware\ril\libril\ril_event.cpp
void ril_event_add(struct ril_event * ev)
{
for (int i = 0; i < MAX_FD_EVENTS; i++) {
if (watch_table[i] == NULL) {
watch_table[i] = ev; //加入事件觀察表中
ev->index = i; //加索引
FD_SET(ev->fd, &readFds);
if (ev->fd >= nfds) nfds = ev->fd+1;
break;
}
}
}
hardware\ril\libril\ril.cpp
static void triggerEvLoop() {
int ret;
if (!pthread_equal(pthread_self(), s_tid_dispatch)) {
//迴圈觸發喚醒事件迴圈
do {
ret = write (s_fdWakeupWrite, " ", 1);
} while (ret < 0 && errno == EINTR);
}
}
3. 啟動RIL庫
hardware\ril\reference-ril\reference-ril.c
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
......
//啟動執行緒,開始主迴圈
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
......
return &s_callbacks; //返回操作結構體
}
//函式回撥結構表
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
hardware\ril\reference-ril\reference-ril.c
開始開啟BP(基帶處理器)
static void *
mainLoop(void *param __unused)
{
int fd;
int ret;
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for (;;) {
fd = -1;
while (fd < 0) {
if (isInEmulator()) {
fd = qemu_pipe_open("pipe:qemud:gsm"); //模擬
} else if (s_port > 0) {
fd = socket_network_client("localhost", s_port, SOCK_STREAM); //網路
} else if (s_device_socket) { //本地
fd = socket_local_client(s_device_path,
ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
SOCK_STREAM);
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR); //開啟基帶處理器
if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
/* disable echo on serial ports */
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd, TCSANOW, &ios );
}
}
......
}
s_closed = 0;
ret = at_open(fd, onUnsolicited); // 開始基帶處理通訊,出入檔案描述符,回撥處理函式
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
......
}
}
4. 未經請求的AT通訊
hardware\ril\reference-ril\atchannel.c
int at_open(int fd, ATUnsolHandler h)
{
int ret;
pthread_t tid;
pthread_attr_t attr;
s_fd = fd;
s_unsolHandler = h; //回撥處理控制代碼
s_readerClosed = 0;
//開執行緒迴圈讀取
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
......
return 0;
}
hardware\ril\reference-ril\atchannel.c
迴圈讀取基帶處理器的AT指令
static void *readerLoop(void *arg __unused)
{
for (;;) {
const char * line;
line = readline(); //讀取AT命令
if (line == NULL) {
break;
}
if(isSMSUnsolicited(line)) { //是未經請求的回覆
char *line1;
const char *line2;
// The scope of string returned by 'readline()' is valid only
// till next call to 'readline()' hence making a copy of line
// before calling readline again.
line1 = strdup(line);
line2 = readline();
if (line2 == NULL) {
free(line1);
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2); //回撥
}
free(line1);
} else {
processLine(line); //處理
}
}
onReaderClosed();
return NULL;
}
hardware\ril\reference-ril\atchannel.c
讀取AT命令列
static const char *readline()
{
ssize_t count;
char *p_read = NULL;
char *p_eol = NULL;
char *ret;
/* this is a little odd. I use *s_ATBufferCur == 0 to
* mean "buffer consumed completely". If it points to a character, than
* the buffer continues until a \0
*/
if (*s_ATBufferCur == '\0') {
/* empty buffer */
s_ATBufferCur = s_ATBuffer;
*s_ATBufferCur = '\0';
p_read = s_ATBuffer;
} else { /* *s_ATBufferCur != '\0' */
/* there's data in the buffer from the last read */
// skip over leading newlines
while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
s_ATBufferCur++;
p_eol = findNextEOL(s_ATBufferCur);
if (p_eol == NULL) {
/* a partial line. move it up and prepare to read more */
size_t len;
len = strlen(s_ATBufferCur);
memmove(s_ATBuffer, s_ATBufferCur, len + 1);
p_read = s_ATBuffer + len;
s_ATBufferCur = s_ATBuffer;
}
/* Otherwise, (p_eol !- NULL) there is a complete line */
/* that will be returned the while () loop below */
}
while (p_eol == NULL) {
if (0 == MAX_AT_RESPONSE - (p_read - s_ATBuffer)) {
RLOGE("ERROR: Input line exceeded buffer\n");
/* ditch buffer and start over again */
s_ATBufferCur = s_ATBuffer;
*s_ATBufferCur = '\0';
p_read = s_ATBuffer;
}
do {
//迴圈讀取AT指令資料
count = read(s_fd, p_read,
MAX_AT_RESPONSE - (p_read - s_ATBuffer));
} while (count < 0 && errno == EINTR);
if (count > 0) {
AT_DUMP( "<< ", p_read, count );
p_read[count] = '\0';
// skip over leading newlines
while (*s_ATBufferCur == '\r' || *s_ATBufferCur == '\n')
s_ATBufferCur++;
p_eol = findNextEOL(s_ATBufferCur);
p_read += count;
} else if (count <= 0) {
/* read error encountered or EOF reached */
if(count == 0) {
RLOGD("atchannel: EOF reached");
} else {
RLOGD("atchannel: read error %s", strerror(errno));
}
return NULL;
}
}
/* a full line in the buffer. Place a \0 over the \r and return */
ret = s_ATBufferCur;
*p_eol = '\0';
s_ATBufferCur = p_eol + 1; /* this will always be <= p_read, */
/* and there will be a \0 at *p_read */
RLOGD("AT< %s\n", ret);
return ret;
}
hardware\ril\reference-ril\atchannel.c
處理命令列
static void processLine(const char *line)
{
pthread_mutex_lock(&s_commandmutex);
if (sp_response == NULL) {
/* no command pending */
handleUnsolicited