Android 电话系统框架介绍

在android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP。AP与BP之间有两种通信方式:

1.Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:

{数组中的索引号,请求回调函数,响应回调函数}

[plain] view plaincopy

  1. {0, NULL, NULL},                   //none
  2. {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus},
  3. {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts},
  4. {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts},
  5. {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts},
  6. {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts},
  7. {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
  8. {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
  9. {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
  10. {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
  11. {RIL_REQUEST_DIAL, dispatchDial, responseVoid},
  12. {RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
  13. {RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
  14. {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
  15. {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid},
  16. {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid},
  17. {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid},
  18. {RIL_REQUEST_UDUB, dispatchVoid, responseVoid},
  19. {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
  20. {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength},
  21. {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings},
  22. {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings},
  23. {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
  24. {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
  25. {RIL_REQUEST_DTMF, dispatchString, responseVoid},
  26. {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
  27. {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS},
  28. {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall},
  29. {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO},
  30. {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid},
  31. {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid},
  32. {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts},
  33. {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid},
  34. {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards},
  35. {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid},
  36. {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts},
  37. {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid},
  38. {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid},
  39. {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString},
  40. {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString},
  41. {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid},
  42. {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid},
  43. {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts},
  44. {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts},
  45. {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid},
  46. {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts},
  47. {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid},
  48. {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid},
  49. {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings},
  50. {RIL_REQUEST_DTMF_START, dispatchString, responseVoid},
  51. {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid},
  52. {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString},
  53. {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid},
  54. {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid},
  55. {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts},
  56. {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts},
  57. {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
  58. {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList},
  59. {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid},
  60. {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw},
  61. {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings},
  62. {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid},
  63. {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid},
  64. {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts},
  65. {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid},
  66. {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid},
  67. {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts},
  68. {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString},
  69. {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid},
  70. {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString},
  71. {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid},
  72. {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid},
  73. {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid},
  74. {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid},
  75. {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts},
  76. {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList},
  77. {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid},
  78. {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid},
  79. {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid},
  80. {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts},
  81. {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid},
  82. {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts},
  83. {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid},
  84. {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts},
  85. {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid},
  86. {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid},
  87. {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid},
  88. {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS},
  89. {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid},
  90. {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf},
  91. {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid},
  92. {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
  93. {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf},
  94. {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid},
  95. {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
  96. {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings},
  97. {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts},
  98. {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid},
  99. {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings},
  100. {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid},
  101. {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString},
  102. {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid},
  103. {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid},
  104. {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid},
  105. {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchCdmaSubscriptionSource, responseInts},
  106. {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString},
  107. {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, dispatchStrings, responseVoid},
  108. {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, dispatchString, responseSIM_IO},
  109. {RIL_REQUEST_VOICE_RADIO_TECH, dispatchVoiceRadioTech, responseInts},

2.unSolicited Response:Bp主动给Ap发送事件,该类型的AT指令及其回调函数以数组的形式存放在ril_unsol_commands.h文件中:

{数组中的索引号,响应回调函数,类型}

[plain] view plaincopy

  1. {RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
  2. {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
  3. {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
  4. {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL},
  5. {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL},
  6. {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL},
  7. {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL},
  8. {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE},
  9. {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL},
  10. {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE},
  11. {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL},
  12. {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL},
  13. {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL},
  14. {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL},
  15. {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL},
  16. {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL},
  17. {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
  18. {RIL_UNSOL_SIM_REFRESH, responseSimRefresh, WAKE_PARTIAL},
  19. {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL},
  20. {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL},
  21. {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL},
  22. {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL},
  23. {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
  24. {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL},
  25. {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
  26. {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL},
  27. {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL},
  28. {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL},
  29. {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL},
  30. {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL},
  31. {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL},
  32. {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL},
  33. {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL},
  34. {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
  35. {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL},
  36. {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, responseInts, WAKE_PARTIAL},

不同手机厂商使用的AT命令不完全相同,为了保密,AP与BP之间通过各厂商自己的相关动态库来通信。

RIL模块由rild守护进程、libril.so、librefrence.so三部分组成:

1.rild模块被编译为一个可执行文件,实现一个main函数作为整个ril模块的入口点。在初始化时使用dlopen打开librefrence_ril.so,从中取出并执行RIL_Init函数,得到RIL_RadioFunctions指针,通过RIL_register()函数注册到libril.so库中,其源码结构如下:

2.libril.so是共享库,主要负责同上层的通信工作,接收ril的请求,并传递给librefrence_ril.so,同时将librefrence_ril.so返回的消息送给调用进程,源码结构如下所示:

3.librefrence_ril.so是由各手机厂商自己实现,在rild进程运行中通过dlopen方式加载,主要负责跟modem硬件通信,转换来自libril.so的请求为AT命令,同时监听Modem的反馈信息给libril.so

Android的电话系统主要分为三个部分,java层的各种电话相关应用,java层的Phone Service,主要为上层提供API,同时与native进行通信,可以看做为电话系统的客户端,native层的电话服务进程RILD,负责为上层提供各种电话功能服务,直接与modem进行交互:

Android电话系统设计框架图:

由于Android 开发者使用的Modem 是不一样的,各种指令格式,初始化序列都可能不一样,所以为了消除这些差别,Android 设计者将ril 做了一个抽象,使用一个虚拟电话的概念,不同modem相关的AT指令或者通信协议编译成相应的动态链接库.so文件,Rild 是具体的AT 指令合成者和应答解析者。

Android电话系统代码结构图:

RILD框架设计

在android的电话系统中,在native层实现了电话服务的服务端,由RILD服务与modem的交互,在java层实现电话的客户端,本文主要介绍电话系统的服务端RILD进程,以下是RILD的设计框架图:

RILD源码分析

接下来通过源码对RILD的整个框架进行详细介绍。

在kernel启动完成后,将启动第一个应用进程Init进程,在android之Init进程启动过程源码分析一文中对init进程的启动流程进行了详细的介绍。init进程在启动过程中将读取init.rc文件来启动一些重量级的native服务,rild进程就是通过配置在init.rc中来启动的。

[plain] view plaincopy

  1. service ril-daemon /system/bin/rild
  2. class main
  3. socket rild stream 660 root radio
  4. socket rild-debug stream 660 radio system
  5. user root
  6. group radio cache inet misc audio sdcard_rw log

RILD进程入口函数分析

接下来给出的是RILD进程启动的时序图:

hardware\ril\rild\rild.c

[cpp] view plaincopy

  1. int main(int argc, char **argv)
  2. {
  3. const char * rilLibPath = NULL;
  4. char **rilArgv;
  5. void *dlHandle;
  6. const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
  7. const RIL_RadioFunctions *funcs;
  8. char libPath[PROPERTY_VALUE_MAX];
  9. unsigned char hasLibArgs = 0;
  10. int i;
  11.   umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
  12.   //rild启动无参数
  13. for (i = 1; i < argc ;) {
  14. if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
  15. rilLibPath = argv[i + 1];
  16. i += 2;
  17. } else if (0 == strcmp(argv[i], "--")) {
  18. i++;
  19. hasLibArgs = 1;
  20. break;
  21. } else {
  22. usage(argv[0]);
  23. }
  24. }
  25.   if (rilLibPath == NULL) {
  26.       //通过Android属性系统读取属性"rild.libpath"的值,即lib库的存放路径
  27. if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
  28. goto done;
  29. } else {
  30. rilLibPath = libPath;
  31. }
  32.   }
  33. ##################################################################################
  34. 判断是否为模拟器
  35. ##################################################################################
  36. #if 1
  37. {
  38. static char*  arg_overrides[3];
  39. static char   arg_device[32];
  40. int           done = 0;
  41. #define  REFERENCE_RIL_PATH  "/system/lib/libreference-ril.so"
  42. /* first, read /proc/cmdline into memory */
  43. char          buffer[1024], *p, *q;
  44. int           len;
  45. int           fd = open("/proc/cmdline",O_RDONLY);
  46. if (fd < 0) {
  47. LOGD("could not open /proc/cmdline:%s", strerror(errno));
  48. goto OpenLib;
  49. }
  50. //读取/proc/cmdline文件中的内容
  51. do {
  52. len = read(fd,buffer,sizeof(buffer)); }
  53. while (len == -1 && errno == EINTR);
  54. if (len < 0) {
  55. LOGD("could not read /proc/cmdline:%s", strerror(errno));
  56. close(fd);
  57. goto OpenLib;
  58. }
  59. close(fd);
  60. //判断是否为模拟器,对于真机,此处条件为false
  61. if (strstr(buffer, "android.qemud=") != NULL)
  62. {
  63. int  tries = 5;
  64. #define  QEMUD_SOCKET_NAME    "qemud"
  65. while (1) {
  66. int  fd;
  67. sleep(1);
  68. fd = socket_local_client(QEMUD_SOCKET_NAME,
  69. ANDROID_SOCKET_NAMESPACE_RESERVED,
  70. SOCK_STREAM );
  71. if (fd >= 0) {
  72. close(fd);
  73. snprintf( arg_device, sizeof(arg_device), "%s/%s",
  74. ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
  75. arg_overrides[1] = "-s";
  76. arg_overrides[2] = arg_device;
  77. done = 1;
  78. break;
  79. }
  80. LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));
  81. if (--tries == 0)
  82. break;
  83. }
  84. if (!done) {
  85. LOGE("could not connect to %s socket (giving up): %s",
  86. QEMUD_SOCKET_NAME, strerror(errno));
  87. while(1)
  88. sleep(0x00ffffff);
  89. }
  90. }
  91. /* otherwise, try to see if we passed a device name from the kernel */
  92. if (!done) do { //true
  93. #define  KERNEL_OPTION  "android.ril="
  94. #define  DEV_PREFIX     "/dev/"
  95. //判断/proc/cmdline中的内容是否包含"android.ril="
  96. p = strstr( buffer, KERNEL_OPTION );
  97. if (p == NULL)
  98. break;
  99. p += sizeof(KERNEL_OPTION)-1;
  100. q  = strpbrk( p, " \t\n\r" );
  101. if (q != NULL)
  102. *q = 0;
  103. snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
  104. arg_device[sizeof(arg_device)-1] = 0;
  105. arg_overrides[1] = "-d";
  106. arg_overrides[2] = arg_device;
  107. done = 1;
  108. } while (0);
  109. if (done) { //false
  110. argv = arg_overrides;
  111. argc = 3;
  112. i    = 1;
  113. hasLibArgs = 1;
  114. rilLibPath = REFERENCE_RIL_PATH;
  115. LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
  116. }
  117. }
  118. OpenLib:
  119. #endif
  120. ##################################################################################
  121. 动态库装载
  122. ##################################################################################
  123.   switchUser();//设置Rild进程的组用户为radio
  124.   //加载厂商自定义的库
  125. ①dlHandle = dlopen(rilLibPath, RTLD_NOW);
  126. if (dlHandle == NULL) {
  127. fprintf(stderr, "dlopen failed: %s\n", dlerror());
  128. exit(-1);
  129.   }
  130.   //创建客户端事件监听线程
  131.   ②RIL_startEventLoop();
  132.   //通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针
  133. ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
  134. if (rilInit == NULL) {
  135. fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
  136. exit(-1);
  137. }
  138. if (hasLibArgs) { //false
  139. rilArgv = argv + i - 1;
  140. argc = argc -i + 1;
  141. } else {
  142. static char * newArgv[MAX_LIB_ARGS];
  143. static char args[PROPERTY_VALUE_MAX];
  144. rilArgv = newArgv;
  145. property_get(LIB_ARGS_PROPERTY, args, "");//通过属性系统读取"rild.libargs"属性值
  146. argc = make_argv(args, rilArgv);
  147. }
  148. // Make sure there‘s a reasonable argv[0]
  149.   rilArgv[0] = argv[0];
  150.   //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
  151.   ④funcs = rilInit(&s_rilEnv, argc, rilArgv);
  152.   //注册客户端事件处理接口RIL_RadioFunctions,并创建socket监听事件
  153. ⑤RIL_register(funcs);
  154. done:
  155. while(1) {
  156. // sleep(UINT32_MAX) seems to return immediately on bionic
  157. sleep(0x00ffffff);
  158. }
  159. }

在main函数中主要完成以下工作:

1.解析命令行参数,通过判断是否为模拟器采取不同的方式来读取libreference-ril.so库的存放路径;

2.使用dlopen手动装载libreference-ril.so库;

3.启动事件循环处理;

4.从libreference-ril.so库中取得RIL_Init函数地址,并使用该函数将libril.so库中的RIL_Env接口注册到libreference-ril.so库,同时将libreference-ril.so库中的RIL_RadioFunctions接口注册到到libril.so库中,建立起libril.so库与libreference-ril.so库通信桥梁;

启动事件循环处理eventLoop工作线程

建立多路I/O驱动机制的消息队列,用来接收上层发出的命令以及往Modem发送AT指令的工作,时整个RIL系统的核心部分。创建一个事件分发线程s_tid_dispatch,线程执行体为eventLoop。

hardware\ril\libril\Ril.cpp

[cpp] view plaincopy

  1. extern "C" void RIL_startEventLoop(void) {
  2. int ret;
  3. pthread_attr_t attr;
  4. /* spin up eventLoop thread and wait for it to get started */
  5. s_started = 0;
  6. pthread_mutex_lock(&s_startupMutex);
  7. pthread_attr_init (&attr);
  8.   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  9.   //创建一个工作线程eventLoop
  10.   ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
  11.   //确保函数返回前eventLoop线程启动运行
  12. while (s_started == 0) {
  13. pthread_cond_wait(&s_startupCond, &s_startupMutex);
  14. }
  15. pthread_mutex_unlock(&s_startupMutex);
  16. if (ret < 0) {
  17. LOGE("Failed to create dispatch thread errno:%d", errno);
  18. return;
  19. }
  20. }

eventLoop执行时序图:

[cpp] view plaincopy

  1. static void * eventLoop(void *param) {
  2. int ret;
  3. int filedes[2];
  4. ril_event_init(); //初始化请求队列
  5. pthread_mutex_lock(&s_startupMutex);
  6. s_started = 1; //eventLoop线程运行标志位
  7. pthread_cond_broadcast(&s_startupCond);
  8.   pthread_mutex_unlock(&s_startupMutex);
  9.   //创建匿名管道
  10. ret = pipe(filedes);
  11. if (ret < 0) {
  12. LOGE("Error in pipe() errno:%d", errno);
  13. return NULL;
  14.   }
  15.   //s_fdWakeupRead为管道读端
  16.   s_fdWakeupRead = filedes[0];
  17.   //s_fdWakeupWrite为管道写端
  18.   s_fdWakeupWrite = filedes[1];
  19.   //设置管道读端为O_NONBLOCK非阻塞
  20.   fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
  21.   //初始化s_wakeupfd_event结构体的内容,句柄为s_fdWakeupRead,回调函数为   processWakeupCallback
  22. ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);
  23. ①rilEventAddWakeup (&s_wakeupfd_event);
  24. // Only returns on error
  25. ②ril_event_loop();
  26. LOGE ("error in event_loop_base errno:%d", errno);
  27. return NULL;
  28. }

在rild中定义了event的概念,Rild支持两种类型的事件:

1. 定时事件:根据事件的执行时间来启动执行,通过ril_timer_add添加到time_list队列中

2. Wakeup事件:这些事件的句柄fd将加入的select IO多路复用的句柄池readFDs中,当对应的fd可读时将触发这些事件。对于处于listen端的socket,fd可读表示有个客户端连接,此时需要调用accept接受连接。

事件定义如下:

[cpp] view plaincopy

  1. struct ril_event {
  2. struct ril_event *next;
  3. struct ril_event *prev;
  4. int fd;  //文件句柄
  5. int index; //该事件在监控表中的索引
  6. bool persist; //如果是保持的,则不从watch_list 中删除
  7. struct timeval timeout; //任务执行时间
  8. ril_event_cb func; //回调事件处理函数
  9. void *param; //回调时参数
  10. };

在Rild进程中的几个重要事件有

[cpp] view plaincopy

  1. static struct ril_event s_commands_event;
  2. ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)
  3. static struct ril_event s_wakeupfd_event;
  4. ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)
  5. static struct ril_event s_listen_event;
  6. ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)
  7. static struct ril_event s_wake_timeout_event;
  8. ril_timer_add(&(p_info->event), &myRelativeTime);

[cpp] view plaincopy

  1. static struct ril_event s_debug_event;
  2. ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)

在RILD中定义了三个事件队列,用于处理不同的事件:

/事件监控队列

static struct ril_event * watch_table[MAX_FD_EVENTS];

//定时事件队列

static struct ril_event timer_list;

//处理事件队列

static struct ril_event pending_list; //待处理事件队列,事件已经触发,需要所回调处理的事件

添加事件

1.添加Wakeup 事件

[cpp] view plaincopy

  1. static void rilEventAddWakeup(struct ril_event *ev) {
  2. ril_event_add(ev); //向监控表watch_table添加一个s_wakeupfd_event事件
  3. triggerEvLoop(); //向管道s_fdWakeupWrite中写入之来触发事件循环
  4. }

[cpp] view plaincopy

  1. void ril_event_add(struct ril_event * ev)
  2. {
  3. dlog("~~~~ +ril_event_add ~~~~");
  4. MUTEX_ACQUIRE();
  5. for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍历监控表watch_table
  6. if (watch_table[i] == NULL) { //从监控表中查找空闲的索引,然后把该任务加入到监控表中
  7. watch_table[i] = ev; //向监控表中添加事件
  8. ev->index = i; //事件的索引设置为在监控表中的索引
  9. dlog("~~~~ added at %d ~~~~", i);
  10. dump_event(ev);
  11. FD_SET(ev->fd, &readFds); //将添加的事件对应的句柄添加到句柄池readFds中
  12. if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值
  13. dlog("~~~~ nfds = %d ~~~~", nfds);
  14. break;
  15. }
  16. }
  17. MUTEX_RELEASE();
  18. dlog("~~~~ -ril_event_add ~~~~");
  19. }

2.添加定时事件

[cpp] view plaincopy

  1. void ril_timer_add(struct ril_event * ev, struct timeval * tv)
  2. {
  3. dlog("~~~~ +ril_timer_add ~~~~");
  4. MUTEX_ACQUIRE();
  5. struct ril_event * list;
  6. if (tv != NULL) {
  7. list = timer_list.next;
  8. ev->fd = -1; // make sure fd is invalid
  9. struct timeval now;
  10. getNow(&now);
  11. timeradd(&now, tv, &ev->timeout);
  12. // keep list sorted
  13. while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) {
  14. list = list->next;
  15. }
  16. // list now points to the first event older than ev
  17. addToList(ev, list);
  18. }
  19. MUTEX_RELEASE();
  20. dlog("~~~~ -ril_timer_add ~~~~");
  21. }

触发事件

[cpp] view plaincopy

  1. static void triggerEvLoop() {
  2. int ret;
  3.   if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //如果当前线程ID不等于事件分发线程eventLoop的线程ID
  4. do {
  5. ret = write (s_fdWakeupWrite, " ", 1); //向管道写端写入值1来触发eventLoop事件循环
  6. } while (ret < 0 && errno == EINTR);
  7. }
  8. }

处理事件

[cpp] view plaincopy

  1. void ril_event_loop()
  2. {
  3. int n;
  4. fd_set rfds;
  5. struct timeval tv;
  6. struct timeval * ptv;
  7. for (;;) {
  8. memcpy(&rfds, &readFds, sizeof(fd_set));
  9. if (-1 == calcNextTimeout(&tv)) {
  10. dlog("~~~~ no timers; blocking indefinitely ~~~~");
  11. ptv = NULL;
  12. } else {
  13. dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
  14. ptv = &tv;
  15. }
  16. //使用select 函数等待在FDS 上,只要FDS 中记录的设备有数据到来,select 就会设置相应的标志位并返回。readFDS 记录了所有的事件相关设备句柄。readFDS 中句柄是在在AddEvent 加入的。
  17. printReadies(&rfds);
  18. n = select(nfds, &rfds, NULL, NULL, ptv);
  19. printReadies(&rfds);
  20. dlog("~~~~ %d events fired ~~~~", n);
  21. if (n < 0) {
  22. if (errno == EINTR) continue;
  23. LOGE("ril_event: select error (%d)", errno);
  24. return;
  25. }
  26. processTimeouts(); //从timer_list中查询执行时间已到的事件,并添加到pending_list中
  27. processReadReadies(&rfds, n); //从watch_table中查询数据可读的事件,并添加到pending_list中去处理,如果该事件不是持久事件,则同时从watch_table中删除
  28. //遍历pending_list,调用事件处理回调函数处理所有事件
  29. firePending();
  30. }
  31. }

在eventLoop工作线程中,循环处理到来的事件及定时结束事件,整个处理流程如下图所示:

首先通过Linux中的select多路I/O复用对句柄池中的所有句柄进行监控,当有事件到来时select返回,否则阻塞。当select返回时,表示有事件的到来,通过调用processTimeouts函数来处理超时事件,处理方式是遍历time_list链表以查询超时事件,并将超时事件移入到pending_list链表中,接着调用processReadReadies函数来处理触发的事件,处理方式为遍历watch_table列表以查询触发的事件,并将触发的事件移入到pending_list链表中,如果该事件不是持久事件,还需要从watch_table列表中移除,当查询完两种待处理的事件并放入到pending_list链表中后,调用firePending函数对待处理的事件进行集中处理,处理方式为遍历链表,调用每一个事件的回调函数。

1.超时事件查询

[cpp] view plaincopy

  1. static void processTimeouts()
  2. {
  3. dlog("~~~~ +processTimeouts ~~~~");
  4. MUTEX_ACQUIRE();
  5. struct timeval now;
  6. struct ril_event * tev = timer_list.next;
  7. struct ril_event * next;
  8. getNow(&now); //获取当前时间
  9.   dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
  10.   //如果当前时间大于事件的超时时间,则将该事件从timer_list中移除,添加到pending_list
  11. while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
  12. dlog("~~~~ firing timer ~~~~");
  13. next = tev->next;
  14. removeFromList(tev); //从timer_list中移除事件
  15. addToList(tev, &pending_list); //将事件添加到pending_list
  16. tev = next;
  17. }
  18. MUTEX_RELEASE();
  19. dlog("~~~~ -processTimeouts ~~~~");
  20. }
2.可读事件查询

[cpp] view plaincopy

  1. static void processReadReadies(fd_set * rfds, int n)
  2. {
  3. dlog("~~~~ +processReadReadies (%d) ~~~~", n);
  4.   MUTEX_ACQUIRE();
  5.   //遍历watch_table数组,根据select返回的句柄n查找对应的事件
  6. for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
  7. struct ril_event * rev = watch_table[i]; //得到相应的事件
  8. if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
  9. addToList(rev, &pending_list); //将该事件添加到pending_list中
  10. if (rev->persist == false) { //如果该事件不是持久事件还要从watch_table中移除
  11. removeWatch(rev, i);
  12. }
  13. n--;
  14. }
  15. }
  16. MUTEX_RELEASE();
  17. dlog("~~~~ -processReadReadies (%d) ~~~~", n);
  18. }
3.事件处理

[cpp] view plaincopy

  1. static void firePending()
  2. {
  3. dlog("~~~~ +firePending ~~~~");
  4. struct ril_event * ev = pending_list.next;
  5. while (ev != &pending_list) { //遍历pending_list链表,处理链表中的所有事件
  6. struct ril_event * next = ev->next;
  7. removeFromList(ev); //将处理完的事件从pending_list中移除
  8. ev->func(ev->fd, 0, ev->param); //调用事件处理的回调函数
  9. ev = next;
  10. }
  11. dlog("~~~~ -firePending ~~~~");
  12. }

RIL_Env定义

hardware\ril\include\telephony\ril.h

[cpp] view plaincopy

  1. struct RIL_Env {
  2. //动态库完成请求后通知处理结果的接口
  3.   void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen);
  4. //动态库unSolicited Response通知接口
  5.   void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen);
  6. //向Rild提交一个超时任务的接口
  7. void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime);
  8. };

hardware\ril\rild\rild.c

s_rilEnv变量定义:

[cpp] view plaincopy

  1. static struct RIL_Env s_rilEnv = {
  2. RIL_onRequestComplete,
  3. RIL_onUnsolicitedResponse,
  4. RIL_requestTimedCallback
  5. };

在hardware\ril\libril\ril.cpp中实现了RIL_Env的各个接口函数

1.RIL_onRequestComplete

[cpp] view plaincopy

  1. extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
  2. RequestInfo *pRI;
  3. int ret;
  4. size_t errorOffset;
  5. pRI = (RequestInfo *)t;
  6. if (!checkAndDequeueRequestInfo(pRI)) {
  7. LOGE ("RIL_onRequestComplete: invalid RIL_Token");
  8. return;
  9. }
  10. if (pRI->local > 0) {
  11. // Locally issued command...void only!
  12. // response does not go back up the command socket
  13. LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
  14. goto done;
  15. }
  16. appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));
  17. if (pRI->cancelled == 0) {
  18. Parcel p;
  19. p.writeInt32 (RESPONSE_SOLICITED);
  20. p.writeInt32 (pRI->token);
  21. errorOffset = p.dataPosition();
  22. p.writeInt32 (e);
  23. if (response != NULL) {
  24. // there is a response payload, no matter success or not.
  25. ret = pRI->pCI->responseFunction(p, response, responselen);
  26. /* if an error occurred, rewind and mark it */
  27. if (ret != 0) {
  28. p.setDataPosition(errorOffset);
  29. p.writeInt32 (ret);
  30. }
  31. }
  32. if (e != RIL_E_SUCCESS) {
  33. appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));
  34. }
  35. if (s_fdCommand < 0) {
  36. LOGD ("RIL onRequestComplete: Command channel closed");
  37. }
  38. sendResponse(p);
  39. }
  40. done:
  41. free(pRI);
  42. }

