非启动界面 Android RIL模块联网

Android的RIL(Radio Interface Layer)模块提供Android telephony服务和radio硬件之间的一个抽象层。RIL模块的架构如下图所示

Android RIL模块非启动界面联网实战(一) - angelbear - angelbear的博客

最上面的是Android的应用程序,比如拨号、短信息等程序,这些程序调用Application Framework层的telephony API,即可以完成打电话、发短信等操作。

以上都是虚拟机以上层面的,rild和vender ril是linux层的用户程序(库),rild是一个daemon程序,在init.rc中可以看到rild程序的启动

service ril-daemon /system/bin/rild 
    socket rild stream 660 root radio 
    socket rild-debug stream 660 radio system 
    user root 
    group radio cache inet misc audio 
同时注意到rild在启动的时候,还开启了两个以名称做标识的socket,rild和rild-debug,rild socket就是上层的framework和rild程序通信的手段,而rild-debug socket是留给radiooptions等程序调试使用的,后来这个rild-debug的socket起到了很重要的作用。

这次我没有从java端的代码入手,而是直接先开始看rild的代码。rild的代码只有rild.c一个,本身并不长,下面是rild的main函数

 
 
  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.  
  11. int i;
  12.  
  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.  
  26. if (rilLibPath == NULL) {
  27. if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
  28. // No lib sepcified on the command line, and nothing set in props.
  29. // Assume "no-ril" case.
  30. goto done;
  31. } else {
  32. rilLibPath = libPath;
  33. }
  34. }
  35.  
  36. /* special override when in the emulator */
  37. #if 1
  38. {
  39. static char* arg_overrides[3];
  40. static char arg_device[32];
  41. int done = 0;
  42.  
  43. #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
  44.  
  45. /* first, read /proc/cmdline into memory */
  46. char buffer[1024], *p, *q;
  47. int len;
  48. int fd = open("/proc/cmdline",O_RDONLY);
  49.  
  50. if (fd < 0) {
  51. LOGD("could not open /proc/cmdline:%s", strerror(errno));
  52. goto OpenLib;
  53. }
  54.  
  55. do {
  56. len = read(fd,buffer,sizeof(buffer)); }
  57. while (len == -1 && errno == EINTR);
  58.  
  59. if (len < 0) {
  60. LOGD("could not read /proc/cmdline:%s", strerror(errno));
  61. close(fd);
  62. goto OpenLib;
  63. }
  64. close(fd);
  65.  
  66. if (strstr(buffer, "android.qemud=") != NULL)
  67. {
  68. /* the qemud daemon is launched after rild, so
  69.   * give it some time to create its GSM socket
  70.   */
  71. int tries = 5;
  72. #define QEMUD_SOCKET_NAME "qemud"
  73. while (1) {
  74. int fd;
  75.  
  76. sleep(1);
  77.  
  78. fd = socket_local_client(
  79. QEMUD_SOCKET_NAME,
  80. ANDROID_SOCKET_NAMESPACE_RESERVED,
  81. SOCK_STREAM );
  82.  
  83. if (fd >= 0) {
  84. close(fd);
  85. snprintf( arg_device, sizeof(arg_device), "%s/%s",
  86. ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
  87.  
  88. arg_overrides[1] = "-s";
  89. arg_overrides[2] = arg_device;
  90. done = 1;
  91. break;
  92. }
  93. LOGD("could not connect to %s socket: %s",
  94. QEMUD_SOCKET_NAME, strerror(errno));
  95. if (--tries == 0)
  96. break;
  97. }
  98. if (!done) {
  99. LOGE("could not connect to %s socket (giving up): %s",
  100. QEMUD_SOCKET_NAME, strerror(errno));
  101. while(1)
  102. sleep(0x00ffffff);
  103. }
  104. }
  105.  
  106. /* otherwise, try to see if we passed a device name from the kernel */
  107. if (!done) do {
  108. #define KERNEL_OPTION "android.ril="
  109. #define DEV_PREFIX "/dev/"
  110.  
  111. p = strstr( buffer, KERNEL_OPTION );
  112. if (p == NULL)
  113. break;
  114.  
  115. p += sizeof(KERNEL_OPTION)-1;
  116. q = strpbrk( p, " \t\n\r" );
  117. if (q != NULL)
  118. *q = 0;
  119.  
  120. snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
  121. arg_device[sizeof(arg_device)-1] = 0;
  122. arg_overrides[1] = "-d";
  123. arg_overrides[2] = arg_device;
  124. done = 1;
  125.  
  126. } while (0);
  127.  
  128. if (done) {
  129. argv = arg_overrides;
  130. argc = 3;
  131. i = 1;
  132. hasLibArgs = 1;
  133. rilLibPath = REFERENCE_RIL_PATH;
  134.  
  135. LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
  136. }
  137. }
  138. OpenLib:
  139. #endif
  140. switchUser();
  141.  
  142. dlHandle = dlopen(rilLibPath, RTLD_NOW);
  143.  
  144. if (dlHandle == NULL) {
  145. fprintf(stderr, "dlopen failed: %s\n", dlerror());
  146. exit(-1);
  147.  
  148. RIL_startEventLoop();
  149.  
  150. rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
  151.  
  152. if (rilInit == NULL) {
  153. fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
  154. exit(-1);
  155. }
  156.  
  157. if (hasLibArgs) {
  158. rilArgv = argv + i - 1;
  159. argc = argc -i + 1;
  160. } else {
  161. static char * newArgv[MAX_LIB_ARGS];
  162. static char args[PROPERTY_VALUE_MAX];
  163. rilArgv = newArgv;
  164. property_get(LIB_ARGS_PROPERTY, args, "");
  165. argc = make_argv(args, rilArgv);
  166. }
  167.  
  168. // Make sure there's a reasonable argv[0]
  169. rilArgv[0] = argv[0];
  170.  
  171. funcs = rilInit(&s_rilEnv, argc, rilArgv);
  172.  
  173. RIL_register(funcs);
  174.  
  175. done:
  176.  
  177. while(1) {
  178. // sleep(UINT32_MAX) seems to return immediately on bionic
  179. sleep(0x00ffffff);
  180. }
  181. }

 

RIL_开头的结构和函数都是libril中的,我们先不管这些,从上面的main函数看来,rild并不干活,它只是把ril-lib-path的so文件载入,然后调用一下其中的RIL_Init函数,传入一下参数,然后再将RIL_Init得到的结果调用libril中的RIL_register,就进入死循环了。

我们在去看一下RIL_Init和RIL_register都是干什么的呢?

 
 
  1. /*include/telephony/ril.h*/
  2. typedef struct {
  3. int version; /* set to RIL_VERSION */
  4. RIL_RequestFunc onRequest;
  5. RIL_RadioStateRequest onStateRequest;
  6. RIL_Supports supports;
  7. RIL_Cancel onCancel;
  8. RIL_GetVersion getVersion;
  9. } RIL_RadioFunctions;
  10.  
  11. /*reference-ril/reference-ril.c*/
  12. static void onRequest (int request, void *data, size_t datalen, RIL_Token t);
  13. static RIL_RadioState currentState();
  14. static int onSupports (int requestCode);
  15. static void onCancel (RIL_Token t);
  16. static const char *getVersion();
  17.  
  18. /*** Static Variables ***/
  19. static const RIL_RadioFunctions s_callbacks = {
  20. RIL_VERSION,
  21. onRequest,
  22. currentState,
  23. onSupports,
  24. onCancel,
  25. getVersion
  26. };
  27.  
  28. const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
  29. {
  30. //blabla...
  31. return &s_callbacks;
  32. }
  33.  
  34. /*libril/ril.cpp*/
  35. extern "C" void
  36. RIL_register (const RIL_RadioFunctions *callbacks) {
  37. int ret;
  38. int flags;
  39.  
  40. if (callbacks == NULL || ((callbacks->version != RIL_VERSION)
  41. && (callbacks->version != 2))) { // Remove when partners upgrade to version 3
  42. LOGE(
  43. "RIL_register: RIL_RadioFunctions * null or invalid version"
  44. " (expected %d)", RIL_VERSION);
  45. return;
  46. }
  47. if (callbacks->version < 3) {
  48. LOGE ("RIL_register: upgrade RIL to version 3 current version=%d", callbacks->version);
  49. }
  50.  
  51. if (s_registerCalled > 0) {
  52. LOGE("RIL_register has been called more than once. "
  53. "Subsequent call ignored");
  54. return;
  55. }
  56.  
  57. memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
  58.  
  59. s_registerCalled = 1;
  60.  
  61. // Little self-check
  62.  
  63. for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
  64. assert(i == s_commands[i].requestNumber);
  65. }
  66.  
  67. for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
  68. assert(i + RIL_UNSOL_RESPONSE_BASE
  69. == s_unsolResponses[i].requestNumber);
  70. }
  71.  
  72. // New rild impl calls RIL_startEventLoop() first
  73. // old standalone impl wants it here.
  74.  
  75. if (s_started == 0) {
  76. RIL_startEventLoop();
  77. }
  78.  
  79. // start listen socket
  80.  
  81. #if 0
  82. ret = socket_local_server (SOCKET_NAME_RIL,
  83. ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
  84.  
  85. if (ret < 0) {
  86. LOGE("Unable to bind socket errno:%d", errno);
  87. exit (-1);
  88. }
  89. s_fdListen = ret;
  90.  
  91. #else
  92. s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
  93. if (s_fdListen < 0) {
  94. LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
  95. exit(-1);
  96. }
  97.  
  98. ret = listen(s_fdListen, 4);
  99.  
  100. if (ret < 0) {
  101. LOGE("Failed to listen on control socket '%d': %s",
  102. s_fdListen, strerror(errno));
  103. exit(-1);
  104. }
  105. #endif
  106.  
  107.  
  108. /* note: non-persistent so we can accept only one connection at a time */
  109. ril_event_set (&s_listen_event, s_fdListen, false,
  110. listenCallback, NULL);
  111.  
  112. rilEventAddWakeup (&s_listen_event);
  113.  
  114. #if 1
  115. // start debug interface socket
  116.  
  117. s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
  118. if (s_fdDebug < 0) {
  119. LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);
  120. exit(-1);
  121. }
  122.  
  123. ret = listen(s_fdDebug, 4);
  124.  
  125. if (ret < 0) {
  126. LOGE("Failed to listen on ril debug socket '%d': %s",
  127. s_fdDebug, strerror(errno));
  128. exit(-1);
  129. }
  130.  
  131. ril_event_set (&s_debug_event, s_fdDebug, true,
  132. debugCallback, NULL);
  133.  
  134. rilEventAddWakeup (&s_debug_event);
  135. #endif
  136.  
  137. }

