Android 电话系统框架介绍

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

1.SolicitedResponse:ApBp发送请求,BpAp发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:

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

[plain] view plain copy
  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},
[plain] view plain copy
  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.unSolicitedResponse:Bp主动给Ap发送事件,该类型的AT指令及其回调函数以数组的形式存放在ril_unsol_commands.h文件中:

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

[plain] view plain copy
  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},
[plain] view plain copy
  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命令不完全相同,为了保密,APBP之间通过各厂商自己的相关动态库来通信。

RIL模块由rild守护进程、libril.solibrefrence.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 plain copy
  1. serviceril-daemon/system/bin/rild
  2. classmain
  3. socketrildstream660rootradio
  4. socketrild-debugstream660radiosystem
  5. userroot
  6. groupradiocacheinetmiscaudiosdcard_rwlog
[plain] view plain copy
  1. serviceril-daemon/system/bin/rild
  2. classmain
  3. socketrildstream660rootradio
  4. socketrild-debugstream660radiosystem
  5. userroot
  6. groupradiocacheinetmiscaudiosdcard_rwlog

RILD进程入口函数分析

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

hardware\ril\rild\rild.c

[cpp] view plain copy
  1. intmain(intargc,char**argv)
  2. {
  3. constchar*rilLibPath=NULL;
  4. char**rilArgv;
  5. void*dlHandle;
  6. constRIL_RadioFunctions*(*rilInit)(conststructRIL_Env*,int,char**);
  7. constRIL_RadioFunctions*funcs;
  8. charlibPath[PROPERTY_VALUE_MAX];
  9. unsignedcharhasLibArgs=0;
  10. inti;
  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. }elseif(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. gotodone;
  29. }else{
  30. rilLibPath=libPath;
  31. }
  32.   }
  33. ##################################################################################
  34. 判断是否为模拟器
  35. ##################################################################################
  36. #if1
  37. {
  38. staticchar*arg_overrides[3];
  39. staticchararg_device[32];
  40. intdone=0;
  41. #defineREFERENCE_RIL_PATH"/system/lib/libreference-ril.so"
  42. /*first,read/proc/cmdlineintomemory*/
  43. charbuffer[1024],*p,*q;
  44. intlen;
  45. intfd=open("/proc/cmdline",O_RDONLY);
  46. if(fd<0){
  47. LOGD("couldnotopen/proc/cmdline:%s",strerror(errno));
  48. gotoOpenLib;
  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("couldnotread/proc/cmdline:%s",strerror(errno));
  56. close(fd);
  57. gotoOpenLib;
  58. }
  59. close(fd);
  60. //判断是否为模拟器,对于真机,此处条件为false
  61. if(strstr(buffer,"android.qemud=")!=NULL)
  62. {
  63. inttries=5;
  64. #defineQEMUD_SOCKET_NAME"qemud"
  65. while(1){
  66. intfd;
  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("couldnotconnectto%ssocket:%s",QEMUD_SOCKET_NAME,strerror(errno));
  81. if(--tries==0)
  82. break;
  83. }
  84. if(!done){
  85. LOGE("couldnotconnectto%ssocket(givingup):%s",
  86. QEMUD_SOCKET_NAME,strerror(errno));
  87. while(1)
  88. sleep(0x00ffffff);
  89. }
  90. }
  91. /*otherwise,trytoseeifwepassedadevicenamefromthekernel*/
  92. if(!done)do{//true
  93. #defineKERNEL_OPTION"android.ril="
  94. #defineDEV_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("overridingwith%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,"dlopenfailed:%s\n",dlerror());
  128. exit(-1);
  129.   }
  130.   //<spanstyle="color:rgb(0,128,0);line-height:1.5;font-family:'CourierNew';white-space:pre-wrap;">创建客户端事件监听线程</span>
  131.   ②RIL_startEventLoop();
  132.   //<spanstyle="color:rgb(0,128,0);line-height:1.5;font-family:'CourierNew';white-space:pre-wrap;">通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针</span>
  133. ③rilInit=(constRIL_RadioFunctions*(*)(conststructRIL_Env*,int,char**))dlsym(dlHandle,"RIL_Init");
  134. if(rilInit==NULL){
  135. fprintf(stderr,"RIL_Initnotdefinedorexportedin%s\n",rilLibPath);
  136. exit(-1);
  137. }
  138. if(hasLibArgs){//false
  139. rilArgv=argv+i-1;
  140. argc=argc-i+1;
  141. }else{
  142. staticchar*newArgv[MAX_LIB_ARGS];
  143. staticcharargs[PROPERTY_VALUE_MAX];
  144. rilArgv=newArgv;
  145. property_get(LIB_ARGS_PROPERTY,args,"");//通过属性系统读取"rild.libargs"属性值
  146. argc=make_argv(args,rilArgv);
  147. }
  148. //Makesurethere'sareasonableargv[0]
  149.   rilArgv[0]=argv[0];
  150.   //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
  151.   ④funcs=rilInit(&s_rilEnv,argc,rilArgv);
  152.   //<spanstyle="color:rgb(0,128,0);line-height:1.5;font-family:'CourierNew';white-space:pre-wrap;">注册客户端事件处理接口</span><spanstyle="color:rgb(0,128,0);font-family:'CourierNew';line-height:1.5;white-space:pre-wrap;">RIL_RadioFunctions</span><spanstyle="color:rgb(0,128,0);line-height:1.5;font-family:'CourierNew';white-space:pre-wrap;">,并创建socket监听事件</span>
  153. ⑤RIL_register(funcs);
  154. done:
  155. while(1){
  156. //sleep(UINT32_MAX)seemstoreturnimmediatelyonbionic
  157. sleep(0x00ffffff);
  158. }
  159. }
