RIL Layer Source Code Analysis

Source: Internet
Author: User
Tags bool socket
write in front


1, this article from the macroscopic point of view to analyze the problem, therefore neglected some non-main line function.
2, similarly, for the function of the non-main logical part, also took the omission.
3, limited by the accumulation of knowledge and understanding of the ability, the text described in the case of improper analysis, we hope to be corrected.
A story starting with the main function



Android's intelligent architecture is the application processor + baseband chip, that is, the Ap+modem mode, AP portion equivalent to Cpu,modem equivalent network card, and each manufacturer using the modem may be different. Each communication protocol, such as GSM/CDMA, is very different, in order to abstract all modems into a unified mode, so Android built a RIL (Radio Interface layer). Under this layer, each vendor can have its own different implementation, but after the RIL layer protocol conversion, all the modems are abstracted to the top of the unified object to be responsible.
RILC and the upper Rilj communication is through the socket transmission data and commands, and the underlying modem signal transmission is through the serial port with at command to achieve.





We begin our analysis from the entrance of Ril.
[CPP] 


@ rild.c
     int main (int argc, char ** argv) {
         // Link library address: /system/lib/libreference-ril.so
         #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
         rilLibPath = REFERENCE_RIL_PATH;
         // Switch UID to AID_RADIO
         switchUser ();
         // Open the link library
         dlHandle = dlopen (rilLibPath, RTLD_NOW);
         // Enable the EventLoop loop
         RIL_startEventLoop ();
         // Find the address of the RIL_Init function from the link library (that is, reference-ril.c)
         rilInit = (const RIL_RadioFunctions * (*) (const struct RIL_Env *, int, char **)) dlsym (dlHandle, "RIL_Init");
         // Call the RIL_Init function in reference-ril.c to initialize the INIT, and get the reference-ril callback function
         funcs = rilInit (& s_rilEnv, argc, rilArgv);
         // Register the reference callback function
         RIL_register (funcs);
     }


As can be seen from the above, the entry function mainly completes 3 functions:
1, open eventloop cycle, complete RIL and RILJ layer data interaction (via socket)
2, open the dynamic Library Reference and build Readerloop cycle, complete RIL and modem layer data interaction (through at)
3. callback function for registered reference

Below we describe the specific process in detail. 



first, the event mechanism
1.1. Event Framework



The event is to loop through the pool of handles added to the EventLoop and handle the current new data if there are new data in the channel represented by any of the handles in the current handle pool. The most important handle in the handle pool is the socket channel between Rilj and RILC.
The implementation of the event is primarily in the Ril_event.cpp file.      

 Let's take a look at the composition of a standard event: [CPP] 


        struct ril_event {
            struct ril_event *next;
            struct ril_event *prev;
            int fd;
            int index;
            bool persist;
            struct timeval timeout;
            ril_event_cb func;
            void *param;
        };


As can be seen from the structure above, the management of event is implemented through a linked list, and some important member variables have the following meanings:


FD: Event-related device handle. The most important is the socket file handle between Rilj and RILC
Persist: Indicates that the current event needs to be persisted and cannot be removed from watch_table
Func: handler function for the current event
Param: Parameters When invoking the current event handler function
Next, before we look at the specific process, let's take a look at what functions are required to process the event:

[CPP] The initialization of the view plain copy//event is actually the initialization   


// Event initialization is actually the initialization of 3 main linked lists
        static void init_list (struct ril_event * list)
        // Add Event to the linked list
        static void addToList (struct ril_event * ev, struct ril_event * list)
        // Remove Event from linked list
        static void removeFromList (struct ril_event * ev)
        // Delete an Event from the watch list
        static void removeWatch (struct ril_event * ev, int index)
        // Handle Timeout Event
        static void processTimeouts ()
        // Initialize the Event list
        void ril_event_init ()
        // Initiate an Event
        void ril_event_set (struct ril_event * ev, int fd, bool persist, ril_event_cb func, void * param)
        // Add an Event to watch_table
        void ril_event_add (struct ril_event * ev)
        // Add an Event to timer_list
        void ril_timer_add (struct ril_event * ev, struct timeval * tv)
        // Delete an Event from watch_table
        void ril_event_del (struct ril_event * ev)
        // Main loop
        void ril_event_loop ()