通过调用responseXXX将底层响应传给客户进程

2.RIL_onUnsolicitedResponse

[cpp] view plaincopy

  1. extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
  2. size_t datalen)
  3. {
  4. int unsolResponseIndex;
  5. int ret;
  6. int64_t timeReceived = 0;
  7. bool shouldScheduleTimeout = false;
  8. if (s_registerCalled == 0) {
  9. // Ignore RIL_onUnsolicitedResponse before RIL_register
  10. LOGW("RIL_onUnsolicitedResponse called before RIL_register");
  11. return;
  12. }
  13. unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
  14. if ((unsolResponseIndex < 0)
  15. || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
  16. LOGE("unsupported unsolicited response code %d", unsolResponse);
  17. return;
  18. }
  19. // Grab a wake lock if needed for this reponse,
  20. // as we exit we‘ll either release it immediately
  21. // or set a timer to release it later.
  22. switch (s_unsolResponses[unsolResponseIndex].wakeType) {
  23. case WAKE_PARTIAL:
  24. grabPartialWakeLock();
  25. shouldScheduleTimeout = true;
  26. break;
  27. case DONT_WAKE:
  28. default:
  29. // No wake lock is grabed so don‘t set timeout
  30. shouldScheduleTimeout = false;
  31. break;
  32. }
  33. // Mark the time this was received, doing this
  34. // after grabing the wakelock incase getting
  35. // the elapsedRealTime might cause us to goto
  36. // sleep.
  37. if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
  38. timeReceived = elapsedRealtime();
  39. }
  40. appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
  41. Parcel p;
  42. p.writeInt32 (RESPONSE_UNSOLICITED);
  43. p.writeInt32 (unsolResponse);
  44. ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
  45. if (ret != 0) {
  46. // Problem with the response. Don‘t continue;
  47. goto error_exit;
  48. }
  49. // some things get more payload
  50. switch(unsolResponse) {
  51. case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
  52. p.writeInt32(s_callbacks.onStateRequest());
  53. appendPrintBuf("%s {%s}", printBuf,
  54. radioStateToString(s_callbacks.onStateRequest()));
  55. break;
  56. case RIL_UNSOL_NITZ_TIME_RECEIVED:
  57. // Store the time that this was received so the
  58. // handler of this message can account for
  59. // the time it takes to arrive and process. In
  60. // particular the system has been known to sleep
  61. // before this message can be processed.
  62. p.writeInt64(timeReceived);
  63. break;
  64. }
  65. ret = sendResponse(p);
  66. if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
  67. // Unfortunately, NITZ time is not poll/update like everything
  68. // else in the system. So, if the upstream client isn‘t connected,
  69. // keep a copy of the last NITZ response (with receive time noted
  70. // above) around so we can deliver it when it is connected
  71. if (s_lastNITZTimeData != NULL) {
  72. free (s_lastNITZTimeData);
  73. s_lastNITZTimeData = NULL;
  74. }
  75. s_lastNITZTimeData = malloc(p.dataSize());
  76. s_lastNITZTimeDataSize = p.dataSize();
  77. memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
  78. }
  79. // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT
  80. // FIXME The java code should handshake here to release wake lock
  81. if (shouldScheduleTimeout) {
  82. // Cancel the previous request
  83. if (s_last_wake_timeout_info != NULL) {
  84. s_last_wake_timeout_info->userParam = (void *)1;
  85. }
  86. s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,
  87. &TIMEVAL_WAKE_TIMEOUT);
  88. }
  89. return;
  90. error_exit:
  91. if (shouldScheduleTimeout) {
  92. releaseWakeLock();
  93. }
  94. }