看到上面三个文件的代码片段,相信大家有个大概的认识了把,vendor ril的RIL_Init函数返回的是真正干活的函数数组的指针,而libril中的RIL_register将这些函数指针存着供自己用,至于什么时候用?在RIL_register中可以看到其尝试获得rild以及rild-debug两个socket的控制socket,于是便可以得知,libril是监听这些socket的信息,然后调用传入的函数指针来处理这些信息,在ril.cpp中随处可见s_callbacks.onRequest的调用,s_callbacks就是callbacks的拷贝。

在ril.cpp的main函数的109行,我们看见这里注册了一个rild socket的listener,是函数listenCallback,这个函数就用来处理向rild发送的命令,

 
 
  1. static void listenCallback (int fd, short flags, void *param) {
  2. int ret;
  3. int err;
  4. int is_phone_socket;
  5. RecordStream *p_rs;
  6.  
  7. struct sockaddr_un peeraddr;
  8. socklen_t socklen = sizeof (peeraddr);
  9.  
  10. struct ucred creds;
  11. socklen_t szCreds = sizeof(creds);
  12.  
  13. struct passwd *pwd = NULL;
  14.  
  15. assert (s_fdCommand < 0);
  16. assert (fd == s_fdListen);
  17.  
  18. s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
  19.  
  20. if (s_fdCommand < 0 ) {
  21. LOGE("Error on accept() errno:%d", errno);
  22. /* start listening for new connections again */
  23. rilEventAddWakeup(&s_listen_event);
  24. return;
  25. }
  26.  
  27. /* check the credential of the other side and only accept socket from
  28.   * phone process
  29.   */
  30. errno = 0;
  31. is_phone_socket = 0;
  32.  
  33. err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
  34.  
  35. if (err == 0 && szCreds > 0) {
  36. errno = 0;
  37. pwd = getpwuid(creds.uid);
  38. if (pwd != NULL) {
  39. if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {
  40. is_phone_socket = 1;
  41. } else {
  42. LOGE("RILD can't accept socket from process %s", pwd->pw_name);
  43. }
  44. } else {
  45. LOGE("Error on getpwuid() errno: %d", errno);
  46. }
  47. } else {
  48. LOGD("Error on getsockopt() errno: %d", errno);
  49. }
  50.  
  51. if ( !is_phone_socket ) {
  52. LOGE("RILD must accept socket from %s", PHONE_PROCESS);
  53.  
  54. close(s_fdCommand);
  55. s_fdCommand = -1;
  56.  
  57. onCommandsSocketClosed();
  58.  
  59. /* start listening for new connections again */
  60. rilEventAddWakeup(&s_listen_event);
  61.  
  62. return;
  63. }
  64.  
  65. ret = fcntl(s_fdCommand, F_SETFL, O_NONBLOCK);
  66.  
  67. if (ret < 0) {
  68. LOGE ("Error setting O_NONBLOCK errno:%d", errno);
  69. }
  70.  
  71. LOGI("libril: new connection");
  72.  
  73. p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
  74.  
  75. ril_event_set (&s_commands_event, s_fdCommand, 1,
  76. processCommandsCallback, p_rs);
  77.  
  78. rilEventAddWakeup (&s_commands_event);
  79.  
  80. onNewCommandConnect();
  81. }
  82.  