[cpp] view plain copy
  1. intmain(intargc,char**argv)
  2. {
  3. constchar*rilLibPath=NULL;
  4. char**rilArgv;
  5. void*dlHandle;
  6. constRIL_RadioFunctions*(*rilInit)(conststructRIL_Env*,int,char**);
  7. constRIL_RadioFunctions*funcs;
  8. charlibPath[PROPERTY_VALUE_MAX];
  9. unsignedcharhasLibArgs=0;
  10. inti;
  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. }elseif(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. gotodone;
  29. }else{
  30. rilLibPath=libPath;
  31. }
  32.   }
  33. ##################################################################################
  34. 判断是否为模拟器
  35. ##################################################################################
  36. #if1
  37. {
  38. staticchar*arg_overrides[3];
  39. staticchararg_device[32];
  40. intdone=0;
  41. #defineREFERENCE_RIL_PATH"/system/lib/libreference-ril.so"
  42. /*first,read/proc/cmdlineintomemory*/
  43. charbuffer[1024],*p,*q;
  44. intlen;
  45. intfd=open("/proc/cmdline",O_RDONLY);
  46. if(fd<0){
  47. LOGD("couldnotopen/proc/cmdline:%s",strerror(errno));
  48. gotoOpenLib;
  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("couldnotread/proc/cmdline:%s",strerror(errno));
  56. close(fd);
  57. gotoOpenLib;
  58. }
  59. close(fd);
  60. //判断是否为模拟器,对于真机,此处条件为false
  61. if(strstr(buffer,"android.qemud=")!=NULL)
  62. {
  63. inttries=5;
  64. #defineQEMUD_SOCKET_NAME"qemud"
  65. while(1){
  66. intfd;
  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("couldnotconnectto%ssocket:%s",QEMUD_SOCKET_NAME,strerror(errno));
  81. if(--tries==0)
  82. break;
  83. }
  84. if(!done){
  85. LOGE("couldnotconnectto%ssocket(givingup):%s",
  86. QEMUD_SOCKET_NAME,strerror(errno));
  87. while(1)
  88. sleep(0x00ffffff);
  89. }
  90. }
  91. /*otherwise,trytoseeifwepassedadevicenamefromthekernel*/
  92. if(!done)do{//true
  93. #defineKERNEL_OPTION"android.ril="
  94. #defineDEV_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("overridingwith%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,"dlopenfailed:%s\n",dlerror());
  128. exit(-1);
  129.   }
  130.   //<spanstyle="font-family:'CourierNew';color:#080000;line-height:1.5;white-space:pre-wrap;">创建客户端事件监听线程</span>
  131.   ②RIL_startEventLoop();
  132.   //<spanstyle="font-family:'CourierNew';color:#080000;line-height:1.5;white-space:pre-wrap;">通过dlsym定位到RIL_Init函数的地址,并且强制转换为RIL_RadioFunctions的函数指针</span>
  133. ③rilInit=(constRIL_RadioFunctions*(*)(conststructRIL_Env*,int,char**))dlsym(dlHandle,"RIL_Init");
  134. if(rilInit==NULL){
  135. fprintf(stderr,"RIL_Initnotdefinedorexportedin%s\n",rilLibPath);
  136. exit(-1);
  137. }
  138. if(hasLibArgs){//false
  139. rilArgv=argv+i-1;
  140. argc=argc-i+1;
  141. }else{
  142. staticchar*newArgv[MAX_LIB_ARGS];
  143. staticcharargs[PROPERTY_VALUE_MAX];
  144. rilArgv=newArgv;
  145. property_get(LIB_ARGS_PROPERTY,args,"");//通过属性系统读取"rild.libargs"属性值
  146. argc=make_argv(args,rilArgv);
  147. }
  148. //Makesurethere'sareasonableargv[0]
  149.   rilArgv[0]=argv[0];
  150.   //调用RIL_Init函数来初始化rild,传入参数s_rilEnv,返回RIL_RadioFunctions地址
  151.   ④funcs=rilInit(&s_rilEnv,argc,rilArgv);
  152.   //<spanstyle="font-family:'CourierNew';color:#080000;line-height:1.5;white-space:pre-wrap;">注册客户端事件处理接口</span><spanstyle="font-family:'CourierNew';color:#080000;line-height:1.5;white-space:pre-wrap;">RIL_RadioFunctions</span><spanstyle="font-family:'CourierNew';color:#080000;line-height:1.5;white-space:pre-wrap;">,并创建socket监听事件</span>
  153. ⑤RIL_register(funcs);
  154. done:
  155. while(1){
  156. //sleep(UINT32_MAX)seemstoreturnimmediatelyonbionic
  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 plain copy
  1. extern"C"voidRIL_startEventLoop(void){
  2. intret;
  3. pthread_attr_tattr;
  4. /*spinupeventLoopthreadandwaitforittogetstarted*/
  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("Failedtocreatedispatchthreaderrno:%d",errno);
  18. return;
  19. }
  20. }
[cpp] view plain copy
  1. extern"C"voidRIL_startEventLoop(void){
  2. intret;
  3. pthread_attr_tattr;
  4. /*spinupeventLoopthreadandwaitforittogetstarted*/
  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("Failedtocreatedispatchthreaderrno:%d",errno);
  18. return;
  19. }
  20. }