这个函数处理modem从网络端接收到的各种事件,如网络信号变化,拨入的电话,收到短信等。然后传给客户进程。

3.RIL_requestTimedCallback

[cpp] view plaincopy

  1. extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
  2. const struct timeval *relativeTime) {
  3. internalRequestTimedCallback (callback, param, relativeTime);
  4. }

[cpp] view plaincopy

  1. static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
  2. const struct timeval *relativeTime)
  3. {
  4. struct timeval myRelativeTime;
  5. UserCallbackInfo *p_info;
  6. p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
  7. p_info->p_callback = callback;
  8. p_info->userParam = param;
  9. if (relativeTime == NULL) {
  10. /* treat null parameter as a 0 relative time */
  11. memset (&myRelativeTime, 0, sizeof(myRelativeTime));
  12. } else {
  13. /* FIXME I think event_add‘s tv param is really const anyway */
  14. memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
  15. }
  16. ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
  17. ril_timer_add(&(p_info->event), &myRelativeTime);
  18. triggerEvLoop();
  19. return p_info;
  20. }

RIL_RadioFunctions定义

客户端向Rild发送请求的接口,由各手机厂商实现。

hardware\ril\include\telephony\Ril.h

[cpp] view plaincopy

  1. typedef struct {
  2. int version; //Rild版本
  3. RIL_RequestFunc onRequest; //AP请求接口
  4. RIL_RadioStateRequest onStateRequest;//BP状态查询
  5. RIL_Supports supports;
  6. RIL_Cancel onCancel;
  7. RIL_GetVersion getVersion;//动态库版本
  8. } RIL_RadioFunctions;