但是仔细看这个这个函数的35行到48行,发现rild的socket并不是谁都可以连的,必须是PHONE_PROCESS才可以连接,也就是说如果是其他process通过rild socket发命令libril是不会处理,直接报错的,其实这里应该可以直接注释掉,但是为了尽量不破坏原来的代码,我就没有走这条路。向下稍微看几行就发现了debugCallback函数,在RIL_register中通过ril_event_set (&s_debug_event, s_fdDebug, true,  debugCallback, NULL);将debug socket的处理函数设定成debugCallback,观察debugCallback中的几个处理函数,发下下面几个可以用来联网的函数。

 
 
  1. case 5:
  2. LOGI("Debug port: Radio On");
  3. data = 1;
  4. issueLocalRequest(RIL_REQUEST_RADIO_POWER, &data, sizeof(int));
  5. sleep(2);
  6. // Set network selection automatic.
  7. issueLocalRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, NULL, 0);
  8. break;
  9. case 6:
  10. LOGI("Debug port: Setup Data Call, Apn :%s\n", args[1]);
  11. actData[0] = args[1];
  12. issueLocalRequest(RIL_REQUEST_SETUP_DATA_CALL, &actData,
  13. sizeof(actData));
  14. break;
  15. case 7:
  16. LOGI("Debug port: Deactivate Data Call");
  17. issueLocalRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, &deactData,
  18. sizeof(deactData));
  19. break;
  20.  

