Android 源码开发系列(三) Android RIL(Radio Interface Layer)

原创 2012年03月25日 18:20:17

1. RIL(Radio Interface Layer) Architecture

RIL is short name for Radio Interface Layer. The ril is divided into three rild, libril, reference-ril. Rild is a executable file,it can be run in linux, and call by init.rc script to run the rild. RIL sourcecode is under the directory as following:root/hardril/ril. The followingpicture show the position of RIL and function for other application.


Picture 1 RIL Architecture


In the picture, there is some information need to show. Vendor ril may be implementedby MODEM manufactory.They may use thefollowing method to implement.

a) Using AT command, this means that the commandshould be sent via COM or UART. So the command may sent by tty device. Thisimplementation recommend by GOOGLE, so in the Android source code, the ril isimplemented by this way.

b) Using message queue, this depending on themanufactory, they will develop their own method to handle the message. Butanyway, they may use the process communication, such as share memory(MemoryMapping), IO pipe(A pipe connect the AP and MODEM). This method need moredeveloping time due to we can not use the modem supporting AT command.(Themodem are supported the AT commands in 3GPP 27.007, the protocols is standardizedby 3GPP). The following, we will descript the ril boot using AT command method.

2. RILProgress of Booting up

The rildis executed by script init.rc. You can find the script in the directory/system/core/rootdir/init.rc. When you open the script and search the key words“rild”, you can findthe following code.


service ril-daemon /system/bin/rild
    class main
    socket rild stream 660 root radio
    socket rild-debug stream 660 radio system
    user root
    group radio cache inet misc audio sdcard_rw log

So the rildwill be compile as an executable program and run by linux system. Now we wantto descript the RILD work.

a)   Parameters work.

In this work, itwant to check the parameters assigned by running the command rild. It may usetty mode or other method progress communication. For example, when we use ATcommand, we may use the –d parameters to inform the system using which device.

b)   OpenLib work.

This workis want to gainthe directory of the reference ril. This step is preparing for work four(Get function RIL_Init by opendl and dlsym). Only when we get the path of reference ril, wecan open itdynamically. This method will reduce theopportunityof coincidence(相一致的,相投的).So the modem manufactory can match the AP code easily.

c)   RIL_startEventLoop work.

This work is want to get theril event loop for ap request. In the source code, you can see thisret = pthread_create(&s_tid_dispatch,&attr, eventLoop, NULL);In linux, this is want to create a new thread to runfunction eventloop. In function event loop, it want to open multi AT channel, ril_event_initfunction is initialize three list(readFds, timer_list, pending_list).

static void *
eventLoop(void *param) {
    int ret;
    int filedes[2];
    s_started = 1;
    ret = pipe(filedes);
    if (ret < 0) {
        ALOGE("Error in pipe() errno:%d", errno);
        return NULL;
    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);
    // Only returns on error
    ALOGE ("error in event_loop_base errno:%d", errno);
    // kill self to restart on error
    kill(0, SIGKILL);
    return NULL;

You can see that the code has open two file(readand write), so the simple code is only support single channel, however, in ourdevice, there are more then five channels to support multi operation, forexample, you want to data service to access the website, at meanwhile, you wantto get a ring call or send MMS. Single channel is only a simple code, not inreal time.

d)  Get function RIL_Init byopendl and dlsym

This work is only to gain the function RIL_Init address and call it. The function RIL_Init is inthe reference ril. After entering this work, we will use the first work result(Parameters),and then run the mainloop function.