变量定义:

[cpp] view plaincopy

  1. static const RIL_RadioFunctions s_callbacks = {
  2. RIL_VERSION,
  3. onRequest,
  4. currentState,
  5. onSupports,
  6. onCancel,
  7. getVersion
  8. };

在hardware\ril\reference-ril\reference-ril.c中实现了RIL_RadioFunctions的各个接口函数

1.onRequest

[cpp] view plaincopy

  1. static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
  2. {
  3. ATResponse *p_response;
  4. int err;
  5. LOGD("onRequest: %s", requestToString(request));
  6. /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
  7. * when RADIO_STATE_UNAVAILABLE.
  8. */
  9. if (sState == RADIO_STATE_UNAVAILABLE
  10. && request != RIL_REQUEST_GET_SIM_STATUS
  11. ) {
  12. RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
  13. return;
  14. }
  15. /* Ignore all non-power requests when RADIO_STATE_OFF
  16. * (except RIL_REQUEST_GET_SIM_STATUS)
  17. */
  18. if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER
  19. || request == RIL_REQUEST_GET_SIM_STATUS)
  20. ) {
  21. RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
  22. return;
  23. }
  24. switch (request) {
  25. case RIL_REQUEST_GET_SIM_STATUS: {
  26. RIL_CardStatus *p_card_status;
  27. char *p_buffer;
  28. int buffer_size;
  29. int result = getCardStatus(&p_card_status);
  30. if (result == RIL_E_SUCCESS) {
  31. p_buffer = (char *)p_card_status;
  32. buffer_size = sizeof(*p_card_status);
  33. } else {
  34. p_buffer = NULL;
  35. buffer_size = 0;
  36. }
  37. RIL_onRequestComplete(t, result, p_buffer, buffer_size);
  38. freeCardStatus(p_card_status);
  39. break;
  40. }
  41. case RIL_REQUEST_GET_CURRENT_CALLS:
  42. requestGetCurrentCalls(data, datalen, t);
  43. break;
  44. case RIL_REQUEST_DIAL:
  45. requestDial(data, datalen, t);
  46. break;
  47. case RIL_REQUEST_HANGUP:
  48. requestHangup(data, datalen, t);
  49. break;
  50. case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
  51. // 3GPP 22.030 6.5.5
  52. // "Releases all held calls or sets User Determined User Busy
  53. //  (UDUB) for a waiting call."
  54. at_send_command("AT+CHLD=0", NULL);
  55. /* success or failure is ignored by the upper layer here.
  56. it will call GET_CURRENT_CALLS and determine success that way */
  57. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  58. break;
  59. case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
  60. // 3GPP 22.030 6.5.5
  61. // "Releases all active calls (if any exist) and accepts
  62. //  the other (held or waiting) call."
  63. at_send_command("AT+CHLD=1", NULL);
  64. /* success or failure is ignored by the upper layer here.
  65. it will call GET_CURRENT_CALLS and determine success that way */
  66. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  67. break;
  68. case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
  69. // 3GPP 22.030 6.5.5
  70. // "Places all active calls (if any exist) on hold and accepts
  71. //  the other (held or waiting) call."
  72. at_send_command("AT+CHLD=2", NULL);
  73. #ifdef WORKAROUND_ERRONEOUS_ANSWER
  74. s_expectAnswer = 1;
  75. #endif /* WORKAROUND_ERRONEOUS_ANSWER */
  76. /* success or failure is ignored by the upper layer here.
  77. it will call GET_CURRENT_CALLS and determine success that way */
  78. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  79. break;
  80. case RIL_REQUEST_ANSWER:
  81. at_send_command("ATA", NULL);
  82. #ifdef WORKAROUND_ERRONEOUS_ANSWER
  83. s_expectAnswer = 1;
  84. #endif /* WORKAROUND_ERRONEOUS_ANSWER */
  85. /* success or failure is ignored by the upper layer here.
  86. it will call GET_CURRENT_CALLS and determine success that way */
  87. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  88. break;
  89. case RIL_REQUEST_CONFERENCE:
  90. // 3GPP 22.030 6.5.5
  91. // "Adds a held call to the conversation"
  92. at_send_command("AT+CHLD=3", NULL);
  93. /* success or failure is ignored by the upper layer here.
  94. it will call GET_CURRENT_CALLS and determine success that way */
  95. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  96. break;
  97. case RIL_REQUEST_UDUB:
  98. /* user determined user busy */
  99. /* sometimes used: ATH */
  100. at_send_command("ATH", NULL);
  101. /* success or failure is ignored by the upper layer here.
  102. it will call GET_CURRENT_CALLS and determine success that way */
  103. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  104. break;
  105. case RIL_REQUEST_SEPARATE_CONNECTION:
  106. {
  107. char  cmd[12];
  108. int   party = ((int*)data)[0];
  109. // Make sure that party is in a valid range.
  110. // (Note: The Telephony middle layer imposes a range of 1 to 7.
  111. // It‘s sufficient for us to just make sure it‘s single digit.)
  112. if (party > 0 && party < 10) {
  113. sprintf(cmd, "AT+CHLD=2%d", party);
  114. at_send_command(cmd, NULL);
  115. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  116. } else {
  117. RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
  118. }
  119. }
  120. break;
  121. case RIL_REQUEST_SIGNAL_STRENGTH:
  122. requestSignalStrength(data, datalen, t);
  123. break;
  124. case RIL_REQUEST_REGISTRATION_STATE:
  125. case RIL_REQUEST_GPRS_REGISTRATION_STATE:
  126. requestRegistrationState(request, data, datalen, t);
  127. break;
  128. case RIL_REQUEST_OPERATOR:
  129. requestOperator(data, datalen, t);
  130. break;
  131. case RIL_REQUEST_RADIO_POWER:
  132. requestRadioPower(data, datalen, t);
  133. break;
  134. case RIL_REQUEST_DTMF: {
  135. char c = ((char *)data)[0];
  136. char *cmd;
  137. asprintf(&cmd, "AT+VTS=%c", (int)c);
  138. at_send_command(cmd, NULL);
  139. free(cmd);
  140. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  141. break;
  142. }
  143. case RIL_REQUEST_SEND_SMS:
  144. requestSendSMS(data, datalen, t);
  145. break;
  146. case RIL_REQUEST_SETUP_DATA_CALL:
  147. requestSetupDataCall(data, datalen, t);
  148. break;
  149. case RIL_REQUEST_SMS_ACKNOWLEDGE:
  150. requestSMSAcknowledge(data, datalen, t);
  151. break;
  152. case RIL_REQUEST_GET_IMSI:
  153. p_response = NULL;
  154. err = at_send_command_numeric("AT+CIMI", &p_response);
  155. if (err < 0 || p_response->success == 0) {
  156. RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
  157. } else {
  158. RIL_onRequestComplete(t, RIL_E_SUCCESS,
  159. p_response->p_intermediates->line, sizeof(char *));
  160. }
  161. at_response_free(p_response);
  162. break;
  163. case RIL_REQUEST_GET_IMEI:
  164. p_response = NULL;
  165. err = at_send_command_numeric("AT+CGSN", &p_response);
  166. if (err < 0 || p_response->success == 0) {
  167. RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
  168. } else {
  169. RIL_onRequestComplete(t, RIL_E_SUCCESS,
  170. p_response->p_intermediates->line, sizeof(char *));
  171. }
  172. at_response_free(p_response);
  173. break;
  174. case RIL_REQUEST_SIM_IO:
  175. requestSIM_IO(data,datalen,t);
  176. break;
  177. case RIL_REQUEST_SEND_USSD:
  178. requestSendUSSD(data, datalen, t);
  179. break;
  180. case RIL_REQUEST_CANCEL_USSD:
  181. p_response = NULL;
  182. err = at_send_command_numeric("AT+CUSD=2", &p_response);
  183. if (err < 0 || p_response->success == 0) {
  184. RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
  185. } else {
  186. RIL_onRequestComplete(t, RIL_E_SUCCESS,
  187. p_response->p_intermediates->line, sizeof(char *));
  188. }
  189. at_response_free(p_response);
  190. break;
  191. case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
  192. at_send_command("AT+COPS=0", NULL);
  193. break;
  194. case RIL_REQUEST_DATA_CALL_LIST:
  195. requestDataCallList(data, datalen, t);
  196. break;
  197. case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
  198. requestQueryNetworkSelectionMode(data, datalen, t);
  199. break;
  200. case RIL_REQUEST_OEM_HOOK_RAW:
  201. // echo back data
  202. RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
  203. break;
  204. case RIL_REQUEST_OEM_HOOK_STRINGS: {
  205. int i;
  206. const char ** cur;
  207. LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
  208. for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
  209. i > 0 ; cur++, i --) {
  210. LOGD("> ‘%s‘", *cur);
  211. }
  212. // echo back strings
  213. RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
  214. break;
  215. }
  216. case RIL_REQUEST_WRITE_SMS_TO_SIM:
  217. requestWriteSmsToSim(data, datalen, t);
  218. break;
  219. case RIL_REQUEST_DELETE_SMS_ON_SIM: {
  220. char * cmd;
  221. p_response = NULL;
  222. asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
  223. err = at_send_command(cmd, &p_response);
  224. free(cmd);
  225. if (err < 0 || p_response->success == 0) {
  226. RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
  227. } else {
  228. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  229. }
  230. at_response_free(p_response);
  231. break;
  232. }
  233. case RIL_REQUEST_ENTER_SIM_PIN:
  234. case RIL_REQUEST_ENTER_SIM_PUK:
  235. case RIL_REQUEST_ENTER_SIM_PIN2:
  236. case RIL_REQUEST_ENTER_SIM_PUK2:
  237. case RIL_REQUEST_CHANGE_SIM_PIN:
  238. case RIL_REQUEST_CHANGE_SIM_PIN2:
  239. requestEnterSimPin(data, datalen, t);
  240. break;
  241. case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
  242. requestSmsBroadcastActivation(0,data, datalen, t);
  243. break;
  244. case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
  245. LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");
  246. requestSetSmsBroadcastConfig(0,data, datalen, t);
  247. break;
  248. case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
  249. requestGetSmsBroadcastConfig(0,data, datalen, t);
  250. break;
  251. default:
  252. RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
  253. break;
  254. }
  255. }