Radio on是将radio模块激活,Setup Data Call就是建立数据连接(gprs,td,wcdma之类的),有这两个功能的话就可以保证连上网了。

其实看到debugCallback的处理函数,我感到很眼熟,为什么呢?因为在rild的文件夹中有一个radiooptions.c的程序,这个程序的用法是这样的

 
 
  1. static void print_usage() {
  2. perror("Usage: radiooptions [option] [extra_socket_args]\n\
  3. 0 - RADIO_RESET, \n\
  4. 1 - RADIO_OFF, \n\
  5. 2 - UNSOL_NETWORK_STATE_CHANGE, \n\
  6. 3 - QXDM_ENABLE, \n\
  7. 4 - QXDM_DISABLE, \n\
  8. 5 - RADIO_ON, \n\
  9. 6 apn- SETUP_PDP apn, \n\
  10. 7 - DEACTIVE_PDP, \n\
  11. 8 number - DIAL_CALL number, \n\
  12. 9 - ANSWER_CALL, \n\
  13. 10 - END_CALL \n");
  14. }
  15.  
  16.  

这样就正好对应上了,radiooptions程序就是官方用来调试ril模块的一个小程序,debugCallback就是在libril中给这个小程序开的“后门”。

于是事情就好办了,前面的一切工作似乎都是白费的,只要调用几下radiooptions不久好了么?

转自:http://yangyangzhao.blog.163.com/blog/static/175816366201011542451166/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android RIL(无线射频接口层)模块是运行在Android手机系统上的一层软件模块,它作为通信协议栈和硬件之间的桥梁,提供了与移动通信网络的通信功能。RIL模块主要负责处理与手机基带芯片的通信,管理移动网络连接以及处理移动通信相关功能。 RIL模块的主要职责包括: 1. 处理与基带芯片的通信:RIL模块通过与基带芯片之间的通信接口,实现对基带芯片的控制和管理,包括进行移动网络的注册、鉴权和密钥协商等。 2. 管理移动网络连接:RIL模块负责与移动网络建立通信连接,包括拨号、发送和接收数据等相关操作。它能够实现与移动网络的通信功能,如发送和接收短信、接听和拨打电话以及访问互联网等。 3. 实现SIM卡管理:RIL模块管理与SIM卡之间的通信,包括识别和读取SIM卡中的相关信息,如号码、短信、联系人等。它能够处理与SIM卡相关的操作,如读取SIM卡中的联系人、发送和接收短信等。 4. 处理通话和短信功能:RIL模块能够实现电话的呼叫功能,包括呼出、接听、挂断等。同时,它还能够处理短信的发送和接收,包括编码和解码等操作。 总之,Android RIL模块Android系统中的一个重要软件模块,它为手机提供了与移动通信网络的连接和通信功能。通过与基带芯片的交互,RIL模块能够实现与移动网络的通信、管理移动网络连接、处理SIM卡相关操作以及实现电话和短信功能等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值