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 emulator虚拟设备分析第二篇之pipe

一、概述 qemu pipe也是一个虚拟设备,是一个通用的虚拟设备,用于提供guest os和emulator通信的功能,这样就不用写很多虚拟设备了。 之前在guest os中有个qemud进程,也是...
  • ayu_ag
  • ayu_ag
  • 2016年09月09日 14:39
  • 1502

android emulator虚拟设备分析第三篇之pipe上的qemud service

一、概述 以boot-properties为例,注意不需要看ANDROID-QEMUD.TXT,这个是和guest os中的qemud进行相关的,已废弃。 启动emulator时,有一个参数-pro...
  • ayu_ag
  • ayu_ag
  • 2016年09月09日 16:03
  • 1670


  • hanbo622
  • hanbo622
  • 2014年11月11日 11:29
  • 6322

Android——4.2 - 3G移植之路之 AT 通信 (四)

在前文Android——4.2 - 3G移植之路之 reference-ril .pppd 拨号上网 (三) 中分析了3G连接网络的流程,其中有说道通过AT指令建立连接, 在这里记录一下3G中的AT...
  • bzw73
  • bzw73
  • 2014年12月28日 10:15
  • 852

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

Android的无线接口层(RIL)提供了Android电话服务(android.telephony)与无线电硬件之间的抽象层。RIL是通讯无关的,提供基于GSM的网络支持。         下图显...
  • youbang321
  • youbang321
  • 2012年07月25日 20:25
  • 2361

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
  • 631


来自: 本章简单讲述下Android实现自动拨号的功能,该功能利用了系统启动的r...
  • chenyefei
  • chenyefei
  • 2016年10月26日 22:48
  • 698

Android——4.2 - 3G移植之路之 AT 通信 (四)

在前文Android——4.2 - 3G移植之路之 reference-ril .pppd 拨号上网 (三) 中分析了3G连接网络的流程,其中有说道通过AT指令建立连接, 在这里记录一下3G中的AT...
  • jscese
  • jscese
  • 2014年11月17日 17:06
  • 4418

Android Radio Interface Layer(RIL)

1.简述 Radio Interface Layer,简称RIL,在手机上是Modem与AP通讯的桥梁,RIL扮演的角色非常重要,RIL被设计成能够可靠的高效的传输数据一个模块。以下是RIL在M...
  • avalonlove
  • avalonlove
  • 2013年11月22日 17:31
  • 704

RIL(Radio Interface Layer)

  • xiejinfeng850414
  • xiejinfeng850414
  • 2012年11月26日 08:54
  • 300
您举报文章:Android 源码开发系列(三) Android RIL(Radio Interface Layer)