对每一个RIL_REQUEST_XXX请求转化成相应的ATcommand,发送给modem,然后睡眠等待,当收到ATcommand的最终响应后,线程被唤醒,将响应传给客户端进程。

2.currentState

[cpp] view plaincopy

  1. static RIL_RadioState currentState()
  2. {
  3. return sState;
  4. }

3.onSupports

[cpp] view plaincopy

  1. static int onSupports (int requestCode)
  2. {
  3. //@@@ todo
  4. return 1;
  5. }

4.onCancel

[cpp] view plaincopy

  1. static void onCancel (RIL_Token t)
  2. {
  3. //@@@todo
  4. }

5.getVersion

[cpp] view plaincopy

  1. static const char * getVersion(void)
  2. {
  3. return "android reference-ril 1.0";
  4. }

注册RIL_Env接口

由于各手机厂商的AT指令差异,因此与modem交互层需要各手机厂商实现,以动态库的形式提供。作为介于modem与上层的中间层,即要与底层交互也要与上层通信,因此就需要定义一个接口来衔接RILD与动态库,RIL_Env和RIL_RadioFunctions接口就是libril.so与librefrence.so通信的桥梁。是Rild架构中用于隔离通用代码和厂商代码的接口,RIL_Env由通用代码实现,而RIL_RadioFunctions则是由厂商代码实现。

