Android RIL模块非启动界面联网实战(一)

原文地址::http://yangyangzhao.blog.163.com/blog/static/175816366201011542451166/

 

在上一篇博文中我讲了如何在Android中不启动界面连接wifi,在这篇博文中我将讲如何不启动界面连接手机网络。

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不久好了么?

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值