Through the main function above we can roughly infer that the process of managing an event should be to generate the corresponding event node, and then add the event to the list, after processing the event will need to remove the current event from the linked list. And we see that there should be more than one list in event management, so what are the linked lists running?


RIL has 3 linked list structures in the event management system: Watch_table,timer_list,pending_list, and uses a device handle pool Readfds to save all the file handles to the socket pipeline. The management process can be summarized as the following 6 points:
1, you can add an event to watch_table or timer_list;
2, if the event is added to the watch_table, the current event's FD (event device handle) needs to be added to the Readfds;
3. If the event is added to the timer_list, it is not necessary to add the FD (event device handle) of the current event to the Readfds, and the FD value of the current event is invalid;
4, in the loop detection process, if found in the Watch_table event will add the current event to Pending_list, if the current event persist property is False, indicating that the current node does not need to be preserved, Removes the current event from Watch_table, and if persist is true, it does not need to be removed from watch_table to delete the current node.
5, during the cyclic detection process, if the event in Timer_list is found timeout, move the current event to Pending_list, and delete the node in timer_list.
6, in the process of cyclic detection, such as watch_table and timer_list processing finished, go to pending_list in the execution of the event within the Func point.

With this understanding, let's take a look at the specific process. Start with the creation entry for the event:

[CPP]