RIL_Init的主要任务:

1. 向librefrence.so注册libril.so提供的接口RIL_Env;

2. 创建一个mainLoop工作线程,用于初始化AT模块,并监控AT模块的状态,一旦AT被关闭,则重新打开并初始化AT;

3. 当AT被打开后,mainLoop工作线程将向Rild提交一个定时事件,并触发eventLoop来完成对modem的初始化;

4. 创建一个readLoop工作线程,用于从AT串口中读取数据;

5.返回librefrence.so提供的接口RIL_RadioFunctions;

hardware\ril\reference-ril\reference-ril.c

[cpp] view plaincopy

  1. const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
  2. {
  3. int ret;
  4. int fd = -1;
  5. int opt;
  6. pthread_attr_t attr;
  7.   s_rilenv = env; //将ril.cpp中定义的RIL_Env注册到reference-ril.c中的s_rilenv
  8. while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
  9. switch (opt) {
  10. case ‘p‘:
  11. s_port = atoi(optarg);
  12. if (s_port == 0) {
  13. usage(argv[0]);
  14. return NULL;
  15. }
  16. LOGI("Opening loopback port %d\n", s_port);
  17. break;
  18. case ‘d‘:
  19. s_device_path = optarg;
  20. LOGI("Opening tty device %s\n", s_device_path);
  21. break;
  22. case ‘s‘:
  23. s_device_path   = optarg;
  24. s_device_socket = 1;
  25. LOGI("Opening socket %s\n", s_device_path);
  26. break;
  27. default:
  28. usage(argv[0]);
  29. return NULL;
  30. }
  31. }
  32. if (s_port < 0 && s_device_path == NULL) {
  33. usage(argv[0]);
  34. return NULL;
  35. }
  36. pthread_attr_init (&attr);
  37.   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  38.   //创建一个mainLoop线程
  39.   ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
  40.   //将reference-ril.c中定义的RIL_RadioFunctions返回并注册到ril.cpp中的s_callbacks
  41. return &s_callbacks;
  42. }

mainLoop工作线程是用来初始化并监控AT模块的,一旦AT模块被关闭,就自动打开。

[cpp] view plaincopy

  1. static void * mainLoop(void *param)
  2. {
  3. int fd;
  4. int ret;
  5.   AT_DUMP("== ", "entering mainLoop()", -1 );
  6.   //为AT模块设置回调函数
  7. at_set_on_reader_closed(onATReaderClosed);
  8. at_set_on_timeout(onATTimeout);
  9. for (;;) {
  10. fd = -1;
  11. while  (fd < 0) { //获得串口AT模块的设备文件描述符
  12. if (s_port > 0) {
  13. fd = socket_loopback_client(s_port, SOCK_STREAM);
  14. } else if (s_device_socket) {
  15. if (!strcmp(s_device_path, "/dev/socket/qemud")) {
  16. /* Qemu-specific control socket */
  17. fd = socket_local_client( "qemud",
  18. ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );
  19. if (fd >= 0 ) {
  20. char  answer[2];
  21. if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||
  22. memcmp(answer, "OK", 2) != 0)
  23. {
  24. close(fd);
  25. fd = -1;
  26. }
  27. }
  28. }
  29. else
  30. fd = socket_local_client( s_device_path,    ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );
  31. } else if (s_device_path != NULL) {
  32. fd = open (s_device_path, O_RDWR);
  33. if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
  34. /* disable echo on serial ports */
  35. struct termios  ios;
  36. tcgetattr( fd, &ios );
  37. ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
  38. tcsetattr( fd, TCSANOW, &ios );
  39. }
  40. }
  41. if (fd < 0) {
  42. perror ("opening AT interface. retrying...");
  43. sleep(10);
  44. }
  45. }
  46. s_closed = 0;
  47. //打开AT模块,创建AT读取线程s_tid_reader,fd为modem设备文件句柄
  48. ret = at_open(fd, onUnsolicited);
  49. if (ret < 0) {
  50. LOGE ("AT error %d on at_open\n", ret);
  51. return 0;
  52. }
  53. //向Rild提交超时任务
  54. RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
  55. sleep(1);
  56. //如果AT模块被关闭,则waitForClose返回,重新打开AT,如果AT已打开,则阻塞
  57. waitForClose();
  58. LOGI("Re-opening after close");
  59. }
  60. }

1.打开AT模块

通过at_open打开文件描述符为fd的AT串口设备,并注册回调函数ATUnsolHandler

[cpp] view plaincopy

  1. int at_open(int fd, ATUnsolHandler h)
  2. {
  3. int ret;
  4. pthread_t tid;
  5. pthread_attr_t attr;
  6. s_fd = fd;
  7. s_unsolHandler = h;
  8. s_readerClosed = 0;
  9. s_responsePrefix = NULL;
  10. s_smsPDU = NULL;
  11. sp_response = NULL;
  12. /* Android power control ioctl */
  13. #ifdef HAVE_ANDROID_OS
  14. #ifdef OMAP_CSMI_POWER_CONTROL
  15. ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
  16. if(ret == 0) {
  17. int ack_count;
  18. int read_count;
  19. int old_flags;
  20. char sync_buf[256];
  21. old_flags = fcntl(fd, F_GETFL, 0);
  22. fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
  23. do {
  24. ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
  25. read_count = 0;
  26. do {
  27. ret = read(fd, sync_buf, sizeof(sync_buf));
  28. if(ret > 0)
  29. read_count += ret;
  30. } while(ret > 0 || (ret < 0 && errno == EINTR));
  31. ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
  32. } while(ack_count > 0 || read_count > 0);
  33. fcntl(fd, F_SETFL, old_flags);
  34. s_readCount = 0;
  35. s_ackPowerIoctl = 1;
  36. }
  37. else
  38. s_ackPowerIoctl = 0;
  39. #else // OMAP_CSMI_POWER_CONTROL
  40. s_ackPowerIoctl = 0;
  41. #endif // OMAP_CSMI_POWER_CONTROL
  42. #endif /*HAVE_ANDROID_OS*/
  43. pthread_attr_init (&attr);
  44.   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  45.   //创建readerLoop工作线程,该线程用于从串口读取数据
  46. ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
  47. if (ret < 0) {
  48. perror ("pthread_create");
  49. return -1;
  50. }
  51. return 0;
  52. }

2.添加定时事件RIL_requestTimedCallback

[cpp] view plaincopy

  1. RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
  2. #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)

向定时事件队列中添加一个定时事件,该事件的处理函数为initializeCallback,用于发送一些AT指令来初始化BP的modem。

3.readLoop工作线程

Read loop 解析从Modem 发过来的回应。如果遇到URC 则通过handleUnsolicited 上报的RIL_JAVA。如果是命令的应答,则通过handleFinalResponse 通知send_at_command 有应答结果。

[cpp] view plaincopy

  1. static void *readerLoop(void *arg)
  2. {
  3. for (;;) {
  4. const char * line;
  5. line = readline();
  6. if (line == NULL) {
  7. break;
  8. }
  9. if(isSMSUnsolicited(line)) { //判断是否是SMS 通知
  10. char *line1;
  11. const char *line2;
  12. line1 = strdup(line);
  13. line2 = readline();
  14. if (line2 == NULL) {
  15. break;
  16. }
  17. if (s_unsolHandler != NULL) {
  18. s_unsolHandler (line1, line2); //回调通知SMS
  19. }
  20. free(line1);
  21. } else {
  22. processLine(line); //处理接收到的数据,根据line中的指令调用不同的回调函数
  23. }
  24. #ifdef HAVE_ANDROID_OS
  25. if (s_ackPowerIoctl > 0) {
  26. /* acknowledge that bytes have been read and processed */
  27. ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
  28. s_readCount = 0;
  29. }
  30. #endif /*HAVE_ANDROID_OS*/
  31. }
  32. onReaderClosed();
  33. return NULL;
  34. }

注册RIL_RadioFunctions接口

hardware\ril\libril\ril.cpp

