# Android RIL code review 2

2015-03-27

#Overview# In this section, I will discuss the details inside the libril.so, these details include:

• RIL event mechanism.
• Communications with frameworks.
• Supports for vendor RIL.

# RIL event mechanism

As the last section’s show us, it’s clear that RIL_startEventLoop create a thread named eventloop, its code will show below:

It invokes ril_event_init to initialize two ril_event structure objects: timer_list and pending_list:

In the end of this function, it also zeros a ril_event structure pointer array which has 8 elements: watch_table. We will know these objects later on. So let’s check the structure ril_event:

We can see that ril_event is a doubly linked list.

We use ril_event_init to initialize all event tables, including timer_list, pending_list and watch_table, their declarations are like below:

static struct ril_event * watch_table[MAX_FD_EVENTS];
static struct ril_event timer_list;
static struct ril_event pending_list;


We use ril_event_set to fill the ril_event object with input parameters.

The fd maybe the file descriptor of the socket, and set it as non-blocking status via invoking fcntl.

We also use ril_event_add to add the new event to watch_table, and set the fd into fd_set . So, if some data from these fds are available, the callback function from ril_event can be invoked, there is a thread(eventloop) do this thing, we will talk about it later. We also use ril_event_del to remove the specific ril_event object from watch_table. And the function “ril_timer_add”, we can use it to add the event to timer_list, and sort it with time out period’s ascending order.

And now, we will go back to the function “eventloop”. After initializing ril_event tables, there is a pipe defined, then put the read fd and the related informations into a ril-event, and add it to the watch_table, the implementation of the callback function is below:

We can write some data to the write fd of the pipe to wake up the thread, it seems that no reason to do that. But the interesting thing is that every time if there is the new ril_event object will be added, the trigger function “triggerEvLoop” will be invoked. The rilEventAddWakeup detail will show this:

I guess if rilEventAddWakeup will be called in another thread, this invoking will activate the eventloop thread. The triggerEvLoop function will trigger processWakeupCallback function:

## The core part of eventloop

The most important part of eventloop is ril_event_loop, it uses select system call to manage some file descriptors. And it has some details need to analysis.

It’s a dead loop, but it has an error’s return. So let’s start from calcNextTimeout.

We use this function to check if we have pending timers in timer_list. If there is no element in timer_list, the function returns -1, and select system call will block itself indefinitely. We should go inside this function:

If we have the pending timer event, we will compare the first element’s timeout value with the current time (start from system’s booting). If tev->timeout is larger than the current time, the event tev don’t overtime, so set the difference between tev’s timeout value and the current time into tv. vise versa, if tev->timeout is smaller than the current time, we will set zero to tv. So back to ril_event_loop, the select system call can get the timeout value from calcNextTimeout. I think we should know how to get the pending timer, so let’s check the detail of ril_timer_add:

As previous code snippets show us, the timer_list was initialized by init_list in ril_event_init, so if the timer_list has no elements, the timer_list’s next pointer and prev pointer all point to itself. We add the relative time interval to the current time, then set this sum to the new ril_event ev, then find the place that keep the larger one located in the back, so the first one is the oldest event.

After that, we can confirm the timeout value that will be passed into select system call. If the invoking to select has an error, it will break the dead loop, but the error from interrupt is ignored .If some file descriptors’ data are available, the final 3 functions will be invoked:

• processTimeouts.
• firePending

## The final tree kicks

If the data comes, we left three kicks. So let’s dive into the first kick:

It’s simple to interprate: we traverse the time_list to find the event whose timeout is smaller then the current time, in other words, we want to find the timeout event, and remove it from the timer_list, then add to the pending_list.

The second kick:

In this function, we scan watch_table to check if any element is ready for receiving data, then add it to the pending_list. Whether we delete the ready item from watch_table depends on persist value in this item.

The final kick:

And now, the pending_list includes all the events will be ready to read, so we traverse the pending_list, fire all of them, invoking their own callback functions.

# Temporary End

This note is long enough, the left content will be delivered in the following post.

-->