inandroidSystemrildrunningAPon,APApplication byrildsendATInstructions toBP,BPAfter receiving the information through therildSent toAP. There are two means of communication between the AP and BP:
1.Solicited Response:AptoBpsend request,BpgiveApSending a reply, the AT command and the type of callback functions stored in an array Ril_commands.h file:
{Array index, callback requests, in response to the callback function}
- {0, NULL, NULL}, //none
- {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
- {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
- {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
- {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
- {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
- {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
- {RIL_REQUEST_DIAL, dispatchDial, responseVoid},
- {RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
- {RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
- {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
- {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid},
- {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid},
- {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid},
- {RIL_REQUEST_UDUB, dispatchVoid, responseVoid},
- {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
- {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength},
- {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings},
- {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings},
- {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
- {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
- {RIL_REQUEST_DTMF, dispatchString, responseVoid},
- {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
- {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS},
- {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall},
- {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO},
- {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid},
- {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid},
- {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts},
- {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid},
- {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards},
- {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid},
- {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts},
- {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid},
- {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid},
- {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString},
- {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString},
- {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid},
- {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid},
- {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts},
- {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts},
- {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid},
- {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts},
- {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid},
- {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid},
- {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings},
- {RIL_REQUEST_DTMF_START, dispatchString, responseVoid},
- {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid},
- {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString},
- {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid},
- {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid},
- {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts},
- {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts},
- {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
- {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList},
- {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid},
- {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw},
- {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings},
- {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid},
- {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid},
- {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts},
- {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid},
- {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid},
- {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts},
- {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString},
- {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid},
- {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString},
- {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid},
- {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid},
- {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid},
- {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid},
- {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts},
- {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList},
- {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts},
- {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid},
- {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts},
- {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts},
- {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid},
- {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid},
- {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid},
- {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS},
- {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid},
- {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf},
- {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid},
- {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf},
- {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid},
- {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
- {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings},
- {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts},
- {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid},
- {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings},
- {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid},
- {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString},
- {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid},
- {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid},
- {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid},
- {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchCdmaSubscriptionSource, responseInts},
- {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString},
- {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, dispatchStrings, responseVoid},
- {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, dispatchString, responseSIM_IO},
- {RIL_REQUEST_VOICE_RADIO_TECH, dispatchVoiceRadioTech, responseInts},
2.unSolicited Response:BpInitiative toApSend event,The AT command and the type of callback functions stored in an array ofril_unsol_commands.h file:
{Array index, in response to the callback function, type}
- {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL},
- {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE},
- {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL},
- {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE},
- {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL},
- {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL},
- {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL},
- {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL},
- {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_SIM_REFRESH, responseSimRefresh, WAKE_PARTIAL},
- {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL},
- {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL},
- {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL},
- {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
- {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL},
- {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, responseInts, WAKE_PARTIAL},
AT mobile phone manufacturers use differentCommand is not exactly the same, in order to confidentiality,APversusBPBetween the various manufacturers to communicate through their relevant dynamic libraries.


RILModule consists ofrildDaemon,libril.so、librefrence.so three partscomposition:
1.rildModule is compiled into an executable file, to achieve amainFunction as a wholerilEntry point of the module. Use during initializationdlopenturn onlibrefrence_ril.so, Which fetches and executesRIL_InitFunction, getRIL_RadioFunctionsPointer byRIL_register()Functions registered tolibril.soLibrary, its source code structure is as follows:

2.libril.soIs a shared library, the work is mainly responsible for communication with the upper receivingrilRequest, and passed tolibrefrence_ril.soWhilelibrefrence_ril.soThe message is returned to the calling process, as shown in the source code is structured as follows:

3.librefrence_ril.so is achieved by the handset makers themselves, runs in rild processbydlopenWay to load, is responsible withmodemCommunication hardware, the conversion fromlibril.soThe request for theATCommand, while listeningModemFeedback tolibril.so

Android telephone system is divided into three parts, a variety of telephone related java application layer, Phone Service java layer, the upper layer was mainly the API, while communicating with a native, can be seen as a client telephone system, Native layer telephone service process RILD, is responsible for the upper layer provides services to various phone functions, to interact directly with the modem:

Android phone system design framework chart:

Because Modem Android developers to use is not the same, various instruction format, initialization sequences may be different, so in order to eliminate these differences, Android designers ril made an abstract concept of using a virtual phone, different modem-related AT commands or the communication protocol to the corresponding compiled dynamic link library .so files, Rild specific AT commands and responses by the synthesis resolver.
Android phone system code structure:
RILD frame design
In the android phone system, the native layer to achieve the service end of the telephone service, by the interaction RILD service and a modem, java layer implementation in a client calls, the paper introduces the server process RILD telephone system, the following isFIG RILD design framework:

RILD source code analysis
Followed by removal of the entire frame RILD source will be described in detail.
After the kernel startup is complete, it will start the first application process Init process, inInit process of android source code analysis process startsIn an article for the init process start the process of a detailed introduction. init.rc init process reads the file in the startup process to start some heavyweight native service, rild process is to start by configuring the init.rc.
- 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
RILD entry function analysis process
The next is a timing chart RILD given to start the process:

hardware\ril\rild\rild.c
- int main(int argc, char **argv)
- {
- const char * rilLibPath = NULL;
- char **rilArgv;
- void *dlHandle;
- const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
- const RIL_RadioFunctions *funcs;
- char libPath[PROPERTY_VALUE_MAX];
- unsigned char hasLibArgs = 0;
- int i;
- umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
- // rild start without parameters
- for (i = 1; i < argc ;) {
- if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
- rilLibPath = argv[i + 1];
- i += 2;
- } else if (0 == strcmp(argv[i], "--")) {
- i++;
- hasLibArgs = 1;
- break;
- } else {
- usage(argv[0]);
- }
- }
- if (rilLibPath == NULL) {
- // read value "rild.libpath" attribute by attribute Android system, i.e. storage path lib library
- if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
- goto done;
- } else {
- rilLibPath = libPath;
- }
- }
- ##################################################################################
- To determine whether the simulator
- ##################################################################################
- #if 1
- {
- static char* arg_overrides[3];
- static char arg_device[32];
- int done = 0;
- #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
- /* first, read /proc/cmdline into memory */
- char buffer[1024], *p, *q;
- int len;
- int fd = open("/proc/cmdline",O_RDONLY);
- if (fd < 0) {
- LOGD("could not open /proc/cmdline:%s", strerror(errno));
- goto OpenLib;
- }
- // read the contents of / proc / cmdline file
- do {
- len = read(fd,buffer,sizeof(buffer)); }
- while (len == -1 && errno == EINTR);
- if (len < 0) {
- LOGD("could not read /proc/cmdline:%s", strerror(errno));
- close(fd);
- goto OpenLib;
- }
- close(fd);
- // determines whether simulator, for the real machine, where the condition is false
- if (strstr(buffer, "android.qemud=") != NULL)
- {
- int tries = 5;
- #define QEMUD_SOCKET_NAME "qemud"
- while (1) {
- int fd;
- sleep(1);
- fd = socket_local_client(QEMUD_SOCKET_NAME,
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM );
- if (fd >= 0) {
- close(fd);
- snprintf( arg_device, sizeof(arg_device), "%s/%s",
- ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
- arg_overrides[1] = "-s";
- arg_overrides[2] = arg_device;
- done = 1;
- break;
- }
- LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));
- if (--tries == 0)
- break;
- }
- if (!done) {
- LOGE("could not connect to %s socket (giving up): %s",
- QEMUD_SOCKET_NAME, strerror(errno));
- while(1)
- sleep(0x00ffffff);
- }
- }
-
- /* otherwise, try to see if we passed a device name from the kernel */
- if (!done) do { //true
- #define KERNEL_OPTION "android.ril="
- #define DEV_PREFIX "/dev/"
- // content determination / proc / cmdline is included in "android.ril ="
- p = strstr( buffer, KERNEL_OPTION );
- if (p == NULL)
- break;
- p += sizeof(KERNEL_OPTION)-1;
- q = strpbrk( p, " \t\n\r" );
- if (q != NULL)
- *q = 0;
- snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
- arg_device[sizeof(arg_device)-1] = 0;
- arg_overrides[1] = "-d";
- arg_overrides[2] = arg_device;
- done = 1;
- } while (0);
-
- if (done) { //false
- argv = arg_overrides;
- argc = 3;
- i = 1;
- hasLibArgs = 1;
- rilLibPath = REFERENCE_RIL_PATH;
- LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
- }
- }
- OpenLib:
- #endif
- ##################################################################################
- Dynamic load library
- ##################################################################################
-
- switchUser();// set Rild process for the radio user groups
- // load library vendor-defined
- ①dlHandle = dlopen(rilLibPath, RTLD_NOW);
- if (dlHandle == NULL) {
- fprintf(stderr, "dlopen failed: %s\n", dlerror());
- exit(-1);
- }
- // Create a client event listener thread
- ②RIL_startEventLoop();
- // address by dlsym RIL_Init targeting function, and cast the function pointer RIL_RadioFunctions
- ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
- if (rilInit == NULL) {
- fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
- exit(-1);
- }
- if (hasLibArgs) { //false
- rilArgv = argv + i - 1;
- argc = argc -i + 1;
- } else {
- static char * newArgv[MAX_LIB_ARGS];
- static char args[PROPERTY_VALUE_MAX];
- rilArgv = newArgv;
- property_get(LIB_ARGS_PROPERTY, args, "");// read "rild.libargs" attribute property values system
- argc = make_argv(args, rilArgv);
- }
- // Make sure there's a reasonable argv[0]
- rilArgv[0] = argv[0];
- // call the function to initialize RIL_Init rild, passing parameters s_rilEnv, return address RIL_RadioFunctions
- ④funcs = rilInit(&s_rilEnv, argc, rilArgv);
- // Register client event processing interface RIL_RadioFunctions, and create a socket listening for events
- ⑤RIL_register(funcs);
- done:
- while(1) {
- // sleep(UINT32_MAX) seems to return immediately on bionic
- sleep(0x00ffffff);
- }
- }
Mainly do the following main function:
1. parse command line arguments, reads libreference-ril.so library storage path by determining whether a different approach to the simulator;
2. dlopen manual loading libreference-ril.so library;
3. Start the event loop processing;
4. RIL_Init function to obtain the address from libreference-ril.so library, using the functionlibril.so libraryRIL_Env interface registration to libreference-ril.so library, while libreference-ril.so library RIL_RadioFunctions interface registers to the library to libril.so establish libril.so library and library libreference-ril.so communication bridge;
Start event loop processing eventLoop worker
The establishment of multi-channelI/ODriving message queue for receiving a command issued by an upper layer and toModemsendATWork order, the entireRILThe core of the system. Create an event dispatch threads_tid_dispatch, thread of execution is eventLoop.
hardware\ril\libril\Ril.cpp
- extern "C" void RIL_startEventLoop(void) {
- int ret;
- pthread_attr_t attr;
- /* spin up eventLoop thread and wait for it to get started */
- s_started = 0;
- pthread_mutex_lock(&s_startupMutex);
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // Create a worker thread eventLoop
- ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
- // make sure the function returns the thread starts running before eventLoop
- while (s_started == 0) {
- pthread_cond_wait(&s_startupCond, &s_startupMutex);
- }
- pthread_mutex_unlock(&s_startupMutex);
- if (ret < 0) {
- LOGE("Failed to create dispatch thread errno:%d", errno);
- return;
- }
- }
eventLoop FIG execution timing:

- static void * eventLoop(void *param) {
- int ret;
- int filedes[2];
- ril_event_init(); // Initialize the request queue
- pthread_mutex_lock(&s_startupMutex);
- s_started = 1; // eventLoop thread running flag
- pthread_cond_broadcast(&s_startupCond);
- pthread_mutex_unlock(&s_startupMutex);
- // Create an anonymous pipe
- ret = pipe(filedes);
- if (ret < 0) {
- LOGE("Error in pipe() errno:%d", errno);
- return NULL;
- }
- // s_fdWakeupRead for the read end of pipe
- s_fdWakeupRead = filedes[0];
- // s_fdWakeupWrite to the write end of the pipe
- s_fdWakeupWrite = filedes[1];
- // set the read end of the pipe O_NONBLOCK nonblocking
- fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
- // Initialize s_wakeupfd_event content structure, handle is s_fdWakeupRead, the callback function is processWakeupCallback
- ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);
- ①rilEventAddWakeup (&s_wakeupfd_event);
- // Only returns on error
- ②ril_event_loop();
- LOGE ("error in event_loop_base errno:%d", errno);
- return NULL;
- }
defines the concept of the event in rild, Rild
It supports two types of events:
1. Timed Events: based on the execution time of the event to start the execution, byril_timer_addadd totime_listQueue
2. WakeupEvent: handle these eventsfdWill join theselect IOMultiplexed handle poolreadFDsWhen the correspondingfdThese events will trigger readable. For inlistenEnd ofsocket,fdReadable expressed client connections, at this time need to callacceptAccept the connection.
event is defined as follows:
- struct ril_event {
- struct ril_event *next;
- struct ril_event *prev;
- int fd; // file handle
- int index; // The index in the event monitor table
- bool persist; // If it is held, is not removed from the watch_list
- struct timeval timeout; // task execution time
- ril_event_cb func; // callback event handler
- void *param; // callback parameters
- };
inRildIn the process of several important events
- static struct ril_event s_commands_event;
- ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)
-
- static struct ril_event s_wakeupfd_event;
- ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)
-
- static struct ril_event s_listen_event;
- ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)
-
- static struct ril_event s_wake_timeout_event;
- ril_timer_add(&(p_info->event), &myRelativeTime);
- static struct ril_event s_debug_event;
- ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)
It defined three event queue in the RILD for handling different events:
/Event Monitoring queue
static struct ril_event * watch_table[MAX_FD_EVENTS];
//Timed event queue
static struct ril_event timer_list;
//Processing the event queue
static struct ril_event pending_list; //Pending event queue, the event has been triggered, the callback handler needs event
Add an event
1. Add
Wakeup Event
- static void rilEventAddWakeup(struct ril_event *ev) {
- ril_event_add(ev); // add an event to the monitoring tables watch_table s_wakeupfd_event
- triggerEvLoop(); // write the pipeline to be triggered in the event loop s_fdWakeupWrite
- }
- void ril_event_add(struct ril_event * ev)
- {
- dlog("~~~~ +ril_event_add ~~~~");
- MUTEX_ACQUIRE();
- for (int i = 0; i < MAX_FD_EVENTS; i++) { // Traverse monitoring table watch_table
- if (watch_table[i] == NULL) { // Find the index free from the monitoring list, then the task was added to the monitoring list
- watch_table[i] = ev; // add events to monitor table
- ev->index = i; // set index for the event in the monitoring tables index
- dlog("~~~~ added at %d ~~~~", i);
- dump_event(ev);
- FD_SET(ev->fd, &readFds); Corresponding to the event handler // add a handler added to the pool readFds
- if (ev->fd >= nfds) nfds = ev->fd+1; // handle to modify the maximum
- dlog("~~~~ nfds = %d ~~~~", nfds);
- break;
- }
- }
- MUTEX_RELEASE();
- dlog("~~~~ -ril_event_add ~~~~");
- }
2. Add timed events
- void ril_timer_add(struct ril_event * ev, struct timeval * tv)
- {
- dlog("~~~~ +ril_timer_add ~~~~");
- MUTEX_ACQUIRE();
- struct ril_event * list;
- if (tv != NULL) {
- list = timer_list.next;
- ev->fd = -1; // make sure fd is invalid
- struct timeval now;
- getNow(&now);
- timeradd(&now, tv, &ev->timeout);
- // keep list sorted
- while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) {
- list = list->next;
- }
- // list now points to the first event older than ev
- addToList(ev, list);
- }
- MUTEX_RELEASE();
- dlog("~~~~ -ril_timer_add ~~~~");
- }
trigger event
- static void triggerEvLoop() {
- int ret;
- if (!pthread_equal(pthread_self(), s_tid_dispatch)) { // If the current thread ID is not equal to the event dispatch thread eventLoop thread ID
- do {
- ret = write (s_fdWakeupWrite, " ", 1); // write end of the pipe 1 to write a value to the trigger event loop eventLoop
- } while (ret < 0 && errno == EINTR);
- }
- }
Handling Events
- void ril_event_loop()
- {
- int n;
- fd_set rfds;
- struct timeval tv;
- struct timeval * ptv;
- for (;;) {
- memcpy(&rfds, &readFds, sizeof(fd_set));
- if (-1 == calcNextTimeout(&tv)) {
- dlog("~~~~ no timers; blocking indefinitely ~~~~");
- ptv = NULL;
- } else {
- dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
- ptv = &tv;
- }
- // wait to use the select function on the FDS, as long as the FDS data recording apparatus soon, it will select the corresponding flag bit and returns. readFDS records all events related to the device handle. readFDS the handle is in the AddEvent added.
- printReadies(&rfds);
- n = select(nfds, &rfds, NULL, NULL, ptv);
- printReadies(&rfds);
- dlog("~~~~ %d events fired ~~~~", n);
- if (n < 0) {
- if (errno == EINTR) continue;
- LOGE("ril_event: select error (%d)", errno);
- return;
- }
- processTimeouts(); // query execution time has come to the event from timer_list and added to the pending_list
- processReadReadies(&rfds, n); // query data readable event from watch_table and added to pending_list in to deal with, if the event is not long-lasting event, it is deleted from the watch_table
- // Traverse pending_list, call an event handler callback function to handle all events
- firePending();
- }
- }
In eventLoop worker thread event loop processing incoming event and the timer expires, the entire processing flow as shown below:
First by Linux in select multi-channel I / O multiplexing handles handles all pool monitor when there is an event coming select returns otherwise blocked. When select returns, expressed an arrival event to handle the timeout events by calling processTimeouts function approach is traversing time_list list to check out events, and moved out event to pending_list the list, then call processReadReadies function to handle events triggered event handling is traversing watch_table list of queries trigger event, and trigger the move to pending_list the list, if the event is not long-lasting event, also need to be removed from the list watch_table, when the event finished two kinds of queries to be processed and after put into pending_list the list, call the function firePending be treated in the event centralized treatment, treatment to traverse the list, call the callback function for each event.
1. timeout event query
- static void processTimeouts()
- {
- dlog("~~~~ +processTimeouts ~~~~");
- MUTEX_ACQUIRE();
- struct timeval now;
- struct ril_event * tev = timer_list.next;
- struct ril_event * next;
- getNow(&now); // Get the current time
- dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
- // If the current time is greater than the timeout time of the event, then the event is removed from the timer_list added to pending_list
- while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
- dlog("~~~~ firing timer ~~~~");
- next = tev->next;
- removeFromList(tev); // remove the event from the timer_list
- addToList(tev, &pending_list); // add the event to pending_list
- tev = next;
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processTimeouts ~~~~");
- }
2. A readable event query
- static void processReadReadies(fd_set * rfds, int n)
- {
- dlog("~~~~ +processReadReadies (%d) ~~~~", n);
- MUTEX_ACQUIRE();
- // Traverse watch_table array, according to the n select returns a handle to find the corresponding event
- for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
- struct ril_event * rev = watch_table[i]; // get the corresponding event
- if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
- addToList(rev, &pending_list); // add the event to the pending_list
- if (rev->persist == false) { // If the event is not persistent in the event also removed from watch_table
- removeWatch(rev, i);
- }
- n--;
- }
- }
- MUTEX_RELEASE();
- dlog("~~~~ -processReadReadies (%d) ~~~~", n);
- }
3. Event Processing
- static void firePending()
- {
- dlog("~~~~ +firePending ~~~~");
- struct ril_event * ev = pending_list.next;
- while (ev != &pending_list) { // Traverse pending_list list, all events are processed in a linked list
- struct ril_event * next = ev->next;
- removeFromList(ev); // event processed removed from the pending_list
- ev->func(ev->fd, 0, ev->param); // Call the event handler callback function
- ev = next;
- }
- dlog("~~~~ -firePending ~~~~");
- }
RIL_Env defined
hardware\ril\include\telephony\ril.h
- struct RIL_Env {
- // notify the processing result after the completion of the request interface DLL
- void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen);
- // dynamic library unSolicited Response notification interface
- void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen);
- // submit a timeout task to Rild Interface
- void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime);
- };
hardware\ril\rild\rild.c
s_rilEnv variable definitions:
- static struct RIL_Env s_rilEnv = {
- RIL_onRequestComplete,
- RIL_onUnsolicitedResponse,
- RIL_requestTimedCallback
- };
Implement the various interface functions RIL_Env in hardware \ ril \ libril \ ril.cpp in
1.RIL_onRequestComplete
- extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
- RequestInfo *pRI;
- int ret;
- size_t errorOffset;
- pRI = (RequestInfo *)t;
- if (!checkAndDequeueRequestInfo(pRI)) {
- LOGE ("RIL_onRequestComplete: invalid RIL_Token");
- return;
- }
- if (pRI->local > 0) {
- // Locally issued command...void only!
- // response does not go back up the command socket
- LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
- goto done;
- }
- appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));
- if (pRI->cancelled == 0) {
- Parcel p;
- p.writeInt32 (RESPONSE_SOLICITED);
- p.writeInt32 (pRI->token);
- errorOffset = p.dataPosition();
- p.writeInt32 (e);
- if (response != NULL) {
- // there is a response payload, no matter success or not.
- ret = pRI->pCI->responseFunction(p, response, responselen);
- /* if an error occurred, rewind and mark it */
- if (ret != 0) {
- p.setDataPosition(errorOffset);
- p.writeInt32 (ret);
- }
- }
- if (e != RIL_E_SUCCESS) {
- appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));
- }
- if (s_fdCommand < 0) {
- LOGD ("RIL onRequestComplete: Command channel closed");
- }
- sendResponse(p);
- }
- done:
- free(pRI);
- }
By calling responseXXXThe underlying passed in response to the client process
2.RIL_onUnsolicitedResponse
- extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
- size_t datalen)
- {
- int unsolResponseIndex;
- int ret;
- int64_t timeReceived = 0;
- bool shouldScheduleTimeout = false;
- if (s_registerCalled == 0) {
- // Ignore RIL_onUnsolicitedResponse before RIL_register
- LOGW("RIL_onUnsolicitedResponse called before RIL_register");
- return;
- }
- unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
- if ((unsolResponseIndex < 0)
- || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
- LOGE("unsupported unsolicited response code %d", unsolResponse);
- return;
- }
- // Grab a wake lock if needed for this reponse,
- // as we exit we'll either release it immediately
- // or set a timer to release it later.
- switch (s_unsolResponses[unsolResponseIndex].wakeType) {
- case WAKE_PARTIAL:
- grabPartialWakeLock();
- shouldScheduleTimeout = true;
- break;
- case DONT_WAKE:
- default:
- // No wake lock is grabed so don't set timeout
- shouldScheduleTimeout = false;
- break;
- }
- // Mark the time this was received, doing this
- // after grabing the wakelock incase getting
- // the elapsedRealTime might cause us to goto
- // sleep.
- if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
- timeReceived = elapsedRealtime();
- }
- appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
- Parcel p;
- p.writeInt32 (RESPONSE_UNSOLICITED);
- p.writeInt32 (unsolResponse);
- ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
- if (ret != 0) {
- // Problem with the response. Don't continue;
- goto error_exit;
- }
- // some things get more payload
- switch(unsolResponse) {
- case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
- p.writeInt32(s_callbacks.onStateRequest());
- appendPrintBuf("%s {%s}", printBuf,
- radioStateToString(s_callbacks.onStateRequest()));
- break;
- case RIL_UNSOL_NITZ_TIME_RECEIVED:
- // Store the time that this was received so the
- // handler of this message can account for
- // the time it takes to arrive and process. In
- // particular the system has been known to sleep
- // before this message can be processed.
- p.writeInt64(timeReceived);
- break;
- }
- ret = sendResponse(p);
- if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
- // Unfortunately, NITZ time is not poll/update like everything
- // else in the system. So, if the upstream client isn't connected,
- // keep a copy of the last NITZ response (with receive time noted
- // above) around so we can deliver it when it is connected
- if (s_lastNITZTimeData != NULL) {
- free (s_lastNITZTimeData);
- s_lastNITZTimeData = NULL;
- }
- s_lastNITZTimeData = malloc(p.dataSize());
- s_lastNITZTimeDataSize = p.dataSize();
- memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
- }
- // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT
- // FIXME The java code should handshake here to release wake lock
- if (shouldScheduleTimeout) {
- // Cancel the previous request
- if (s_last_wake_timeout_info != NULL) {
- s_last_wake_timeout_info->userParam = (void *)1;
- }
- s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,
- &TIMEVAL_WAKE_TIMEOUT);
- }
- return;
- error_exit:
- if (shouldScheduleTimeout) {
- releaseWakeLock();
- }
- }
This function handles modemVarious events received at the network, such as network signal changes from incoming calls, receive text messages and so on. Then passed to the client process.
3.RIL_requestTimedCallback
- extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
- const struct timeval *relativeTime) {
- internalRequestTimedCallback (callback, param, relativeTime);
- }
- static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
- const struct timeval *relativeTime)
- {
- struct timeval myRelativeTime;
- UserCallbackInfo *p_info;
- p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
- p_info->p_callback = callback;
- p_info->userParam = param;
- if (relativeTime == NULL) {
- /* treat null parameter as a 0 relative time */
- memset (&myRelativeTime, 0, sizeof(myRelativeTime));
- } else {
- /* FIXME I think event_add's tv param is really const anyway */
- memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
- }
- ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
- ril_timer_add(&(p_info->event), &myRelativeTime);
- triggerEvLoop();
- return p_info;
- }
RIL_RadioFunctions defined
Client toRildRequest transmission interface,Achieved by each mobile phone manufacturers.
hardware\ril\include\telephony\Ril.h
- typedef struct {
- int version; // Rild version
- RIL_RequestFunc onRequest; // AP Request Interface
- RIL_RadioStateRequest onStateRequest;// BP Status
- RIL_Supports supports;
- RIL_Cancel onCancel;
- RIL_GetVersion getVersion;// dynamic library version
- } RIL_RadioFunctions;
variable definitions:
- static const RIL_RadioFunctions s_callbacks = {
- RIL_VERSION,
- onRequest,
- currentState,
- onSupports,
- onCancel,
- getVersion
- };
RIL_RadioFunctions implement various interface functions in hardware \ ril \ reference-ril \ reference-ril.c in
1.onRequest
- static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
- {
- ATResponse *p_response;
- int err;
- LOGD("onRequest: %s", requestToString(request));
- /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
- * when RADIO_STATE_UNAVAILABLE.
- */
- if (sState == RADIO_STATE_UNAVAILABLE
- && request != RIL_REQUEST_GET_SIM_STATUS
- ) {
- RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
- return;
- }
- /* Ignore all non-power requests when RADIO_STATE_OFF
- * (except RIL_REQUEST_GET_SIM_STATUS)
- */
- if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER
- || request == RIL_REQUEST_GET_SIM_STATUS)
- ) {
- RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
- return;
- }
- switch (request) {
- case RIL_REQUEST_GET_SIM_STATUS: {
- RIL_CardStatus *p_card_status;
- char *p_buffer;
- int buffer_size;
- int result = getCardStatus(&p_card_status);
- if (result == RIL_E_SUCCESS) {
- p_buffer = (char *)p_card_status;
- buffer_size = sizeof(*p_card_status);
- } else {
- p_buffer = NULL;
- buffer_size = 0;
- }
- RIL_onRequestComplete(t, result, p_buffer, buffer_size);
- freeCardStatus(p_card_status);
- break;
- }
- case RIL_REQUEST_GET_CURRENT_CALLS:
- requestGetCurrentCalls(data, datalen, t);
- break;
- case RIL_REQUEST_DIAL:
- requestDial(data, datalen, t);
- break;
- case RIL_REQUEST_HANGUP:
- requestHangup(data, datalen, t);
- break;
- case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
- // 3GPP 22.030 6.5.5
- // "Releases all held calls or sets User Determined User Busy
- // (UDUB) for a waiting call."
- at_send_command("AT+CHLD=0", NULL);
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
- // 3GPP 22.030 6.5.5
- // "Releases all active calls (if any exist) and accepts
- // the other (held or waiting) call."
- at_send_command("AT+CHLD=1", NULL);
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
- // 3GPP 22.030 6.5.5
- // "Places all active calls (if any exist) on hold and accepts
- // the other (held or waiting) call."
- at_send_command("AT+CHLD=2", NULL);
-
- #ifdef WORKAROUND_ERRONEOUS_ANSWER
- s_expectAnswer = 1;
- #endif /* WORKAROUND_ERRONEOUS_ANSWER */
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_ANSWER:
- at_send_command("ATA", NULL);
- #ifdef WORKAROUND_ERRONEOUS_ANSWER
- s_expectAnswer = 1;
- #endif /* WORKAROUND_ERRONEOUS_ANSWER */
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_CONFERENCE:
- // 3GPP 22.030 6.5.5
- // "Adds a held call to the conversation"
- at_send_command("AT+CHLD=3", NULL);
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_UDUB:
- /* user determined user busy */
- /* sometimes used: ATH */
- at_send_command("ATH", NULL);
- /* success or failure is ignored by the upper layer here.
- it will call GET_CURRENT_CALLS and determine success that way */
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- case RIL_REQUEST_SEPARATE_CONNECTION:
- {
- char cmd[12];
- int party = ((int*)data)[0];
- // Make sure that party is in a valid range.
- // (Note: The Telephony middle layer imposes a range of 1 to 7.
- // It's sufficient for us to just make sure it's single digit.)
- if (party > 0 && party < 10) {
- sprintf(cmd, "AT+CHLD=2%d", party);
- at_send_command(cmd, NULL);
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- }
- }
- break;
- case RIL_REQUEST_SIGNAL_STRENGTH:
- requestSignalStrength(data, datalen, t);
- break;
- case RIL_REQUEST_REGISTRATION_STATE:
- case RIL_REQUEST_GPRS_REGISTRATION_STATE:
- requestRegistrationState(request, data, datalen, t);
- break;
- case RIL_REQUEST_OPERATOR:
- requestOperator(data, datalen, t);
- break;
- case RIL_REQUEST_RADIO_POWER:
- requestRadioPower(data, datalen, t);
- break;
- case RIL_REQUEST_DTMF: {
- char c = ((char *)data)[0];
- char *cmd;
- asprintf(&cmd, "AT+VTS=%c", (int)c);
- at_send_command(cmd, NULL);
- free(cmd);
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- break;
- }
- case RIL_REQUEST_SEND_SMS:
- requestSendSMS(data, datalen, t);
- break;
- case RIL_REQUEST_SETUP_DATA_CALL:
- requestSetupDataCall(data, datalen, t);
- break;
- case RIL_REQUEST_SMS_ACKNOWLEDGE:
- requestSMSAcknowledge(data, datalen, t);
- break;
- case RIL_REQUEST_GET_IMSI:
- p_response = NULL;
- err = at_send_command_numeric("AT+CIMI", &p_response);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(char *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_GET_IMEI:
- p_response = NULL;
- err = at_send_command_numeric("AT+CGSN", &p_response);
-
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(char *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_SIM_IO:
- requestSIM_IO(data,datalen,t);
- break;
- case RIL_REQUEST_SEND_USSD:
- requestSendUSSD(data, datalen, t);
- break;
- case RIL_REQUEST_CANCEL_USSD:
- p_response = NULL;
- err = at_send_command_numeric("AT+CUSD=2", &p_response);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS,
- p_response->p_intermediates->line, sizeof(char *));
- }
- at_response_free(p_response);
- break;
- case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
- at_send_command("AT+COPS=0", NULL);
- break;
- case RIL_REQUEST_DATA_CALL_LIST:
- requestDataCallList(data, datalen, t);
- break;
- case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
- requestQueryNetworkSelectionMode(data, datalen, t);
- break;
- case RIL_REQUEST_OEM_HOOK_RAW:
- // echo back data
- RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
- break;
- case RIL_REQUEST_OEM_HOOK_STRINGS: {
- int i;
- const char ** cur;
- LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
- for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
- i > 0 ; cur++, i --) {
- LOGD("> '%s'", *cur);
- }
- // echo back strings
- RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
- break;
- }
- case RIL_REQUEST_WRITE_SMS_TO_SIM:
- requestWriteSmsToSim(data, datalen, t);
- break;
- case RIL_REQUEST_DELETE_SMS_ON_SIM: {
- char * cmd;
- p_response = NULL;
- asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
- err = at_send_command(cmd, &p_response);
- free(cmd);
- if (err < 0 || p_response->success == 0) {
- RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
- } else {
- RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
- }
- at_response_free(p_response);
- break;
- }
- case RIL_REQUEST_ENTER_SIM_PIN:
- case RIL_REQUEST_ENTER_SIM_PUK:
- case RIL_REQUEST_ENTER_SIM_PIN2:
- case RIL_REQUEST_ENTER_SIM_PUK2:
- case RIL_REQUEST_CHANGE_SIM_PIN:
- case RIL_REQUEST_CHANGE_SIM_PIN2:
- requestEnterSimPin(data, datalen, t);
- break;
- case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
- requestSmsBroadcastActivation(0,data, datalen, t);
- break;
- case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
- LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");
- requestSetSmsBroadcastConfig(0,data, datalen, t);
- break;
- case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
- requestGetSmsBroadcastConfig(0,data, datalen, t);
- break;
- default:
- RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
- break;
- }
- }
For each RIL_REQUEST_XXXConverted to the corresponding requestATcommand,send tomodemAnd then wait for sleep, when receivedATcommandAfter the final response, the thread wakes up, the response to the client process.
2.currentState
- static RIL_RadioState currentState()
- {
- return sState;
- }
3.onSupports
- static int onSupports (int requestCode)
- {
- //@@@ todo
- return 1;
- }
4.onCancel
- static void onCancel (RIL_Token t)
- {
- //@@@todo
- }
5.getVersion
- static const char * getVersion(void)
- {
- return "android reference-ril 1.0";
- }
Registration RIL_Env Interface
Since the AT command differences among mobile phone manufacturers, mobile phone manufacturers therefore need to achieve interaction with the modem layer, provided in the form of a dynamic library. As an intermediate layer between the modem and the upper layer, i.e., to interact with the bottom also communicate with the upper layer, so it is necessary to define an interface adapter RILD a dynamic library,RIL_Env andInterface is RIL_RadioFunctionslibril.so andBridge librefrence.so communication.YesRildIsolated interface architecture for generic code and manufacturer code,RIL_EnvRealized by a common code, andRIL_RadioFunctionsIt is the code of vendor implementations.
RIL_InitThe main tasks:
1. tolibrefrence.so registrationlibril.so interface providedRIL_Env;
2. CreatemainLoopWorker, used to initializeATModule, and monitorATStatus of the module, onceATIt is closed, then reopened and initializeAT;
3. whenATAfter being opened,mainLoopWorker willRildSubmit a timed events, and triggerseventLoopTo complete themodemInitialization;
4. CreatereadLoopWorker thread for theATSerial read data;
5.returnlibrefrence.so interface providedRIL_RadioFunctions;
hardware\ril\reference-ril\reference-ril.c
- 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; // will be defined ril.cpp RIL_Env registered to the reference-ril.c in s_rilenv
- 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;
- }
- LOGI("Opening loopback port %d\n", s_port);
- break;
- case 'd':
- s_device_path = optarg;
- LOGI("Opening tty device %s\n", s_device_path);
- break;
- case 's':
- s_device_path = optarg;
- s_device_socket = 1;
- LOGI("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);
- // Create a thread mainLoop
- ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
- // The RIL_RadioFunctions reference-ril.c defined return and register ril.cpp in s_callbacks
- return &s_callbacks;
- }
mainLoopWorker thread is used to initialize and monitorATModule, onceATModule is turned off, it opens automatically.
- static void * mainLoop(void *param)
- {
- int fd;
- int ret;
- AT_DUMP("== ", "entering mainLoop()", -1 );
- // Set a callback function to AT module
- at_set_on_reader_closed(onATReaderClosed);
- at_set_on_timeout(onATTimeout);
- for (;;) {
- fd = -1;
- while (fd < 0) { // Get device descriptor AT Serial Module
- 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")) {
- /* 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);
- }
- }
- s_closed = 0;
- // open the AT module, create a thread to read AT s_tid_reader, fd as a modem device file handle
- ret = at_open(fd, onUnsolicited);
- if (ret < 0) {
- LOGE ("AT error %d on at_open\n", ret);
- return 0;
- }
- // submit timeout task to Rild
- RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
- sleep(1);
- // If the AT module is turned off, the waitForClose return, re-open the AT, if AT is open, blocking
- waitForClose();
- LOGI("Re-opening after close");
- }
- }
1. Open AT module
byat_openOpen the file descriptorfdofATSerial devices, and register a callback functionATUnsolHandler
- int at_open(int fd, ATUnsolHandler h)
- {
- int ret;
- pthread_t tid;
- pthread_attr_t attr;
- s_fd = fd;
- s_unsolHandler = h;
- s_readerClosed = 0;
- s_responsePrefix = NULL;
- s_smsPDU = NULL;
- sp_response = NULL;
- /* Android power control ioctl */
- #ifdef HAVE_ANDROID_OS
- #ifdef OMAP_CSMI_POWER_CONTROL
- ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
- if(ret == 0) {
- int ack_count;
- int read_count;
- int old_flags;
- char sync_buf[256];
- old_flags = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
- do {
- ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
- read_count = 0;
- do {
- ret = read(fd, sync_buf, sizeof(sync_buf));
- if(ret > 0)
- read_count += ret;
- } while(ret > 0 || (ret < 0 && errno == EINTR));
- ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
- } while(ack_count > 0 || read_count > 0);
- fcntl(fd, F_SETFL, old_flags);
- s_readCount = 0;
- s_ackPowerIoctl = 1;
- }
- else
- s_ackPowerIoctl = 0;
- #else // OMAP_CSMI_POWER_CONTROL
- s_ackPowerIoctl = 0;
- #endif // OMAP_CSMI_POWER_CONTROL
- #endif /*HAVE_ANDROID_OS*/
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- // Create readerLoop work thread that is used to read data from the serial port
- ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
- if (ret < 0) {
- perror ("pthread_create");
- return -1;
- }
- return 0;
- }
2.Add timed events RIL_requestTimedCallback
- RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
-
- #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
The timing to add a timer event in the event queue, the event handler is initializeCallback, for transmitting some of the ATCommand to initializeBPofmodem。
3.readLoop worker
Read loop parsing hair came from Modem response. If you encounter URC handleUnsolicited reported RIL_JAVA through. If you answered command, then there is a response by handleFinalResponse notice send_at_command results.
- static void *readerLoop(void *arg)
- {
- for (;;) {
- const char * line;
- line = readline();
- if (line == NULL) {
- break;
- }
- if(isSMSUnsolicited(line)) { // determine whether the SMS notification
- char *line1;
- const char *line2;
- line1 = strdup(line);
- line2 = readline();