const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
    int ret;
    int fd = -1;
    int opt;
    pthread_attr_t attr;
    s_rilenv = env;
    while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
        switch (opt) {
            case 'p':
                s_port = atoi(optarg);
                if (s_port == 0) {
                    return NULL;
                ALOGI("Opening loopback port %d\n", s_port);
            case 'd':
                s_device_path = optarg;
                ALOGI("Opening tty device %s\n", s_device_path);
            case 's':
                s_device_path   = optarg;
                s_device_socket = 1;
                ALOGI("Opening socket %s\n", s_device_path);
                return NULL;
    if (s_port < 0 && s_device_path == NULL) {
        return NULL;
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
    return &s_callbacks;

In function mainloop, you can know that it is a dead loop. The code willcheck the socket port and connect to if the device is simulator, itwill connect to qemud, otherwise it will connect to After all is bedone, will open AT channel and give the callback function onUnsolicited, whenthere are some unsolicited messages from modem.

static void *
mainLoop(void *param)
int fd;
int ret;
    AT_DUMP("== ", "entering mainLoop()", -1 );
    for (;;) {
        fd = -1;
        while  (fd < 0) {
            if (s_port > 0) {
                fd = socket_loopback_client(s_port, SOCK_STREAM);
            } else if (s_device_socket) {
                if (!strcmp(s_device_path, "/dev/socket/qemud")) {
                    /* Before trying to connect to /dev/socket/qemud (which is
                     * now another "legacy" way of communicating with the
                     * emulator), we will try to connecto to gsm service via
                     * qemu pipe. */
                    fd = qemu_pipe_open("qemud:gsm");
                    if (fd < 0) {
                        /* Qemu-specific control socket */
                        fd = socket_local_client( "qemud",
                                                  SOCK_STREAM );
                        if (fd >= 0 ) {
                            char  answer[2];
                            if ( write(fd, "gsm", 3) != 3 ||
                                 read(fd, answer, 2) != 2 ||
                                 memcmp(answer, "OK", 2) != 0)
                                fd = -1;
                    fd = socket_local_client( s_device_path,
                                            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 );

            if (fd < 0) {
                perror ("opening AT interface. retrying...");
                /* never returns */

        s_closed = 0;
        ret = at_open(fd, onUnsolicited);

        if (ret < 0) {
            ALOGE ("AT error %d on at_open\n", ret);
            return 0;
        RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
        // Give initializeCallback a chance to dispatched, since
        // we don't presently have a cancellation mechanism
        ALOGI("Re-opening after close");

e)   RIL_register

This work isto register all the AP request and callback, so when the function has been finished,we can return to The event includes solicited and unsolicitedrequest.

extern "C" void
RIL_register (const RIL_RadioFunctions *callbacks) {
    int ret;
    int flags;

    if (callbacks == NULL) {
        ALOGE("RIL_register: RIL_RadioFunctions * null");
    if (callbacks->version < RIL_VERSION_MIN) {
        ALOGE("RIL_register: version %d is to old, min version is %d",
             callbacks->version, RIL_VERSION_MIN);
    if (callbacks->version > RIL_VERSION) {
        ALOGE("RIL_register: version %d is too new, max version is %d",
             callbacks->version, RIL_VERSION);
    ALOGE("RIL_register: RIL version %d", callbacks->version);

    if (s_registerCalled > 0) {
        ALOGE("RIL_register has been called more than once. "
                "Subsequent call ignored");

    memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));

    s_registerCalled = 1;

    // Little self-check

    for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
        assert(i == s_commands[i].requestNumber);

    for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
        assert(i + RIL_UNSOL_RESPONSE_BASE
                == s_unsolResponses[i].requestNumber);

    // New rild impl calls RIL_startEventLoop() first
    // old standalone impl wants it here.

    if (s_started == 0) {

    // start listen socket

#if 0
    ret = socket_local_server (SOCKET_NAME_RIL,

    if (ret < 0) {
        ALOGE("Unable to bind socket errno:%d", errno);
        exit (-1);
    s_fdListen = ret;

    s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
    if (s_fdListen < 0) {
        ALOGE("Failed to get socket '" SOCKET_NAME_RIL "'");

    ret = listen(s_fdListen, 4);

    if (ret < 0) {
        ALOGE("Failed to listen on control socket '%d': %s",
             s_fdListen, strerror(errno));

    /* note: non-persistent so we can accept only one connection at a time */
    ril_event_set (&s_listen_event, s_fdListen, false,
                listenCallback, NULL);

    rilEventAddWakeup (&s_listen_event);

#if 1
    // start debug interface socket

    s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
    if (s_fdDebug < 0) {
        ALOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);

    ret = listen(s_fdDebug, 4);

    if (ret < 0) {
        ALOGE("Failed to listen on ril debug socket '%d': %s",
             s_fdDebug, strerror(errno));

    ril_event_set (&s_debug_event, s_fdDebug, true,
                debugCallback, NULL);

    rilEventAddWakeup (&s_debug_event);


Android 无线接口层RIL(Radio Layer Interface)——RILD

Android 无线接口层RIL(Radio Layer Interface)——RILD       Rild是Init进程启动的一个本地服务,这个本地服务并没有使用Binder之类的通讯手段,...

Android 无线接口层RIL(Radio Layer Interface)——RILD

Android 无线接口层RIL(Radio Layer Interface)——RILD       Rild是Init进程启动的一个本地服务,这个本地服务并没有使用Binder之类的通讯手段,...
  • sjdi521
  • sjdi521
  • 2014年09月30日 18:18
  • 507

Android 无线接口层RIL(Radio Layer Interface)

Android的无线接口层(RIL)提供了Android电话服务(android.telephony)与无线电硬件之间的抽象层。RIL是通讯无关的,提供基于GSM的网络支持。         下图显...

ril.dll (radio interface layer dll)

  • 2008年10月17日 18:05
  • 64KB
  • 下载

Radio Layer Interface(android)

Radio Layer Interface Introduction RIL Initialization RIL Interaction Solicited Unsolicited...
  • ghd_214
  • ghd_214
  • 2011年10月20日 23:29
  • 1202

Android 无线接口层(Radio Layer Interface)

原文地址::     INDEX 介绍 RIL 初始...

Android Radio Interface Layer

Android Radio Interface Layer (2013-3-7 23:08)   1.简述 Radio Interface Layer,简称RIL,在手机上是Mod...
  • mydots
  • mydots
  • 2015年10月30日 00:36
  • 520


这里再次 将Android6.0的phone应用源码分析(5)中最后的流向图拿出来 从图中可以看到RILJ通过RILD向MODEM发送命令后,接受response是通过readerLoop异...

Android RIL源码梳理(1) ——rild启动流程 .

一、RIL的基本架构 Android RIL (Radio Interface Layer)提供了Telephony服务和Radio硬件之间的抽象层。RIL负责数据的可靠传输、AT命令的发送...

Android RIL源码分析(2)

第二部分, Java代码 1.package简介: Android中,telephony相关的java代码主要在下列目录中: v frameworks/base/telephony/jav...
  • acm2008
  • acm2008
  • 2012年04月09日 14:18
  • 1162
您举报文章:Android 源码开发系列(三) Android RIL(Radio Interface Layer)