eventLoop执行时序图:


[cpp] view plain copy
  1. staticvoid*eventLoop(void*param){
  2. intret;
  3. intfiledes[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("Errorinpipe()errno:%d",errno);
  13. returnNULL;
  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. //Onlyreturnsonerror
  25. ②ril_event_loop();
  26. LOGE("errorinevent_loop_baseerrno:%d",errno);
  27. returnNULL;
  28. }
[cpp] view plain copy
  1. staticvoid*eventLoop(void*param){
  2. intret;
  3. intfiledes[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("Errorinpipe()errno:%d",errno);
  13. returnNULL;
  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. //Onlyreturnsonerror
  25. ②ril_event_loop();
  26. LOGE("errorinevent_loop_baseerrno:%d",errno);
  27. returnNULL;
  28. }
在rild中定义了event的概念,Rild 支持两种类型的事件:

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

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

事件定义如下: [cpp] view plain copy
  1. structril_event{
  2. structril_event*next;
  3. structril_event*prev;
  4. intfd;//文件句柄
  5. intindex;//该事件在监控表中的索引
  6. boolpersist;//如果是保持的,则不从watch_list中删除
  7. structtimevaltimeout;//任务执行时间
  8. ril_event_cbfunc;//回调事件处理函数
  9. void*param;//回调时参数
  10. };
[cpp] view plain copy
  1. structril_event{
  2. structril_event*next;
  3. structril_event*prev;
  4. intfd;//文件句柄
  5. intindex;//该事件在监控表中的索引
  6. boolpersist;//如果是保持的,则不从watch_list中删除
  7. structtimevaltimeout;//任务执行时间
  8. ril_event_cbfunc;//回调事件处理函数
  9. void*param;//回调时参数
  10. };

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

[cpp] view plain copy
  1. staticstructril_events_commands_event;
  2. ril_event_set(&s_commands_event,s_fdCommand,1,processCommandsCallback,p_rs)
  3. staticstructril_events_wakeupfd_event;
  4. ril_event_set(&s_wakeupfd_event,s_fdWakeupRead,true,processWakeupCallback,NULL)
  5. staticstructril_events_listen_event;
  6. ril_event_set(&s_listen_event,s_fdListen,false,listenCallback,NULL)
  7. staticstructril_events_wake_timeout_event;
  8. ril_timer_add(&(p_info->event),&myRelativeTime);
[cpp] view plain copy
  1. staticstructril_events_commands_event;
  2. ril_event_set(&s_commands_event,s_fdCommand,1,processCommandsCallback,p_rs)
  3. staticstructril_events_wakeupfd_event;
  4. ril_event_set(&s_wakeupfd_event,s_fdWakeupRead,true,processWakeupCallback,NULL)
  5. staticstructril_events_listen_event;
  6. ril_event_set(&s_listen_event,s_fdListen,false,listenCallback,NULL)
  7. staticstructril_events_wake_timeout_event;
  8. ril_timer_add(&(p_info->event),&myRelativeTime);
[cpp] view plain copy
  1. staticstructril_events_debug_event;
  2. ril_event_set(&s_debug_event,s_fdDebug,true,debugCallback,NULL)
[cpp] view plain copy
  1. staticstructril_events_debug_event;
  2. ril_event_set(&s_debug_event,s_fdDebug,true,debugCallback,NULL)

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

/事件监控队列

staticstructril_event*watch_table[MAX_FD_EVENTS];

//定时事件队列

staticstructril_eventtimer_list;

//处理事件队列

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


添加事件

1.添加 Wakeup 事件 [cpp] view plain copy
  1. staticvoidrilEventAddWakeup(structril_event*ev){
  2. ril_event_add(ev);//向监控表watch_table添加一个s_wakeupfd_event事件
  3. triggerEvLoop();//向管道s_fdWakeupWrite中写入之来触发事件循环
  4. }
[cpp] view plain copy
  1. staticvoidrilEventAddWakeup(structril_event*ev){
  2. ril_event_add(ev);//向监控表watch_table添加一个s_wakeupfd_event事件
  3. triggerEvLoop();//向管道s_fdWakeupWrite中写入之来触发事件循环
  4. }

[cpp] view plain copy
  1. voidril_event_add(structril_event*ev)
  2. {
  3. dlog("~~~~+ril_event_add~~~~");
  4. MUTEX_ACQUIRE();
  5. for(inti=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("~~~~addedat%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. }
[cpp] view plain copy
  1. voidril_event_add(structril_event*ev)
  2. {
  3. dlog("~~~~+ril_event_add~~~~");
  4. MUTEX_ACQUIRE();
  5. for(inti=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("~~~~addedat%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 plain copy
  1. voidril_timer_add(structril_event*ev,structtimeval*tv)
  2. {
  3. dlog("~~~~+ril_timer_add~~~~");
  4. MUTEX_ACQUIRE();
  5. structril_event*list;
  6. if(tv!=NULL){
  7. list=timer_list.next;
  8. ev->fd=-1;//makesurefdisinvalid
  9. structtimevalnow;
  10. getNow(&now);
  11. timeradd(&now,tv,&ev->timeout);
  12. //keeplistsorted
  13. while(timercmp(&list->timeout,&ev->timeout,<)&&(list!=&timer_list)){
  14. list=list->next;
  15. }
  16. //listnowpointstothefirsteventolderthanev
  17. addToList(ev,list);
  18. }
  19. MUTEX_RELEASE();
  20. dlog("~~~~-ril_timer_add~~~~");
  21. }
[cpp] view plain copy
  1. voidril_timer_add(structril_event*ev,structtimeval*tv)
  2. {
  3. dlog("~~~~+ril_timer_add~~~~");
  4. MUTEX_ACQUIRE();
  5. structril_event*list;
  6. if(tv!=NULL){
  7. list=timer_list.next;
  8. ev->fd=-1;//makesurefdisinvalid
  9. structtimevalnow;
  10. getNow(&now);
  11. timeradd(&now,tv,&ev->timeout);
  12. //keeplistsorted
  13. while(timercmp(&list->timeout,&ev->timeout,<)&&(list!=&timer_list)){
  14. list=list->next;
  15. }
  16. //listnowpointstothefirsteventolderthanev
  17. addToList(ev,list);
  18. }
  19. MUTEX_RELEASE();
  20. dlog("~~~~-ril_timer_add~~~~");
  21. }

触发事件

[cpp] view plain copy
  1. staticvoidtriggerEvLoop(){
  2. intret;
  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 plain copy
  1. staticvoidtriggerEvLoop(){
  2. intret;
  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 plain copy
  1. voidril_event_loop()
  2. {
  3. intn;
  4. fd_setrfds;
  5. structtimevaltv;
  6. structtimeval*ptv;
  7. for(;;){
  8. memcpy(&rfds,&readFds,sizeof(fd_set));
  9. if(-1==calcNextTimeout(&tv)){
  10. dlog("~~~~notimers;blockingindefinitely~~~~");
  11. ptv=NULL;
  12. }else{
  13. dlog("~~~~blockingfor%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("~~~~%deventsfired~~~~",n);
  21. if(n<0){
  22. if(errno==EINTR)continue;
  23. LOGE("ril_event:selecterror(%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. }
[cpp] view plain copy
  1. voidril_event_loop()
  2. {
  3. intn;
  4. fd_setrfds;
  5. structtimevaltv;
  6. structtimeval*ptv;
  7. for(;;){
  8. memcpy(&rfds,&readFds,sizeof(fd_set));
  9. if(-1==calcNextTimeout(&tv)){
  10. dlog("~~~~notimers;blockingindefinitely~~~~");
  11. ptv=NULL;
  12. }else{
  13. dlog("~~~~blockingfor%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("~~~~%deventsfired~~~~",n);
  21. if(n<0){
  22. if(errno==EINTR)continue;
  23. LOGE("ril_event:selecterror(%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 plain copy
  1. staticvoidprocessTimeouts()
  2. {
  3. dlog("~~~~+processTimeouts~~~~");
  4. MUTEX_ACQUIRE();
  5. structtimevalnow;
  6. structril_event*tev=timer_list.next;
  7. structril_event*next;
  8. getNow(&now);//获取当前时间
  9.   dlog("~~~~Lookingfortimers<=%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("~~~~firingtimer~~~~");
  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. }
[cpp] view plain copy
  1. staticvoidprocessTimeouts()
  2. {
  3. dlog("~~~~+processTimeouts~~~~");
  4. MUTEX_ACQUIRE();
  5. structtimevalnow;
  6. structril_event*tev=timer_list.next;
  7. structril_event*next;
  8. getNow(&now);//获取当前时间
  9.   dlog("~~~~Lookingfortimers<=%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("~~~~firingtimer~~~~");
  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 plain copy
  1. staticvoidprocessReadReadies(fd_set*rfds,intn)
  2. {
  3. dlog("~~~~+processReadReadies(%d)~~~~",n);
  4.   MUTEX_ACQUIRE();
  5.   //遍历watch_table数组,根据select返回的句柄n查找对应的事件
  6. for(inti=0;(i<MAX_FD_EVENTS)&&(n>0);i++){
  7. structril_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. }
[cpp] view plain copy
  1. staticvoidprocessReadReadies(fd_set*rfds,intn)
  2. {
  3. dlog("~~~~+processReadReadies(%d)~~~~",n);
  4.   MUTEX_ACQUIRE();
  5.   //遍历watch_table数组,根据select返回的句柄n查找对应的事件
  6. for(inti=0;(i<MAX_FD_EVENTS)&&(n>0);i++){
  7. structril_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 plain copy
  1. staticvoidfirePending()
  2. {
  3. dlog("~~~~+firePending~~~~");
  4. structril_event*ev=pending_list.next;
  5. while(ev!=&pending_list){//遍历pending_list链表,处理链表中的所有事件
  6. structril_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. }
[cpp] view plain copy
  1. staticvoidfirePending()
  2. {
  3. dlog("~~~~+firePending~~~~");
  4. structril_event*ev=pending_list.next;
  5. while(ev!=&pending_list){//遍历pending_list链表,处理链表中的所有事件
  6. structril_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 plain copy
  1. structRIL_Env{
  2. //动态库完成请求后通知处理结果的接口
  3.   void(*OnRequestComplete)(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen);
  4. //动态库unSolicitedResponse通知接口
  5.   void(*OnUnsolicitedResponse)(intunsolResponse,constvoid*data,size_tdatalen);
  6. //向Rild提交一个超时任务的接口
  7. void(*RequestTimedCallback)(RIL_TimedCallbackcallback,void*param,conststructtimeval*relativeTime);
  8. };
[cpp] view plain copy
  1. structRIL_Env{
  2. //动态库完成请求后通知处理结果的接口
  3.   void(*OnRequestComplete)(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen);
  4. //动态库unSolicitedResponse通知接口
  5.   void(*OnUnsolicitedResponse)(intunsolResponse,constvoid*data,size_tdatalen);
  6. //向Rild提交一个超时任务的接口
  7. void(*RequestTimedCallback)(RIL_TimedCallbackcallback,void*param,conststructtimeval*relativeTime);
  8. };

hardware\ril\rild\rild.c

s_rilEnv变量定义:

[cpp] view plain copy
  1. staticstructRIL_Envs_rilEnv={
  2. RIL_onRequestComplete,
  3. RIL_onUnsolicitedResponse,
  4. RIL_requestTimedCallback
  5. };
[cpp] view plain copy
  1. staticstructRIL_Envs_rilEnv={
  2. RIL_onRequestComplete,
  3. RIL_onUnsolicitedResponse,
  4. RIL_requestTimedCallback
  5. };

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

1.RIL_onRequestComplete

[cpp] view plain copy
  1. extern"C"voidRIL_onRequestComplete(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen){
  2. RequestInfo*pRI;
  3. intret;
  4. size_terrorOffset;
  5. pRI=(RequestInfo*)t;
  6. if(!checkAndDequeueRequestInfo(pRI)){
  7. LOGE("RIL_onRequestComplete:invalidRIL_Token");
  8. return;
  9. }
  10. if(pRI->local>0){
  11. //Locallyissuedcommand...voidonly!
  12. //responsedoesnotgobackupthecommandsocket
  13. LOGD("C[locl]<%s",requestToString(pRI->pCI->requestNumber));
  14. gotodone;
  15. }
  16. appendPrintBuf("[%04d]<%s",pRI->token,requestToString(pRI->pCI->requestNumber));
  17. if(pRI->cancelled==0){
  18. Parcelp;
  19. p.writeInt32(RESPONSE_SOLICITED);
  20. p.writeInt32(pRI->token);
  21. errorOffset=p.dataPosition();
  22. p.writeInt32(e);
  23. if(response!=NULL){
  24. //thereisaresponsepayload,nomattersuccessornot.
  25. ret=pRI->pCI->responseFunction(p,response,responselen);
  26. /*ifanerroroccurred,rewindandmarkit*/
  27. if(ret!=0){
  28. p.setDataPosition(errorOffset);
  29. p.writeInt32(ret);
  30. }
  31. }
  32. if(e!=RIL_E_SUCCESS){
  33. appendPrintBuf("%sfailsby%s",printBuf,failCauseToString(e));
  34. }
  35. if(s_fdCommand<0){
  36. LOGD("RILonRequestComplete:Commandchannelclosed");
  37. }
  38. sendResponse(p);
  39. }
  40. done:
  41. free(pRI);
  42. }
[cpp] view plain copy
  1. extern"C"voidRIL_onRequestComplete(RIL_Tokent,RIL_Errnoe,void*response,size_tresponselen){
  2. RequestInfo*pRI;
  3. intret;
  4. size_terrorOffset;
  5. pRI=(RequestInfo*)t;
  6. if(!checkAndDequeueRequestInfo(pRI)){
  7. LOGE("RIL_onRequestComplete:invalidRIL_Token");
  8. return;
  9. }
  10. if(pRI->local>0){
  11. //Locallyissuedcommand...voidonly!
  12. //responsedoesnotgobackupthecommandsocket
  13. LOGD("C[locl]<%s",requestToString(pRI->pCI->requestNumber));
  14. gotodone;
  15. }
  16. appendPrintBuf("[%04d]<%s",pRI->token,requestToString(pRI->pCI->requestNumber));
  17. if(pRI->cancelled==0){
  18. Parcelp;
  19. p.writeInt32(RESPONSE_SOLICITED);
  20. p.writeInt32(pRI->token);
  21. errorOffset=p.dataPosition();
  22. p.writeInt32(e);
  23. if(response!=NULL){
  24. //thereisaresponsepayload,nomattersuccessornot.
  25. ret=pRI->pCI->responseFunction(p,response,responselen);
  26. /*ifanerroroccurred,rewindandmarkit*/
  27. if(ret!=0){
  28. p.setDataPosition(errorOffset);
  29. p.writeInt32(ret);
  30. }
  31. }
  32. if(e!=RIL_E_SUCCESS){
  33. appendPrintBuf("%sfailsby%s",printBuf,failCauseToString(e));
  34. }
  35. if(s_fdCommand<0){
  36. LOGD("RILonRequestComplete:Commandchannelclosed");
  37. }
  38. sendResponse(p);
  39. }
  40. done:
  41. free(pRI);
  42. }

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

2.RIL_onUnsolicitedResponse

[cpp] view plain copy
  1. extern"C"voidRIL_onUnsolicitedResponse(intunsolResponse,void*data,
  2. size_tdatalen)
  3. {
  4. intunsolResponseIndex;
  5. intret;
  6. int64_ttimeReceived=0;
  7. boolshouldScheduleTimeout=false;
  8. if(s_registerCalled==0){
  9. //IgnoreRIL_onUnsolicitedResponsebeforeRIL_register
  10. LOGW("RIL_onUnsolicitedResponsecalledbeforeRIL_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("unsupportedunsolicitedresponsecode%d",unsolResponse);
  17. return;
  18. }
  19. //Grabawakelockifneededforthisreponse,
  20. //asweexitwe'lleitherreleaseitimmediately
  21. //orsetatimertoreleaseitlater.
  22. switch(s_unsolResponses[unsolResponseIndex].wakeType){
  23. caseWAKE_PARTIAL:
  24. grabPartialWakeLock();
  25. shouldScheduleTimeout=true;
  26. break;
  27. caseDONT_WAKE:
  28. default:
  29. //Nowakelockisgrabedsodon'tsettimeout
  30. shouldScheduleTimeout=false;
  31. break;
  32. }
  33. //Markthetimethiswasreceived,doingthis
  34. //aftergrabingthewakelockincasegetting
  35. //theelapsedRealTimemightcauseustogoto
  36. //sleep.
  37. if(unsolResponse==RIL_UNSOL_NITZ_TIME_RECEIVED){
  38. timeReceived=elapsedRealtime();
  39. }
  40. appendPrintBuf("[UNSL]<%s",requestToString(unsolResponse));
  41. Parcelp;
  42. p.writeInt32(RESPONSE_UNSOLICITED);
  43. p.writeInt32(unsolResponse);
  44. ret=s_unsolResponses[unsolResponseIndex].responseFunction(p,data,datalen);
  45. if(ret!=0){
  46. //Problemwiththeresponse.Don'tcontinue;
  47. gotoerror_exit;
  48. }
  49. //somethingsgetmorepayload
  50. switch(unsolResponse){
  51. caseRIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
  52. p.writeInt32(s_callbacks.onStateRequest());
  53. appendPrintBuf("%s{%s}",printBuf,
  54. radioStateToString(s_callbacks.onStateRequest()));
  55. break;
  56. caseRIL_UNSOL_NITZ_TIME_RECEIVED:
  57. //Storethetimethatthiswasreceivedsothe
  58. //handlerofthismessagecanaccountfor
  59. //thetimeittakestoarriveandprocess.In
  60. //particularthesystemhasbeenknowntosleep
  61. //beforethismessagecanbeprocessed.
  62. p.writeInt64(timeReceived);
  63. break;
  64. }
  65. ret=sendResponse(p);
  66. if(ret!=0&&unsolResponse==RIL_UNSOL_NITZ_TIME_RECEIVED){
  67. //Unfortunately,NITZtimeisnotpoll/updatelikeeverything
  68. //elseinthesystem.So,iftheupstreamclientisn'tconnected,
  69. //keepacopyofthelastNITZresponse(withreceivetimenoted
  70. //above)aroundsowecandeliveritwhenitisconnected
  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. //Fornow,weautomaticallygobacktosleepafterTIMEVAL_WAKE_TIMEOUT
  80. //FIXMEThejavacodeshouldhandshakeheretoreleasewakelock
  81. if(shouldScheduleTimeout){
  82. //Cancelthepreviousrequest
  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. }
[cpp] view plain copy
  1. extern"C"voidRIL_onUnsolicitedResponse(intunsolResponse,void*data,
  2. size_tdatalen)
  3. {
  4. intunsolResponseIndex;
  5. intret;
  6. int64_ttimeReceived=0;
  7. boolshouldScheduleTimeout=false;
  8. if(s_registerCalled==0){
  9. //IgnoreRIL_onUnsolicitedResponsebeforeRIL_register
  10. LOGW("RIL_onUnsolicitedResponsecalledbeforeRIL_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("unsupportedunsolicitedresponsecode%d",unsolResponse);
  17. return;
  18. }
  19. //Grabawakelockifneededforthisreponse,
  20. //asweexitwe'lleitherreleaseitimmediately
  21. //orsetatimertoreleaseitlater.
  22. switch(s_unsolResponses[unsolResponseIndex].wakeType){
  23. caseWAKE_PARTIAL:
  24. grabPartialWakeLock();
  25. shouldScheduleTimeout=true;
  26. break;
  27. caseDONT_WAKE:
  28. default:
  29. //Nowakelockisgrabedsodon'tsettimeout
  30. shouldScheduleTimeout=false;
  31. break;
  32. }
  33. //Markthetimethiswasreceived,doingthis
  34. //aftergrabingthewakelockincasegetting
  35. //theelapsedRealTimemightcauseustogoto
  36. //sleep.
  37. if(unsolResponse==RIL_UNSOL_NITZ_TIME_RECEIVED){
  38. timeReceived=elapsedRealtime();
  39. }
  40. appendPrintBuf("[UNSL]<%s",requestToString(unsolResponse));
  41. Parcelp;
  42. p.writeInt32(RESPONSE_UNSOLICITED);
  43. p.writeInt32(unsolResponse);
  44. ret=s_unsolResponses[unsolResponseIndex].responseFunction(p,data,datalen);
  45. if(ret!=0){
  46. //Problemwiththeresponse.Don'tcontinue;
  47. gotoerror_exit;
  48. }
  49. //somethingsgetmorepayload
  50. switch(unsolResponse){
  51. caseRIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
  52. p.writeInt32(s_callbacks.onStateRequest());
  53. appendPrintBuf("%s{%s}",printBuf,
  54. radioStateToString(s_callbacks.onStateRequest()));
  55. break;
  56. caseRIL_UNSOL_NITZ_TIME_RECEIVED:
  57. //Storethetimethatthiswasreceivedsothe
  58. //handlerofthismessagecanaccountfor
  59. //thetimeittakestoarriveandprocess.In
  60. //particularthesystemhasbeenknowntosleep
  61. //beforethismessagecanbeprocessed.
  62. p.writeInt64(timeReceived);
  63. break;
  64. }
  65. ret=sendResponse(p);
  66. if(ret!=0&&unsolResponse==RIL_UNSOL_NITZ_TIME_RECEIVED){
  67. //Unfortunately,NITZtimeisnotpoll/updatelikeeverything
  68. //elseinthesystem.So,iftheupstreamclientisn'tconnected,
  69. //keepacopyofthelastNITZresponse(withreceivetimenoted
  70. //above)aroundsowecandeliveritwhenitisconnected
  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. //Fornow,weautomaticallygobacktosleepafterTIMEVAL_WAKE_TIMEOUT
  80. //FIXMEThejavacodeshouldhandshakeheretoreleasewakelock
  81. if(shouldScheduleTimeout){
  82. //Cancelthepreviousrequest
  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 plain copy
  1. extern"C"voidRIL_requestTimedCallback(RIL_TimedCallbackcallback,void*param,
  2. conststructtimeval*relativeTime){
  3. internalRequestTimedCallback(callback,param,relativeTime);
  4. }
[cpp] view plain copy
  1. extern"C"voidRIL_requestTimedCallback(RIL_TimedCallbackcallback,void*param,
  2. conststructtimeval*relativeTime){
  3. internalRequestTimedCallback(callback,param,relativeTime);
  4. }

[cpp] view plain copy
  1. staticUserCallbackInfo*internalRequestTimedCallback(RIL_TimedCallbackcallback,void*param,
  2. conststructtimeval*relativeTime)
  3. {
  4. structtimevalmyRelativeTime;
  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. /*treatnullparameterasa0relativetime*/
  11. memset(&myRelativeTime,0,sizeof(myRelativeTime));
  12. }else{
  13. /*FIXMEIthinkevent_add'stvparamisreallyconstanyway*/
  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. returnp_info;
  20. }
[cpp] view plain copy
  1. staticUserCallbackInfo*internalRequestTimedCallback(RIL_TimedCallbackcallback,void*param,
  2. conststructtimeval*relativeTime)
  3. {
  4. structtimevalmyRelativeTime;
  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. /*treatnullparameterasa0relativetime*/
  11. memset(&myRelativeTime,0,sizeof(myRelativeTime));
  12. }else{
  13. /*FIXMEIthinkevent_add'stvparamisreallyconstanyway*/
  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. returnp_info;
  20. }

RIL_RadioFunctions定义

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

hardware\ril\include\telephony\Ril.h

[cpp] view plain copy
  1. typedefstruct{
  2. intversion;//Rild版本
  3. RIL_RequestFunconRequest;//AP请求接口
  4. RIL_RadioStateRequestonStateRequest;//BP状态查询
  5. RIL_Supportssupports;
  6. RIL_CancelonCancel;
  7. RIL_GetVersiongetVersion;//动态库版本
  8. }RIL_RadioFunctions;
[cpp] view plain copy
  1. typedefstruct{
  2. intversion;//Rild版本
  3. RIL_RequestFunconRequest;//AP请求接口
  4. RIL_RadioStateRequestonStateRequest;//BP状态查询
  5. RIL_Supportssupports;
  6. RIL_CancelonCancel;
  7. RIL_GetVersiongetVersion;//动态库版本
  8. }RIL_RadioFunctions;
变量定义: [cpp] view plain copy
  1. staticconstRIL_RadioFunctionss_callbacks={
  2. RIL_VERSION,
  3. onRequest,
  4. currentState,
  5. onSupports,
  6. onCancel,
  7. getVersion
  8. };
[cpp] view plain copy
  1. staticconstRIL_RadioFunctionss_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 plain copy
  1. staticvoidonRequest(intrequest,void*data,size_tdatalen,RIL_Tokent)
  2. {
  3. ATResponse*p_response;
  4. interr;
  5. LOGD("onRequest:%s",requestToString(request));
  6. /*IgnoreallrequestsexceptRIL_REQUEST_GET_SIM_STATUS
  7. *whenRADIO_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. /*Ignoreallnon-powerrequestswhenRADIO_STATE_OFF
  16. *(exceptRIL_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. caseRIL_REQUEST_GET_SIM_STATUS:{
  26. RIL_CardStatus*p_card_status;
  27. char*p_buffer;
  28. intbuffer_size;
  29. intresult=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. caseRIL_REQUEST_GET_CURRENT_CALLS:
  42. requestGetCurrentCalls(data,datalen,t);
  43. break;
  44. caseRIL_REQUEST_DIAL:
  45. requestDial(data,datalen,t);
  46. break;
  47. caseRIL_REQUEST_HANGUP:
  48. requestHangup(data,datalen,t);
  49. break;
  50. caseRIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
  51. //3GPP22.0306.5.5
  52. //"ReleasesallheldcallsorsetsUserDeterminedUserBusy
  53. //(UDUB)forawaitingcall."
  54. at_send_command("AT+CHLD=0",NULL);
  55. /*successorfailureisignoredbytheupperlayerhere.
  56. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  57. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  58. break;
  59. caseRIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
  60. //3GPP22.0306.5.5
  61. //"Releasesallactivecalls(ifanyexist)andaccepts
  62. //theother(heldorwaiting)call."
  63. at_send_command("AT+CHLD=1",NULL);
  64. /*successorfailureisignoredbytheupperlayerhere.
  65. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  66. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  67. break;
  68. caseRIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
  69. //3GPP22.0306.5.5
  70. //"Placesallactivecalls(ifanyexist)onholdandaccepts
  71. //theother(heldorwaiting)call."
  72. at_send_command("AT+CHLD=2",NULL);
  73. #ifdefWORKAROUND_ERRONEOUS_ANSWER
  74. s_expectAnswer=1;
  75. #endif/*WORKAROUND_ERRONEOUS_ANSWER*/
  76. /*successorfailureisignoredbytheupperlayerhere.
  77. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  78. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  79. break;
  80. caseRIL_REQUEST_ANSWER:
  81. at_send_command("ATA",NULL);
  82. #ifdefWORKAROUND_ERRONEOUS_ANSWER
  83. s_expectAnswer=1;
  84. #endif/*WORKAROUND_ERRONEOUS_ANSWER*/
  85. /*successorfailureisignoredbytheupperlayerhere.
  86. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  87. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  88. break;
  89. caseRIL_REQUEST_CONFERENCE:
  90. //3GPP22.0306.5.5
  91. //"Addsaheldcalltotheconversation"
  92. at_send_command("AT+CHLD=3",NULL);
  93. /*successorfailureisignoredbytheupperlayerhere.
  94. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  95. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  96. break;
  97. caseRIL_REQUEST_UDUB:
  98. /*userdetermineduserbusy*/
  99. /*sometimesused:ATH*/
  100. at_send_command("ATH",NULL);
  101. /*successorfailureisignoredbytheupperlayerhere.
  102. itwillcallGET_CURRENT_CALLSanddeterminesuccessthatway*/
  103. RIL_onRequestComplete(t,RIL_E_SUCCESS,NULL,0);
  104. break;
  105. caseRIL_REQUEST_SEPARATE_CONNECTION:
  106. {
  107. charcmd[12];
  108. intparty=((int*)data)[0];

更多相关文章

  1. android在framework层增加自己的service仿照GPS
  2. Android活动生命周期
  3. 可左右两侧挤压傍边布局的Android抽屉
  4. Dalvik虚拟机JNI方法的注册过程分析
  5. Android单元测试研究与实践
  6. 第26章、OnKeyListener键盘事件(从零开始学Android)
  7. Android手掌抑制功能的实现
  8. 如何用Android(安卓)webview播放HTML5 video标签
  9. Android(安卓)App压力测试(Monkey和ADB)

随机推荐

  1. android客户端从服务器端下载文件,服务端
  2. Android防止按钮连续点击
  3. android 跳转到应用通知设置界面【Androi
  4. 列出手机中所有的App,点击启动
  5. Android中实现计时器的功能
  6. Android(安卓)软键盘问题总结
  7. Android学习笔记之mainfest文件中android
  8. cocos2d-x之JS中的Android按键监听
  9. Android系统定制源码修改 - MTK平台
  10. android 重力感应的基本假设