[cpp] view plaincopy

  1. extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
  2. int ret;
  3.   int flags;
  4.   //版本验证
  5. if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {
  6. return;
  7. }
  8. if (callbacks->version < RIL_VERSION) {
  9. LOGE ("RIL_register: upgrade RIL to version %d current version=%d",
  10. RIL_VERSION, callbacks->version);
  11. }
  12. if (s_registerCalled > 0) {
  13. LOGE("RIL_register has been called more than once. "Subsequent call ignored");
  14. return;
  15.   }
  16. //将reference-ril.c中定义的RIL_RadioFunctions注册到ril.cpp中
  17. memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
  18. s_registerCalled = 1;
  19. for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
  20. assert(i == s_commands[i].requestNumber); //序号验证
  21. }
  22. for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
  23. assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber);
  24. }
  25. // old standalone impl wants it here.
  26. if (s_started == 0) {
  27. RIL_startEventLoop();
  28. }
  29.   // 得到名为rild的socket句柄
  30.   s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
  31. if (s_fdListen < 0) {
  32. LOGE("Failed to get socket ‘" SOCKET_NAME_RIL "‘");
  33. exit(-1);
  34.   }
  35.   // 监听该socket
  36. ret = listen(s_fdListen, 4);
  37. if (ret < 0) {
  38. LOGE("Failed to listen on control socket ‘%d‘: %s",s_fdListen, strerror(errno));
  39. exit(-1);
  40. }
  41. /* 设置s_listen_event事件,一旦有客户端连接,即s_fdListen可读就会导致eventLoop工作线程中的select返回,因为该事件不是持久的,因此调用为listenCallback处理完后,将从watch_table移除该事件,所以Rild只支持一个客户端连接*/
  42.   ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
  43. /* 添加s_listen_event事件,并触发eventLoop工作线程 */
  44. rilEventAddWakeup (&s_listen_event);
  45. #if 1
  46. // 得到调试socket的句柄rild-debug
  47. s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
  48. if (s_fdDebug < 0) {
  49. LOGE("Failed to get socket ‘" SOCKET_NAME_RIL_DEBUG "‘ errno:%d", errno);
  50. exit(-1);
  51.   }
  52.   //监听该socket
  53. ret = listen(s_fdDebug, 4);
  54. if (ret < 0) {
  55. LOGE("Failed to listen on ril debug socket ‘%d‘: %s",s_fdDebug, strerror(errno));
  56. exit(-1);
  57.   }
  58. /* 设置s_debug_event事件 */
  59. ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);
  60. /* 添加s_debug_event事件,并触发eventLoop工作线程  */
  61. rilEventAddWakeup (&s_debug_event);
  62. #endif
  63. }

打开监听端口,接收来自客户端进程的命令请求,当与客户进程连接建立时调用listenCallback函数,创建单独线程监视并处理所有事件源。

1.客户端连接处理

s_listen_event事件用于处理上层客户端的socket连接,当得到socket连接请求时,eventLoop工作线程里的select返回并自动调用listenCallback回调函数进行处理:

[cpp] view plaincopy

  1. tatic void listenCallback (int fd, short flags, void *param) {
  2. int ret;
  3. int err;
  4. int is_phone_socket;
  5. RecordStream *p_rs;
  6. commthread_data_t *user_data = NULL;
  7. user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));
  8. struct sockaddr_un peeraddr;
  9. socklen_t socklen = sizeof (peeraddr);
  10. struct ucred creds;
  11. socklen_t szCreds = sizeof(creds);
  12. struct passwd *pwd = NULL;
  13. assert (s_fdCommand < 0);
  14.   assert (fd == s_fdListen);
  15.   //接收一个客户端的连接,并将该socket连接保存在变量s_fdCommand中
  16. s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
  17. if (s_fdCommand < 0 ) {
  18. LOGE("Error on accept() errno:%d", errno);
  19. /* start listening for new connections again */
  20. rilEventAddWakeup(&s_listen_event);
  21. return;
  22. }
  23. /* 对客户端权限判断,判断是否是进程组ID为radio的进程发起的连接*/
  24. errno = 0;
  25. is_phone_socket = 0;
  26. err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
  27. if (err == 0 && szCreds > 0) {
  28. errno = 0;
  29. pwd = getpwuid(creds.uid);
  30. if (pwd != NULL) {
  31. if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {
  32. is_phone_socket = 1;
  33. } else {
  34. LOGE("RILD can‘t accept socket from process %s", pwd->pw_name);
  35. }
  36. } else {
  37. LOGE("Error on getpwuid() errno: %d", errno);
  38. }
  39. } else {
  40. LOGD("Error on getsockopt() errno: %d", errno);
  41. }
  42. if ( !is_phone_socket ) {
  43. LOGE("RILD must accept socket from %s", PHONE_PROCESS);
  44. close(s_fdCommand);
  45. s_fdCommand = -1;
  46. onCommandsSocketClosed();
  47. /* start listening for new connections again */
  48. rilEventAddWakeup(&s_listen_event);
  49. return;
  50. }
  51. #if 0
  52. if(s_dualSimMode) {
  53. if(s_sim_num == 0) {
  54. property_get(SIM_POWER_PROPERTY, prop, "0");
  55. if(!strcmp(prop, "0")) {
  56. property_set(SIM_POWER_PROPERTY, "1");
  57. s_callbacks.powerSIM(NULL);
  58. }
  59. } else if(s_sim_num == 1) {
  60. property_get(SIM_POWER_PROPERTY1, prop, "0");
  61. if(!strcmp(prop, "0")) {
  62. property_set(SIM_POWER_PROPERTY1, "1");
  63. s_callbacks.powerSIM(NULL);
  64. }
  65. }
  66. } else {
  67. property_get(SIM_POWER_PROPERTY, prop, "0");
  68. if(!strcmp(prop, "0")) {
  69. property_set(SIM_POWER_PROPERTY, "1");
  70. s_callbacks.powerSIM(NULL);
  71. }
  72. }
  73. #endif
  74. //p_rs为RecordStream类型,它内部会分配一个缓冲区来存储客户端发送过来的数据
  75.   p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
  76.   //添加一个针对接收到的客户端连接的处理事件,从而在eventLoop工作线程中处理该客户端的各种请求
  77. ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);
  78. rilEventAddWakeup (&s_commands_event);
  79. onNewCommandConnect();
  80. }

2.客户端通信处理

在listenCallback中首先接收客户端的连接请求,并验证客户端的权限,同时将该客户端以事件的形式添加到eventLoop工作线程中进行监控,当该客户端有数据请求时,eventLoop工作线程从select中返回,并自动调用processCommandsCallback回调函数:

[cpp] view plaincopy

  1. static void processCommandsCallback(int fd, short flags, void *param) {
  2. RecordStream *p_rs;
  3. void *p_record;
  4. size_t recordlen;
  5. int ret;
  6. assert(fd == s_fdCommand);
  7. p_rs = (RecordStream *)param;
  8.   for (;;) { //循环处理客户端发送过来的AT命令
  9.       //读取一条AT命令
  10. ret = record_stream_get_next(p_rs, &p_record, &recordlen);
  11. if (ret == 0 && p_record == NULL) {
  12. break;
  13. } else if (ret < 0) {
  14. break;
  15. } else if (ret == 0) { /* && p_record != NULL */
  16. //处理客户端发送过来的AT命令
  17. processCommandBuffer(p_record, recordlen);
  18. }
  19. }
  20. if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
  21. if (ret != 0) {
  22. LOGE("error on reading command socket errno:%d\n", errno);
  23. } else {
  24. LOGW("EOS.  Closing command socket.");
  25. }
  26. close(s_fdCommand);
  27. s_fdCommand = -1;
  28. ril_event_del(&s_commands_event);
  29. record_stream_free(p_rs);
  30. rilEventAddWakeup(&s_listen_event);
  31. onCommandsSocketClosed();
  32. }
  33. }

通过processCommandBuffer函数来处理每一条AT命令:

[cpp] view plaincopy

  1. static int processCommandBuffer(void *buffer, size_t buflen) {
  2. Parcel p;
  3. status_t status;
  4. int32_t request;
  5. int32_t token;
  6. RequestInfo *pRI;
  7. int ret;
  8. p.setData((uint8_t *) buffer, buflen);
  9. // status checked at end
  10. status = p.readInt32(&request);
  11. status = p.readInt32 (&token);
  12. if (status != NO_ERROR) {
  13. LOGE("invalid request block");
  14. return 0;
  15. }
  16. if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
  17. LOGE("unsupported request code %d token %d", request, token);
  18. return 0;
  19. }
  20. pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
  21. pRI->token = token; //AT命令标号
  22. pRI->pCI = &(s_commands[request]); //根据request找到s_commands命令数组中的指定AT命令
  23. ret = pthread_mutex_lock(&s_pendingRequestsMutex);
  24. assert (ret == 0);
  25. pRI->p_next = s_pendingRequests;
  26. s_pendingRequests = pRI;
  27. ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
  28.   assert (ret == 0);
  29.   //调用指定AT命令的dispatch函数,根据接收来自客户进程的命令和参数,调用onRequest进行处理。
  30. pRI->pCI->dispatchFunction(p, pRI);
  31. return 0;
  32. }