@ ril.cpp      RIL_startEventLoop (void) {          // Open the Event thread and call eventLoop to enter the loop          ret = pthread_create (& s_tid_dispatch, & attr, eventLoop, NULL);      }



    Then we go into the thread's entry function to view: 

[CPP] 

eventLoop (void * param) {
         // Event initialization
         ril_event_init ();
         // Create an Event
         ril_event_set (& s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL);
         // Add the Event created above to watch_table, which plays the role of awakening LoopEvent, which will be explained in detail later
         rilEventAddWakeup (& s_wakeupfd_event);
         // enter loop
         ril_event_loop ();
     }




As can be seen, the event is set up by two steps:1, the initialization of the linked list, 2, into the loop loop. Let's take a look at two different processes:
1.2, the construction process of EventLoop
1.2.1, event initialization process. is actually the ril_event_init process.       

[CPP]

 @ril_event.cpp
    void ril_event_init()
    {
        FD_ZERO(&readFds);
        init_list(&timer_list);
        init_list(&pending_list);
        memset(watch_table, 0, sizeof(watch_table));
    }


The initialization process is simple, which is the initialization of the set of file handles and 3 important lists that are involved in the loop framework.

the process of 1.2.2 and event loops 

[CPP] 


eventLoop (void * param) {
         // Event initialization
         ril_event_init ();
         // Create an Event
         ril_event_set (& s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL);
         // Add the Event created above to watch_table, which plays the role of awakening LoopEvent, which will be explained in detail later
         rilEventAddWakeup (& s_wakeupfd_event);
         // enter loop
         ril_event_loop ();
     }



The above for loop can be clearly seen, when the RILJ send the data, in the EventLoop will be timer_list, watch_table, pending_list processing, and then to see the process of the 3 tables separately:
A, timer_list table [CPP] 


eventLoop (void * param) {
         // Event initialization
         ril_event_init ();
         // Create an Event
         ril_event_set (& s_wakeupfd_event, s_fdWakeupRead, true, processWakeupCallback, NULL);
         // Add the Event created above to watch_table, which plays the role of awakening LoopEvent, which will be explained in detail later
         rilEventAddWakeup (& s_wakeupfd_event);
         // enter loop
         ril_event_loop ();
     }


B, watch_table table 

[CPP]

static void processReadReadies (fd_set * rfds, int n)          {              for (int i = 0; (i <MAX_FD_EVENTS) && (n> 0); i ++) {                  // Add to pending_list                  addToList (rev, & pending_list);                  if (rev-> persist == false) {                      // If persist is false, delete the current Event                      removeWatch (rev, i);                  }              }          }


C, pending_list table        

  [CPP]

static void firePending ()
         {
             while (ev! = & pending_list) {
                 // Delete the current node
                 removeFromList (ev);
                 // Execute its func and pass parameters in
                 ev-> func (ev-> fd, 0, ev-> param);
             }
         }


The above loop procedure illustrates that EventLoop is the use of the Select method in Linux in the internal loop to detect all file handles (or pipes) in Readfds, and if new data is found to come in, go through the watch_table and timer_list tables, Add the eventloop that need to be processed to the pending_list and enter the Pending_list to execute the func of each event.






The process of receiving data in the loop is mentioned above, so what is the process of handling these commands in detail? This process will be explained after we understand the reference process.



Again, the data detected here is primarily the command sent down by Rilj (not the AT command on the modem side).

second. loading of reference library


In this step, Ril needs to load an at-related ***ril.so dynamic-link library. The use of the library form, is to consider that each manufacturer uses different modems, we can not use a unified interface to the bottom of the responsibility, so use the form of libraries. In this way, different modem manufacturers to provide a different link library, as long as the RIL layer of the framework can be met. The main thing in the current link library is the REFERENCE-RIL.C and atchannel.c files.
The reference library needs to accomplish two tasks:
1, the EventLoop in the command through at the send to the modem;
2. Build a Readerloop loop, accept the modem message, and return the message to EventLoop (non-URC message) depending on the message (URC and non-URC) or send it directly to Rilj (URC message).
Let's look at the Readerloop build process (the process of sending an at is described in the last chapter of the document):
2.1. Readerloop establishment and circulation process in reference

In this step, you need to complete the initialization of the reference and open the Readerloop loop.

[CPP] 


@ reference-ril.c
     const RIL_RadioFunctions * RIL_Init (const struct RIL_Env * env, int argc, char ** argv)
     {
         // Enable the thread of ril, and the entry function is mainLoop
         ret = pthread_create (& s_tid_mainloop, & attr, mainLoop, NULL);
         // Return the ril callback function
         return & s_callbacks;
     }


    Let's look at the entry function:

  [CPP] 

static void * mainLoop (void * param)
     {
         // Initialize the closing method and timeout method of the AT channel
         at_set_on_reader_closed (onATReaderClosed);
         at_set_on_timeout (onATTimeout);
         for (;;) {
             // Open AT and pass inUnsolicited method to process URC messages
             ret = at_open (fd, onUnsolicited);
             RIL_requestTimedCallback (initializeCallback, NULL, & TIMEVAL_0);
             waitForClose ();
         }
     }


As you can see above, not only the at channel is opened, but also the timeout method is set. The current thread, after opening the at channel, blocks the wait in Waitforclose, if the at channel is actively shutting down the current at channel after the detection timeout, the blocking thread in the waitforclose will be activated and Waitforclose will return. Once the Waitforclose function returns, it will enter the for loop again and reopen the at channel.



We mainly track the opening process of the at channel, as well as the processing flow of the event: 

[CPP]

view plain copy @atchannel. c int at_open (int fd, Atunsolhandler h) {/ /URC Message Handling: onunsolicited () @reference-R

@ atchannel.c
     int at_open (int fd, ATUnsolHandler h)
     {
         // URC message processing method: onUnsolicited () @ reference-ril.c
         s_fd = fd;
         // Create a thread to read the AT command and process the information sent by the Modem
         ret = pthread_create (& s_tid_reader, & attr, readerLoop, & attr);
     }



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.