关闭

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

标签: androidinterfacelayersocketparametersfunction
5884人阅读 评论(3) 收藏 举报
分类:

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];
    ril_event_init();
    pthread_mutex_lock(&s_startupMutex);
    s_started = 1;
    pthread_cond_broadcast(&s_startupCond);
    pthread_mutex_unlock(&s_startupMutex);
    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
    ril_event_loop();
    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) {
                    usage(argv[0]);
                    return NULL;
                }
                ALOGI("Opening loopback port %d\n", s_port);
            break;
            case 'd':
                s_device_path = optarg;
                ALOGI("Opening tty device %s\n", s_device_path);
            break;
            case 's':
                s_device_path   = optarg;
                s_device_socket = 1;
                ALOGI("Opening socket %s\n", s_device_path);
            break;
            default:
                usage(argv[0]);
                return NULL;
        }
    }
    if (s_port < 0 && s_device_path == NULL) {
        usage(argv[0]);
        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 ril.java. if the device is simulator, itwill connect to qemud, otherwise it will connect to ril.java. 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 );
    at_set_on_reader_closed(onATReaderClosed);
    at_set_on_timeout(onATTimeout);
    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",
                                                  ANDROID_SOCKET_NAMESPACE_RESERVED,
                                                  SOCK_STREAM );
                        if (fd >= 0 ) {
                            char  answer[2];
                            if ( write(fd, "gsm", 3) != 3 ||
                                 read(fd, answer, 2) != 2 ||
                                 memcmp(answer, "OK", 2) != 0)
                            {
                                close(fd);
                                fd = -1;
                            }
                       }
                    }
                }
                else
                    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 );
                }
            }

            if (fd < 0) {
                perror ("opening AT interface. retrying...");
                sleep(10);
                /* 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
        sleep(1);
        waitForClose();
        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 ril.java. 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");
        return;
    }
    if (callbacks->version < RIL_VERSION_MIN) {
        ALOGE("RIL_register: version %d is to old, min version is %d",
             callbacks->version, RIL_VERSION_MIN);
        return;
    }
    if (callbacks->version > RIL_VERSION) {
        ALOGE("RIL_register: version %d is too new, max version is %d",
             callbacks->version, RIL_VERSION);
        return;
    }
    ALOGE("RIL_register: RIL version %d", callbacks->version);

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

    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) {
        RIL_startEventLoop();
    }

    // start listen socket

#if 0
    ret = socket_local_server (SOCKET_NAME_RIL,
            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);

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

#else
    s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
    if (s_fdListen < 0) {
        ALOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
        exit(-1);
    }

    ret = listen(s_fdListen, 4);

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


    /* 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);
        exit(-1);
    }

    ret = listen(s_fdDebug, 4);

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

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

    rilEventAddWakeup (&s_debug_event);
#endif

}
4
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:92645次
    • 积分:1222
    • 等级:
    • 排名:千里之外
    • 原创:21篇
    • 转载:6篇
    • 译文:0篇
    • 评论:85条
    最新评论