打电话的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},

发短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},

3.电话拨打流程

[cpp] view plaincopy

  1. static void dispatchDial (Parcel &p, RequestInfo *pRI) {
  2.   RIL_Dial dial; //RIL_Dial存储了打电话的所有信息
  3. RIL_UUS_Info uusInfo;
  4. int32_t sizeOfDial;
  5. int32_t t;
  6. .................. //初始化dial变量
  7.   s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);
  8.   .................
  9. return;
  10. }

s_callbacks.onRequest其实就是调用RIL_RadioFunctions中的onRequest函数,该函数在前面已介绍过了。

[cpp] view plaincopy

  1. static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
  2. {
  3. switch (request) {
  4. case RIL_REQUEST_DIAL:
  5. requestDial(data, datalen, t);
  6. break;
  7. }
  8. }

[cpp] view plaincopy

  1. static void requestDial(void *data, size_t datalen, RIL_Token t)
  2. {
  3. RIL_Dial *p_dial;
  4. char *cmd;
  5. const char *clir;
  6. int ret;
  7. p_dial = (RIL_Dial *)data;
  8. switch (p_dial->clir) {
  9. case 1: clir = "I"; break;  /*invocation*/
  10. case 2: clir = "i"; break;  /*suppression*/
  11. default:
  12. case 0: clir = ""; break;   /*subscription default*/
  13.   }
  14.   //向串口发送AT指令
  15. ret = at_send_command(cmd, NULL);
  16.   free(cmd);
  17.   //通知请求结果
  18. RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
  19. }

向AT发送完拨号指令后,通过RIL_onRequestComplete返回处理结果,RIL_onRequestComplete实际上是RIL_Env中的OnRequestComplete函数,在前面我们也介绍过了

[cpp] view plaincopy

  1. extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
  2. RequestInfo *pRI;
  3. int ret;
  4. size_t errorOffset;
  5.   pRI = (RequestInfo *)t;
  6.   //该请求已经处理,需要从请求队列中移除该请求
  7. if (!checkAndDequeueRequestInfo(pRI)) {
  8. LOGE ("RIL_onRequestComplete: invalid RIL_Token");
  9. return;
  10. }
  11. if (pRI->local > 0) {
  12. ...........
  13. sendResponse(p);
  14. }
  15. done:
  16. free(pRI);
  17. }

[cpp] view plaincopy

  1. static int sendResponse (Parcel &p) {
  2. return sendResponseRaw(p.data(), p.dataSize()); //将结果发送给JAVA RIL客户端
  3. }

[cpp] view plaincopy

  1. static int sendResponseRaw (const void *data, size_t dataSize) {
  2. int fd = s_fdCommand;
  3. int ret;
  4. uint32_t header;
  5. if (s_fdCommand < 0) {
  6. return -1;
  7. }
  8. if (dataSize > MAX_COMMAND_BYTES) {
  9. return -1;
  10. }
  11. pthread_mutex_lock(&s_writeMutex);
  12. header = htonl(dataSize);
  13. ret = blockingWrite(fd, (void *)&header, sizeof(header));
  14. if (ret < 0) {
  15. pthread_mutex_unlock(&s_writeMutex);
  16. return ret;
  17. }
  18. ret = blockingWrite(fd, data, dataSize);
  19. if (ret < 0) {
  20. pthread_mutex_unlock(&s_writeMutex);
  21. return ret;
  22. }
  23. pthread_mutex_unlock(&s_writeMutex);
  24. return 0;
  25. }

拨打电话的时序图如下:

Rild通过onRequest向动态库提交一个请求,然后返回,动态库处理完请求后,处理结果通过回调接口通知客户端

Android 电话系统框架介绍,布布扣,bubuko.com

时间: 07-13

Android 电话系统框架介绍的相关文章

Android系统框架介绍

图中的软件层次自上而下分成4个层次应用程序(Application)用用程序框架(Application Framework)各种类库(Libraries)和android运行时(Adnorid Runtime)操作系统(OS)一.应用程序(Application)        应用层是和用户交互的一个层次,用户可以看得见的一些应用,用户可以操作.这类应用基本都是通过Java语言编写的独立的能够完成某些功能的应用程序. Android本身提供了桌面(Home),联系人(Contacts),拨打

2、android系统框架的介绍

android系统框架介绍 src目录:主要完成java代码编写 assets目录:资源目录 res目录:存放图片.布局文件.字符串.菜单等文件 bin目录:输出文件夹,如生成apk文件 project.properties:工程属性文件配置 gen目录:系统自动生成的源代码目录 R.java文件:系统自动生成的文件,默认有attr.drawable.layout.string4个静态内部类,每个类对应一种资源 AndroidManifest.xml:描述package中暴露的组件(activi

[IOS_HTML5]各种JS框架介绍--用HTML5/CSS3/JS开发Android/IOS应用

现在人人都想成为安卓/IOS应用开发工程师.其实,安卓/IOS应用可以用很多种语言来实现.由于我们前端开发工程师,对HTML5/CSS/JavaScript的网络编程已经相当熟悉了.所以,今天大家将会认识到一些利用前端语言来开发安卓/IOS应用的工具. 在文章的末尾,也介绍了使用JAVA.C#.Lua以及AS3来开发安卓应用的工具. 希望大家都能找到适合自己的开发工具!祝大家开发安卓/IOS应用一切顺利! PhoneGap 开发语言: HTML, CSS, JavaScript 开发工具: Ph

Android应用程序窗口设计框架介绍

在Android系统中,一个Activity对应一个应用程序窗口,任何一个Activity的启动都是由AMS服务和应用程序进程相互配合来完成的.AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属进程来完成.AMS服务通过realStartActivityLocked函数来通知应用程序进程启动某个Activity: frameworks\base\services\java\com\android\server\am\ ActivityStack.j

Android 网络框架 Retrofit2.0介绍、使用和封装

前言 时至今日,Android的网络框架不再像之前那么到处都是,随着Google把 HttpClient直接删掉,似乎意味着Android越来越成熟.网络框架中的佼佼者Volley也不再那么光鲜,取而代之的是 Retrofit 和 okHttp. 感觉很像 OnePiece 中白胡子的离去象征着时代的变革,新时代的开始,多弗的垮台象征着七武海制度的取缔一样,不会使用Retrofit + okHttp + RxJava等一系列技术,就迈不进新时代的门槛,也不足以称为一个合格的开发者. 哈哈闲话不多

Android Multimedia框架总结(七)C++中MediaPlayer的C/S架构补充及MediaService介绍

http://blog.csdn.net/hejjunlin/article/details/52465168 前面一篇主要介绍c++中MediaPlayer的C/S架构中和Client相关部分,并中间穿插了mediaplayerservice的部分.但是对于这块C/S部分,没有放大去分析.<Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程>是从整体上看的,今天我们把这块C/S模型放大去看下.同样先看下Agen

Android多媒体开发介绍(转)

Android多媒体开发介绍 转自:http://blog.csdn.net/reiliu/article/details/9060557 一.       多媒体架构 基于第三方PacketVideo公司的OpenCORE来实现,支持所有通用的音频/视频/静态图像格式,包括:MPEG4.H.264.MP3.AAC.AMR.JPG.PNG.GIF等.从功能上分为两部分,一是音/视频的回放(PlayBack),二是音视频的纪录(Recorder). CODEC(编解码器)使用OpenMAX 1L

android多媒体框架学习 详解 最新版本

一:多媒体框架概述   jellybean 的多媒体跟以前的版本,通过对比没啥变化,最大的变化是google终于舍得给multimedia建个独立的git了(framework/av),等你好久了!也体现了media 在整个android系统中的重要性!framework/av下都是些C/C++代码(libmedia,libmediaplayerservice,libstagefright),jni和 java api 还是保留在原来的位置,改革还不够彻底,但还是迈出了这一步,以后维护能更好的进

如何在程序开发项目中选择合适的 JavaScript 框架,节省时间和成本的9款极佳的JavaScript框架介绍

从技术上来看,iOS,Android 和 Windows Phone 上的移动应用是使用不同的程序语言开发的,iOS 应用使用 Objective-C,Android 应用使用 Java,而 Windows Phone 应用使用 .NET. .随着 JavaScript,CSS 和 HTML 知识技能的提升,相信你也可以构建一个超赞的移动应用.在这篇博客里,我们将会介绍一些极好的 JavaScript 移动应用程序开发框架. 说到网络开发,就不得不说 JavaScript,这是一款很有前途的程序