1. RIL(RadioInterface Layer) Architecture
RIL is short name for Radio Layer Interface. The rilis 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 the opportunity of 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 this ret = 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);
-
- ril_event_loop();
- ALOGE ("error in event_loop_base errno:%d", errno);
-
- 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")) {
-
-
-
-
- fd = qemu_pipe_open("qemud:gsm");
- if (fd < 0) {
-
- 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 ) ) {
-
- struct termios ios;
- tcgetattr( fd, &ios );
- ios.c_lflag = 0;
- tcsetattr( fd, TCSANOW, &ios );
- }
- }
-
- if (fd < 0) {
- perror ("opening AT interface. retrying...");
- sleep(10);
-
- }
- }
-
- 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);
-
-
- 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;
-
-
-
- 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);
- }
-
-
-
-
- if (s_started == 0) {
- RIL_startEventLoop();
- }
-
-
-
- #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
-
-
-
- ril_event_set (&s_listen_event, s_fdListen, false,
- listenCallback, NULL);
-
- rilEventAddWakeup (&s_listen_event);
-
- #if 1
-
-
- 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
-
- }