在android系統中rild運行在AP上,AP上的應用經過rild發送AT指令給BP,BP接收到信息後又經過rild傳送給AP。AP與BP之間有兩種通訊方式:java
1.Solicited Response:Ap向Bp發送請求,Bp給Ap發送回覆,該類型的AT指令及其回調函數以數組的形式存放在Ril_commands.h文件中:android
{數組中的索引號,請求回調函數,響應回調函數}ios
[plain] view plaincopyprint?git
{0, NULL, NULL}, //none 數組
{RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, 網絡
{RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts}, 架構
{RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts}, app
{RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts}, 框架
{RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts}, socket
{RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts},
{RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts},
{RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts},
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
{RIL_REQUEST_GET_IMSI, dispatchStrings, responseString},
{RIL_REQUEST_HANGUP, dispatchInts, responseVoid},
{RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid},
{RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid},
{RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid},
{RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid},
{RIL_REQUEST_UDUB, dispatchVoid, responseVoid},
{RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
{RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength},
{RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings},
{RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings},
{RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings},
{RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid},
{RIL_REQUEST_DTMF, dispatchString, responseVoid},
{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
{RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS},
{RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall},
{RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO},
{RIL_REQUEST_SEND_USSD, dispatchString, responseVoid},
{RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid},
{RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts},
{RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid},
{RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards},
{RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid},
{RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts},
{RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid},
{RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid},
{RIL_REQUEST_GET_IMEI, dispatchVoid, responseString},
{RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString},
{RIL_REQUEST_ANSWER,dispatchVoid, responseVoid},
{RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid},
{RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts},
{RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts},
{RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid},
{RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts},
{RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid},
{RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid},
{RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings},
{RIL_REQUEST_DTMF_START, dispatchString, responseVoid},
{RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid},
{RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString},
{RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid},
{RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid},
{RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts},
{RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts},
{RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts},
{RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList},
{RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid},
{RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw},
{RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings},
{RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid},
{RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid},
{RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts},
{RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid},
{RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid},
{RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts},
{RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString},
{RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid},
{RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString},
{RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid},
{RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid},
{RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid},
{RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid},
{RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts},
{RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList},
{RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts},
{RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid},
{RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts},
{RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts},
{RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid},
{RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid},
{RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid},
{RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS},
{RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid},
{RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf},
{RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid},
{RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf},
{RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid},
{RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid},
{RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings},
{RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts},
{RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid},
{RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings},
{RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid},
{RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString},
{RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid},
{RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid},
{RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid},
{RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchCdmaSubscriptionSource, responseInts},
{RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString},
{RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, dispatchStrings, responseVoid},
{RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, dispatchString, responseSIM_IO},
{RIL_REQUEST_VOICE_RADIO_TECH, dispatchVoiceRadioTech, responseInts},
{0, NULL, NULL}, //none {RIL_REQUEST_GET_SIM_STATUS, dispatchVoid, responseSimStatus}, {RIL_REQUEST_ENTER_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PIN2, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_SIM_PUK2, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_SIM_PIN2, dispatchStrings, responseInts}, {RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, dispatchStrings, responseInts}, {RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList}, {RIL_REQUEST_DIAL, dispatchDial, responseVoid}, {RIL_REQUEST_GET_IMSI, dispatchStrings, responseString}, {RIL_REQUEST_HANGUP, dispatchInts, responseVoid}, {RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, dispatchVoid, responseVoid}, {RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, dispatchVoid, responseVoid}, {RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, dispatchVoid, responseVoid}, {RIL_REQUEST_CONFERENCE, dispatchVoid, responseVoid}, {RIL_REQUEST_UDUB, dispatchVoid, responseVoid}, {RIL_REQUEST_LAST_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, {RIL_REQUEST_SIGNAL_STRENGTH, dispatchVoid, responseRilSignalStrength}, {RIL_REQUEST_VOICE_REGISTRATION_STATE, dispatchVoid, responseStrings}, {RIL_REQUEST_DATA_REGISTRATION_STATE, dispatchVoid, responseStrings}, {RIL_REQUEST_OPERATOR, dispatchVoid, responseStrings}, {RIL_REQUEST_RADIO_POWER, dispatchInts, responseVoid}, {RIL_REQUEST_DTMF, dispatchString, responseVoid}, {RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS}, {RIL_REQUEST_SEND_SMS_EXPECT_MORE, dispatchStrings, responseSMS}, {RIL_REQUEST_SETUP_DATA_CALL, dispatchDataCall, responseSetupDataCall}, {RIL_REQUEST_SIM_IO, dispatchSIM_IO, responseSIM_IO}, {RIL_REQUEST_SEND_USSD, dispatchString, responseVoid}, {RIL_REQUEST_CANCEL_USSD, dispatchVoid, responseVoid}, {RIL_REQUEST_GET_CLIR, dispatchVoid, responseInts}, {RIL_REQUEST_SET_CLIR, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, dispatchCallForward, responseCallForwards}, {RIL_REQUEST_SET_CALL_FORWARD, dispatchCallForward, responseVoid}, {RIL_REQUEST_QUERY_CALL_WAITING, dispatchInts, responseInts}, {RIL_REQUEST_SET_CALL_WAITING, dispatchInts, responseVoid}, {RIL_REQUEST_SMS_ACKNOWLEDGE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_IMEI, dispatchVoid, responseString}, {RIL_REQUEST_GET_IMEISV, dispatchVoid, responseString}, {RIL_REQUEST_ANSWER,dispatchVoid, responseVoid}, {RIL_REQUEST_DEACTIVATE_DATA_CALL, dispatchStrings, responseVoid}, {RIL_REQUEST_QUERY_FACILITY_LOCK, dispatchStrings, responseInts}, {RIL_REQUEST_SET_FACILITY_LOCK, dispatchStrings, responseInts}, {RIL_REQUEST_CHANGE_BARRING_PASSWORD, dispatchStrings, responseVoid}, {RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, dispatchVoid, responseVoid}, {RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, dispatchString, responseVoid}, {RIL_REQUEST_QUERY_AVAILABLE_NETWORKS , dispatchVoid, responseStrings}, {RIL_REQUEST_DTMF_START, dispatchString, responseVoid}, {RIL_REQUEST_DTMF_STOP, dispatchVoid, responseVoid}, {RIL_REQUEST_BASEBAND_VERSION, dispatchVoid, responseString}, {RIL_REQUEST_SEPARATE_CONNECTION, dispatchInts, responseVoid}, {RIL_REQUEST_SET_MUTE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_MUTE, dispatchVoid, responseInts}, {RIL_REQUEST_QUERY_CLIP, dispatchVoid, responseInts}, {RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, dispatchVoid, responseInts}, {RIL_REQUEST_DATA_CALL_LIST, dispatchVoid, responseDataCallList}, {RIL_REQUEST_RESET_RADIO, dispatchVoid, responseVoid}, {RIL_REQUEST_OEM_HOOK_RAW, dispatchRaw, responseRaw}, {RIL_REQUEST_OEM_HOOK_STRINGS, dispatchStrings, responseStrings}, {RIL_REQUEST_SCREEN_STATE, dispatchInts, responseVoid}, {RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, dispatchInts, responseVoid}, {RIL_REQUEST_WRITE_SMS_TO_SIM, dispatchSmsWrite, responseInts}, {RIL_REQUEST_DELETE_SMS_ON_SIM, dispatchInts, responseVoid}, {RIL_REQUEST_SET_BAND_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_STK_GET_PROFILE, dispatchVoid, responseString}, {RIL_REQUEST_STK_SET_PROFILE, dispatchString, responseVoid}, {RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, dispatchString, responseString}, {RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, dispatchString, responseVoid}, {RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM, dispatchInts, responseVoid}, {RIL_REQUEST_EXPLICIT_CALL_TRANSFER, dispatchVoid, responseVoid}, {RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, dispatchInts, responseVoid}, {RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, dispatchVoid, responseInts}, {RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, dispatchVoid, responseCellList}, {RIL_REQUEST_SET_LOCATION_UPDATES, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, dispatchVoid, responseInts}, {RIL_REQUEST_SET_TTY_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_QUERY_TTY_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, dispatchVoid, responseInts}, {RIL_REQUEST_CDMA_FLASH, dispatchString, responseVoid}, {RIL_REQUEST_CDMA_BURST_DTMF, dispatchStrings, responseVoid}, {RIL_REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY, dispatchString, responseVoid}, {RIL_REQUEST_CDMA_SEND_SMS, dispatchCdmaSms, responseSMS}, {RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, dispatchCdmaSmsAck, responseVoid}, {RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseGsmBrSmsCnf}, {RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG, dispatchGsmBrSmsCnf, responseVoid}, {RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG, dispatchVoid, responseCdmaBrSmsCnf}, {RIL_REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG, dispatchCdmaBrSmsCnf, responseVoid}, {RIL_REQUEST_CDMA_SMS_BROADCAST_ACTIVATION, dispatchInts, responseVoid}, {RIL_REQUEST_CDMA_SUBSCRIPTION, dispatchVoid, responseStrings}, {RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, dispatchRilCdmaSmsWriteArgs, responseInts}, {RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, dispatchInts, responseVoid}, {RIL_REQUEST_DEVICE_IDENTITY, dispatchVoid, responseStrings}, {RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, dispatchVoid, responseVoid}, {RIL_REQUEST_GET_SMSC_ADDRESS, dispatchVoid, responseString}, {RIL_REQUEST_SET_SMSC_ADDRESS, dispatchString, responseVoid}, {RIL_REQUEST_REPORT_SMS_MEMORY_STATUS, dispatchInts, responseVoid}, {RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING, dispatchVoid, responseVoid}, {RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE, dispatchCdmaSubscriptionSource, responseInts}, {RIL_REQUEST_ISIM_AUTHENTICATION, dispatchString, responseString}, {RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU, dispatchStrings, responseVoid}, {RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, dispatchString, responseSIM_IO}, {RIL_REQUEST_VOICE_RADIO_TECH, dispatchVoiceRadioTech, responseInts},
2.unSolicited Response:Bp主動給Ap發送事件,該類型的AT指令及其回調函數以數組的形式存放在ril_unsol_commands.h文件中:
{數組中的索引號,響應回調函數,類型}
[plain] view plaincopyprint?
{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL},
{RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE},
{RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL},
{RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE},
{RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL},
{RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL},
{RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL},
{RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL},
{RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_SIM_REFRESH, responseSimRefresh, WAKE_PARTIAL},
{RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL},
{RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL},
{RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL},
{RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, responseInts, WAKE_PARTIAL},
{RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS, responseString, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, responseString, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_ON_USSD, responseStrings, WAKE_PARTIAL}, {RIL_UNSOL_ON_USSD_REQUEST, responseVoid, DONT_WAKE}, {RIL_UNSOL_NITZ_TIME_RECEIVED, responseString, WAKE_PARTIAL}, {RIL_UNSOL_SIGNAL_STRENGTH, responseRilSignalStrength, DONT_WAKE}, {RIL_UNSOL_DATA_CALL_LIST_CHANGED, responseDataCallList, WAKE_PARTIAL}, {RIL_UNSOL_SUPP_SVC_NOTIFICATION, responseSsn, WAKE_PARTIAL}, {RIL_UNSOL_STK_SESSION_END, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_STK_PROACTIVE_COMMAND, responseString, WAKE_PARTIAL}, {RIL_UNSOL_STK_EVENT_NOTIFY, responseString, WAKE_PARTIAL}, {RIL_UNSOL_STK_CALL_SETUP, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_SIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_SIM_REFRESH, responseSimRefresh, WAKE_PARTIAL}, {RIL_UNSOL_CALL_RING, responseCallRing, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_CDMA_NEW_SMS, responseCdmaSms, WAKE_PARTIAL}, {RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, responseRaw, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RESTRICTED_STATE_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_CALL_WAITING, responseCdmaCallWaiting, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_INFO_REC, responseCdmaInformationRecords, WAKE_PARTIAL}, {RIL_UNSOL_OEM_HOOK_RAW, responseRaw, WAKE_PARTIAL}, {RIL_UNSOL_RINGBACK_TONE, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_RESEND_INCALL_MUTE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_CDMA_PRL_CHANGED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE, responseVoid, WAKE_PARTIAL}, {RIL_UNSOL_RIL_CONNECTED, responseInts, WAKE_PARTIAL}, {RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, responseInts, WAKE_PARTIAL},
不一樣手機廠商使用的AT命令不徹底相同,爲了保密,AP與BP之間經過各廠商本身的相關動態庫來通訊。
RIL模塊由rild守護進程、libril.so、librefrence.so三部分組成:
1.rild模塊被編譯爲一個可執行文件,實現一個main函數做爲整個ril模塊的入口點。在初始化時使用dlopen打開librefrence_ril.so,從中取出並執行RIL_Init函數,獲得RIL_RadioFunctions指針,經過RIL_register()函數註冊到libril.so庫中,其源碼結構以下:
2.libril.so是共享庫,主要負責同上層的通訊工做,接收ril的請求,並傳遞給librefrence_ril.so,同時將librefrence_ril.so返回的消息送給調用進程,源碼結構以下所示:
3.librefrence_ril.so是由各手機廠商本身實現,在rild進程運行中經過dlopen方式加載,主要負責跟modem硬件通訊,轉換來自libril.so的請求爲AT命令,同時監聽Modem的反饋信息給libril.so
Android的電話系統主要分爲三個部分,java層的各類電話相關應用,java層的Phone Service,主要爲上層提供API,同時與native進行通訊,能夠看作爲電話系統的客戶端,native層的電話服務進程RILD,負責爲上層提供各類電話功能服務,直接與modem進行交互:
Android電話系統設計框架圖:
因爲Android 開發者使用的Modem 是不同的,各類指令格式,初始化序列均可能不同,因此爲了消除這些差異,Android 設計者將ril 作了一個抽象,使用一個虛擬電話的概念,不一樣modem相關的AT指令或者通訊協議編譯成相應的動態連接庫.so文件,Rild 是具體的AT 指令合成者和應答解析者。
Android電話系統代碼結構圖:
在android的電話系統中,在native層實現了電話服務的服務端,由RILD服務與modem的交互,在java層實現電話的客戶端,本文主要介紹電話系統的服務端RILD進程,如下是RILD的設計框架圖:
接下來經過源碼對RILD的整個框架進行詳細介紹。
在kernel啓動完成後,將啓動第一個應用進程Init進程,在android之Init進程啓動過程源碼分析一文中對init進程的啓動流程進行了詳細的介紹。init進程在啓動過程當中將讀取init.rc文件來啓動一些重量級的native服務,rild進程就是經過配置在init.rc中來啓動的。
[plain] view plaincopyprint?
service ril-daemon /system/bin/rild
class main
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio sdcard_rw log
service ril-daemon /system/bin/rild class main socket rild stream 660 root radio socket rild-debug stream 660 radio system user root group radio cache inet misc audio sdcard_rw log
接下來給出的是RILD進程啓動的時序圖:
hardware\ril\rild\rild.c
[cpp] view plaincopyprint?
int main(int argc, char **argv)
{
const char * rilLibPath = NULL;
char **rilArgv;
void *dlHandle;
const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
const RIL_RadioFunctions *funcs;
char libPath[PROPERTY_VALUE_MAX];
unsigned char hasLibArgs = 0;
int i;
umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
//rild啓動無參數
for (i = 1; i < argc ;) {
if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
rilLibPath = argv[i + 1];
i += 2;
} else if (0 == strcmp(argv[i], "--")) {
i++;
hasLibArgs = 1;
break;
} else {
usage(argv[0]);
}
}
if (rilLibPath == NULL) {
//經過Android屬性系統讀取屬性"rild.libpath"的值,即lib庫的存放路徑
if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
goto done;
} else {
rilLibPath = libPath;
}
}
##################################################################################
判斷是否爲模擬器
##################################################################################
#if 1
{
static char* arg_overrides[3];
static char arg_device[32];
int done = 0;
#define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
/* first, read /proc/cmdline into memory */
char buffer[1024], *p, *q;
int len;
int fd = open("/proc/cmdline",O_RDONLY);
if (fd < 0) {
LOGD("could not open /proc/cmdline:%s", strerror(errno));
goto OpenLib;
}
//讀取/proc/cmdline文件中的內容
do {
len = read(fd,buffer,sizeof(buffer)); }
while (len == -1 && errno == EINTR);
if (len < 0) {
LOGD("could not read /proc/cmdline:%s", strerror(errno));
close(fd);
goto OpenLib;
}
close(fd);
//判斷是否爲模擬器,對於真機,此處條件爲false
if (strstr(buffer, "android.qemud=") != NULL)
{
int tries = 5;
#define QEMUD_SOCKET_NAME "qemud"
while (1) {
int fd;
sleep(1);
fd = socket_local_client(QEMUD_SOCKET_NAME,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM );
if (fd >= 0) {
close(fd);
snprintf( arg_device, sizeof(arg_device), "%s/%s",
ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
arg_overrides[1] = "-s";
arg_overrides[2] = arg_device;
done = 1;
break;
}
LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno));
if (--tries == 0)
break;
}
if (!done) {
LOGE("could not connect to %s socket (giving up): %s",
QEMUD_SOCKET_NAME, strerror(errno));
while(1)
sleep(0x00ffffff);
}
}
/* otherwise, try to see if we passed a device name from the kernel */
if (!done) do { //true
#define KERNEL_OPTION "android.ril="
#define DEV_PREFIX "/dev/"
//判斷/proc/cmdline中的內容是否包含"android.ril="
p = strstr( buffer, KERNEL_OPTION );
if (p == NULL)
break;
p += sizeof(KERNEL_OPTION)-1;
q = strpbrk( p, " \t\n\r" );
if (q != NULL)
*q = 0;
snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
arg_device[sizeof(arg_device)-1] = 0;
arg_overrides[1] = "-d";
arg_overrides[2] = arg_device;
done = 1;
} while (0);
if (done) { //false
argv = arg_overrides;
argc = 3;
i = 1;
hasLibArgs = 1;
rilLibPath = REFERENCE_RIL_PATH;
LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
}
}
OpenLib:
#endif
##################################################################################
動態庫裝載
##################################################################################
switchUser();//設置Rild進程的組用戶爲radio
//加載廠商自定義的庫
①dlHandle = dlopen(rilLibPath, RTLD_NOW);
if (dlHandle == NULL) {
fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(-1);
}
//建立客戶端事件監聽線程
②RIL_startEventLoop();
//經過dlsym定位到RIL_Init函數的地址,而且強制轉換爲RIL_RadioFunctions的函數指針
③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
if (rilInit == NULL) {
fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
exit(-1);
}
if (hasLibArgs) { //false
rilArgv = argv + i - 1;
argc = argc -i + 1;
} else {
static char * newArgv[MAX_LIB_ARGS];
static char args[PROPERTY_VALUE_MAX];
rilArgv = newArgv;
property_get(LIB_ARGS_PROPERTY, args, "");//經過屬性系統讀取"rild.libargs"屬性值
argc = make_argv(args, rilArgv);
}
// Make sure there's a reasonable argv[0]
rilArgv[0] = argv[0];
//調用RIL_Init函數來初始化rild,傳入參數s_rilEnv,返回RIL_RadioFunctions地址
④funcs = rilInit(&s_rilEnv, argc, rilArgv);
//註冊客戶端事件處理接口RIL_RadioFunctions,並建立socket監聽事件
⑤RIL_register(funcs);
done:
while(1) {
// sleep(UINT32_MAX) seems to return immediately on bionic
sleep(0x00ffffff);
}
}
int main(int argc, char **argv) { const char * rilLibPath = NULL; char **rilArgv; void *dlHandle; const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **); const RIL_RadioFunctions *funcs; char libPath[PROPERTY_VALUE_MAX]; unsigned char hasLibArgs = 0; int i; umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH); //rild啓動無參數 for (i = 1; i < argc ;) { if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) { rilLibPath = argv[i + 1]; i += 2; } else if (0 == strcmp(argv[i], "--")) { i++; hasLibArgs = 1; break; } else { usage(argv[0]); } } if (rilLibPath == NULL) { //經過Android屬性系統讀取屬性"rild.libpath"的值,即lib庫的存放路徑 if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) { goto done; } else { rilLibPath = libPath; } } ################################################################################## 判斷是否爲模擬器 ################################################################################## #if 1 { static char* arg_overrides[3]; static char arg_device[32]; int done = 0; #define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so" /* first, read /proc/cmdline into memory */ char buffer[1024], *p, *q; int len; int fd = open("/proc/cmdline",O_RDONLY); if (fd < 0) { LOGD("could not open /proc/cmdline:%s", strerror(errno)); goto OpenLib; } //讀取/proc/cmdline文件中的內容 do { len = read(fd,buffer,sizeof(buffer)); } while (len == -1 && errno == EINTR); if (len < 0) { LOGD("could not read /proc/cmdline:%s", strerror(errno)); close(fd); goto OpenLib; } close(fd); //判斷是否爲模擬器,對於真機,此處條件爲false if (strstr(buffer, "android.qemud=") != NULL) { int tries = 5; #define QEMUD_SOCKET_NAME "qemud" while (1) { int fd; sleep(1); fd = socket_local_client(QEMUD_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM ); if (fd >= 0) { close(fd); snprintf( arg_device, sizeof(arg_device), "%s/%s", ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME ); arg_overrides[1] = "-s"; arg_overrides[2] = arg_device; done = 1; break; } LOGD("could not connect to %s socket: %s",QEMUD_SOCKET_NAME, strerror(errno)); if (--tries == 0) break; } if (!done) { LOGE("could not connect to %s socket (giving up): %s", QEMUD_SOCKET_NAME, strerror(errno)); while(1) sleep(0x00ffffff); } } /* otherwise, try to see if we passed a device name from the kernel */ if (!done) do { //true #define KERNEL_OPTION "android.ril=" #define DEV_PREFIX "/dev/" //判斷/proc/cmdline中的內容是否包含"android.ril=" p = strstr( buffer, KERNEL_OPTION ); if (p == NULL) break; p += sizeof(KERNEL_OPTION)-1; q = strpbrk( p, " \t\n\r" ); if (q != NULL) *q = 0; snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p ); arg_device[sizeof(arg_device)-1] = 0; arg_overrides[1] = "-d"; arg_overrides[2] = arg_device; done = 1; } while (0); if (done) { //false argv = arg_overrides; argc = 3; i = 1; hasLibArgs = 1; rilLibPath = REFERENCE_RIL_PATH; LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]); } } OpenLib: #endif ################################################################################## 動態庫裝載 ################################################################################## switchUser();//設置Rild進程的組用戶爲radio //加載廠商自定義的庫 ①dlHandle = dlopen(rilLibPath, RTLD_NOW); if (dlHandle == NULL) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); exit(-1); } //建立客戶端事件監聽線程 ②RIL_startEventLoop(); //經過dlsym定位到RIL_Init函數的地址,而且強制轉換爲RIL_RadioFunctions的函數指針 ③rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init"); if (rilInit == NULL) { fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath); exit(-1); } if (hasLibArgs) { //false rilArgv = argv + i - 1; argc = argc -i + 1; } else { static char * newArgv[MAX_LIB_ARGS]; static char args[PROPERTY_VALUE_MAX]; rilArgv = newArgv; property_get(LIB_ARGS_PROPERTY, args, "");//經過屬性系統讀取"rild.libargs"屬性值 argc = make_argv(args, rilArgv); } // Make sure there's a reasonable argv[0] rilArgv[0] = argv[0]; //調用RIL_Init函數來初始化rild,傳入參數s_rilEnv,返回RIL_RadioFunctions地址 ④funcs = rilInit(&s_rilEnv, argc, rilArgv); //註冊客戶端事件處理接口RIL_RadioFunctions,並建立socket監聽事件 ⑤RIL_register(funcs); done: while(1) { // sleep(UINT32_MAX) seems to return immediately on bionic sleep(0x00ffffff); } }
在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庫通訊橋樑;
創建多路I/O驅動機制的消息隊列,用來接收上層發出的命令以及往Modem發送AT指令的工做,時整個RIL系統的核心部分。建立一個事件分發線程s_tid_dispatch,線程執行體爲eventLoop。
hardware\ril\libril\Ril.cpp
[cpp] view plaincopyprint?
extern "C" void RIL_startEventLoop(void) {
int ret;
pthread_attr_t attr;
/* spin up eventLoop thread and wait for it to get started */
s_started = 0;
pthread_mutex_lock(&s_startupMutex);
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//建立一個工做線程eventLoop
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
//確保函數返回前eventLoop線程啓動運行
while (s_started == 0) {
pthread_cond_wait(&s_startupCond, &s_startupMutex);
}
pthread_mutex_unlock(&s_startupMutex);
if (ret < 0) {
LOGE("Failed to create dispatch thread errno:%d", errno);
return;
}
}
extern "C" void RIL_startEventLoop(void) { int ret; pthread_attr_t attr; /* spin up eventLoop thread and wait for it to get started */ s_started = 0; pthread_mutex_lock(&s_startupMutex); pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //建立一個工做線程eventLoop ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL); //確保函數返回前eventLoop線程啓動運行 while (s_started == 0) { pthread_cond_wait(&s_startupCond, &s_startupMutex); } pthread_mutex_unlock(&s_startupMutex); if (ret < 0) { LOGE("Failed to create dispatch thread errno:%d", errno); return; } }
eventLoop執行時序圖:
[cpp] view plaincopyprint?
static void * eventLoop(void *param) {
int ret;
int filedes[2];
ril_event_init(); //初始化請求隊列
pthread_mutex_lock(&s_startupMutex);
s_started = 1; //eventLoop線程運行標誌位
pthread_cond_broadcast(&s_startupCond);
pthread_mutex_unlock(&s_startupMutex);
//建立匿名管道
ret = pipe(filedes);
if (ret < 0) {
LOGE("Error in pipe() errno:%d", errno);
return NULL;
}
//s_fdWakeupRead爲管道讀端
s_fdWakeupRead = filedes[0];
//s_fdWakeupWrite爲管道寫端
s_fdWakeupWrite = filedes[1];
//設置管道讀端爲O_NONBLOCK非阻塞
fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK);
//初始化s_wakeupfd_event結構體的內容,句柄爲s_fdWakeupRead,回調函數爲 processWakeupCallback
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL);
①rilEventAddWakeup (&s_wakeupfd_event);
// Only returns on error
②ril_event_loop();
LOGE ("error in event_loop_base errno:%d", errno);
return NULL;
}
static void * eventLoop(void *param) { int ret; int filedes[2]; ril_event_init(); //初始化請求隊列 pthread_mutex_lock(&s_startupMutex); s_started = 1; //eventLoop線程運行標誌位 pthread_cond_broadcast(&s_startupCond); pthread_mutex_unlock(&s_startupMutex); //建立匿名管道 ret = pipe(filedes); if (ret < 0) { LOGE("Error in pipe() errno:%d", errno); return NULL; } //s_fdWakeupRead爲管道讀端 s_fdWakeupRead = filedes[0]; //s_fdWakeupWrite爲管道寫端 s_fdWakeupWrite = filedes[1]; //設置管道讀端爲O_NONBLOCK非阻塞 fcntl(s_fdWakeupRead, F_SETFL, O_NONBLOCK); //初始化s_wakeupfd_event結構體的內容,句柄爲s_fdWakeupRead,回調函數爲 processWakeupCallback ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL); ①rilEventAddWakeup (&s_wakeupfd_event); // Only returns on error ②ril_event_loop(); LOGE ("error in event_loop_base errno:%d", errno); return NULL; }
在rild中定義了event的概念,Rild支持兩種類型的事件:
1. 定時事件:根據事件的執行時間來啓動執行,經過ril_timer_add添加到time_list隊列中
2. Wakeup事件:這些事件的句柄fd將加入的select IO多路複用的句柄池readFDs中,當對應的fd可讀時將觸發這些事件。對於處於listen端的socket,fd可讀表示有個客戶端鏈接,此時須要調用accept接受鏈接。
事件定義以下:
[cpp] view plaincopyprint?
struct ril_event {
struct ril_event *next;
struct ril_event *prev;
int fd; //文件句柄
int index; //該事件在監控表中的索引
bool persist; //若是是保持的,則不從watch_list 中刪除
struct timeval timeout; //任務執行時間
ril_event_cb func; //回調事件處理函數
void *param; //回調時參數
};
struct ril_event { struct ril_event *next; struct ril_event *prev; int fd; //文件句柄 int index; //該事件在監控表中的索引 bool persist; //若是是保持的,則不從watch_list 中刪除 struct timeval timeout; //任務執行時間 ril_event_cb func; //回調事件處理函數 void *param; //回調時參數 };
在Rild進程中的幾個重要事件有
[cpp] view plaincopyprint?
static struct ril_event s_commands_event;
ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs)
static struct ril_event s_wakeupfd_event;
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL)
static struct ril_event s_listen_event;
ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL)
static struct ril_event s_wake_timeout_event;
ril_timer_add(&(p_info->event), &myRelativeTime);
static struct ril_event s_commands_event; ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs) static struct ril_event s_wakeupfd_event; ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,processWakeupCallback, NULL) static struct ril_event s_listen_event; ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL) static struct ril_event s_wake_timeout_event; ril_timer_add(&(p_info->event), &myRelativeTime);
[cpp] view plaincopyprint?
static struct ril_event s_debug_event;
ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)
static struct ril_event s_debug_event; ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL)
在RILD中定義了三個事件隊列,用於處理不一樣的事件:
/事件監控隊列
static struct ril_event * watch_table[MAX_FD_EVENTS];
//定時事件隊列
static struct ril_event timer_list;
//處理事件隊列
static struct ril_event pending_list; //待處理事件隊列,事件已經觸發,須要所回調處理的事件
1.添加Wakeup 事件
[cpp] view plaincopyprint?
static void rilEventAddWakeup(struct ril_event *ev) {
ril_event_add(ev); //向監控表watch_table添加一個s_wakeupfd_event事件
triggerEvLoop(); //向管道s_fdWakeupWrite中寫入之來觸發事件循環
}
static void rilEventAddWakeup(struct ril_event *ev) { ril_event_add(ev); //向監控表watch_table添加一個s_wakeupfd_event事件 triggerEvLoop(); //向管道s_fdWakeupWrite中寫入之來觸發事件循環 }
[cpp] view plaincopyprint?
void ril_event_add(struct ril_event * ev)
{
dlog("~~~~ +ril_event_add ~~~~");
MUTEX_ACQUIRE();
for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍歷監控表watch_table
if (watch_table[i] == NULL) { //從監控表中查找空閒的索引,而後把該任務加入到監控表中
watch_table[i] = ev; //向監控表中添加事件
ev->index = i; //事件的索引設置爲在監控表中的索引
dlog("~~~~ added at %d ~~~~", i);
dump_event(ev);
FD_SET(ev->fd, &readFds); //將添加的事件對應的句柄添加到句柄池readFds中
if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值
dlog("~~~~ nfds = %d ~~~~", nfds);
break;
}
}
MUTEX_RELEASE();
dlog("~~~~ -ril_event_add ~~~~");
}
void ril_event_add(struct ril_event * ev) { dlog("~~~~ +ril_event_add ~~~~"); MUTEX_ACQUIRE(); for (int i = 0; i < MAX_FD_EVENTS; i++) { //遍歷監控表watch_table if (watch_table[i] == NULL) { //從監控表中查找空閒的索引,而後把該任務加入到監控表中 watch_table[i] = ev; //向監控表中添加事件 ev->index = i; //事件的索引設置爲在監控表中的索引 dlog("~~~~ added at %d ~~~~", i); dump_event(ev); FD_SET(ev->fd, &readFds); //將添加的事件對應的句柄添加到句柄池readFds中 if (ev->fd >= nfds) nfds = ev->fd+1; //修改句柄最大值 dlog("~~~~ nfds = %d ~~~~", nfds); break; } } MUTEX_RELEASE(); dlog("~~~~ -ril_event_add ~~~~"); }
2.添加定時事件
[cpp] view plaincopyprint?
void ril_timer_add(struct ril_event * ev, struct timeval * tv)
{
dlog("~~~~ +ril_timer_add ~~~~");
MUTEX_ACQUIRE();
struct ril_event * list;
if (tv != NULL) {
list = timer_list.next;
ev->fd = -1; // make sure fd is invalid
struct timeval now;
getNow(&now);
timeradd(&now, tv, &ev->timeout);
// keep list sorted
while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) {
list = list->next;
}
// list now points to the first event older than ev
addToList(ev, list);
}
MUTEX_RELEASE();
dlog("~~~~ -ril_timer_add ~~~~");
}
void ril_timer_add(struct ril_event * ev, struct timeval * tv) { dlog("~~~~ +ril_timer_add ~~~~"); MUTEX_ACQUIRE(); struct ril_event * list; if (tv != NULL) { list = timer_list.next; ev->fd = -1; // make sure fd is invalid struct timeval now; getNow(&now); timeradd(&now, tv, &ev->timeout); // keep list sorted while (timercmp(&list->timeout, &ev->timeout, < ) && (list != &timer_list)) { list = list->next; } // list now points to the first event older than ev addToList(ev, list); } MUTEX_RELEASE(); dlog("~~~~ -ril_timer_add ~~~~"); }
[cpp] view plaincopyprint?
static void triggerEvLoop() {
int ret;
if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //若是當前線程ID不等於事件分發線程eventLoop的線程ID
do {
ret = write (s_fdWakeupWrite, " ", 1); //向管道寫端寫入值1來觸發eventLoop事件循環
} while (ret < 0 && errno == EINTR);
}
}
static void triggerEvLoop() { int ret; if (!pthread_equal(pthread_self(), s_tid_dispatch)) { //若是當前線程ID不等於事件分發線程eventLoop的線程ID do { ret = write (s_fdWakeupWrite, " ", 1); //向管道寫端寫入值1來觸發eventLoop事件循環 } while (ret < 0 && errno == EINTR); } }
[cpp] view plaincopyprint?
void ril_event_loop()
{
int n;
fd_set rfds;
struct timeval tv;
struct timeval * ptv;
for (;;) {
memcpy(&rfds, &readFds, sizeof(fd_set));
if (-1 == calcNextTimeout(&tv)) {
dlog("~~~~ no timers; blocking indefinitely ~~~~");
ptv = NULL;
} else {
dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec);
ptv = &tv;
}
//使用select 函數等待在FDS 上,只要FDS 中記錄的設備有數據到來,select 就會設置相應的標誌位並返回。readFDS 記錄了全部的事件相關設備句柄。readFDS 中句柄是在在AddEvent 加入的。
printReadies(&rfds);
n = select(nfds, &rfds, NULL, NULL, ptv);
printReadies(&rfds);
dlog("~~~~ %d events fired ~~~~", n);
if (n < 0) {
if (errno == EINTR) continue;
LOGE("ril_event: select error (%d)", errno);
return;
}
processTimeouts(); //從timer_list中查詢執行時間已到的事件,並添加到pending_list中
processReadReadies(&rfds, n); //從watch_table中查詢數據可讀的事件,並添加到pending_list中去處理,若是該事件不是持久事件,則同時從watch_table中刪除
//遍歷pending_list,調用事件處理回調函數處理全部事件
firePending();
}
}
void ril_event_loop() { int n; fd_set rfds; struct timeval tv; struct timeval * ptv; for (;;) { memcpy(&rfds, &readFds, sizeof(fd_set)); if (-1 == calcNextTimeout(&tv)) { dlog("~~~~ no timers; blocking indefinitely ~~~~"); ptv = NULL; } else { dlog("~~~~ blocking for %ds + %dus ~~~~", (int)tv.tv_sec, (int)tv.tv_usec); ptv = &tv; } //使用select 函數等待在FDS 上,只要FDS 中記錄的設備有數據到來,select 就會設置相應的標誌位並返回。readFDS 記錄了全部的事件相關設備句柄。readFDS 中句柄是在在AddEvent 加入的。 printReadies(&rfds); n = select(nfds, &rfds, NULL, NULL, ptv); printReadies(&rfds); dlog("~~~~ %d events fired ~~~~", n); if (n < 0) { if (errno == EINTR) continue; LOGE("ril_event: select error (%d)", errno); return; } processTimeouts(); //從timer_list中查詢執行時間已到的事件,並添加到pending_list中 processReadReadies(&rfds, n); //從watch_table中查詢數據可讀的事件,並添加到pending_list中去處理,若是該事件不是持久事件,則同時從watch_table中刪除 //遍歷pending_list,調用事件處理回調函數處理全部事件 firePending(); } }
在eventLoop工做線程中,循環處理到來的事件及定時結束事件,整個處理流程以下圖所示:
首先經過Linux中的select多路I/O複用對句柄池中的全部句柄進行監控,當有事件到來時select返回,不然阻塞。當select返回時,表示有事件的到來,經過調用processTimeouts函數來處理超時事件,處理方式是遍歷time_list鏈表以查詢超時事件,並將超時事件移入到pending_list鏈表中,接着調用processReadReadies函數來處理觸發的事件,處理方式爲遍歷watch_table列表以查詢觸發的事件,並將觸發的事件移入到pending_list鏈表中,若是該事件不是持久事件,還須要從watch_table列表中移除,當查詢完兩種待處理的事件並放入到pending_list鏈表中後,調用firePending函數對待處理的事件進行集中處理,處理方式爲遍歷鏈表,調用每個事件的回調函數。
[cpp] view plaincopyprint?
static void processTimeouts()
{
dlog("~~~~ +processTimeouts ~~~~");
MUTEX_ACQUIRE();
struct timeval now;
struct ril_event * tev = timer_list.next;
struct ril_event * next;
getNow(&now); //獲取當前時間
dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec);
//若是當前時間大於事件的超時時間,則將該事件從timer_list中移除,添加到pending_list
while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) {
dlog("~~~~ firing timer ~~~~");
next = tev->next;
removeFromList(tev); //從timer_list中移除事件
addToList(tev, &pending_list); //將事件添加到pending_list
tev = next;
}
MUTEX_RELEASE();
dlog("~~~~ -processTimeouts ~~~~");
}
static void processTimeouts() { dlog("~~~~ +processTimeouts ~~~~"); MUTEX_ACQUIRE(); struct timeval now; struct ril_event * tev = timer_list.next; struct ril_event * next; getNow(&now); //獲取當前時間 dlog("~~~~ Looking for timers <= %ds + %dus ~~~~", (int)now.tv_sec, (int)now.tv_usec); //若是當前時間大於事件的超時時間,則將該事件從timer_list中移除,添加到pending_list while ((tev != &timer_list) && (timercmp(&now, &tev->timeout, >))) { dlog("~~~~ firing timer ~~~~"); next = tev->next; removeFromList(tev); //從timer_list中移除事件 addToList(tev, &pending_list); //將事件添加到pending_list tev = next; } MUTEX_RELEASE(); dlog("~~~~ -processTimeouts ~~~~"); }
[cpp] view plaincopyprint?
static void processReadReadies(fd_set * rfds, int n)
{
dlog("~~~~ +processReadReadies (%d) ~~~~", n);
MUTEX_ACQUIRE();
//遍歷watch_table數組,根據select返回的句柄n查找對應的事件
for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) {
struct ril_event * rev = watch_table[i]; //獲得相應的事件
if (rev != NULL && FD_ISSET(rev->fd, rfds)) {
addToList(rev, &pending_list); //將該事件添加到pending_list中
if (rev->persist == false) { //若是該事件不是持久事件還要從watch_table中移除
removeWatch(rev, i);
}
n--;
}
}
MUTEX_RELEASE();
dlog("~~~~ -processReadReadies (%d) ~~~~", n);
}
static void processReadReadies(fd_set * rfds, int n) { dlog("~~~~ +processReadReadies (%d) ~~~~", n); MUTEX_ACQUIRE(); //遍歷watch_table數組,根據select返回的句柄n查找對應的事件 for (int i = 0; (i < MAX_FD_EVENTS) && (n > 0); i++) { struct ril_event * rev = watch_table[i]; //獲得相應的事件 if (rev != NULL && FD_ISSET(rev->fd, rfds)) { addToList(rev, &pending_list); //將該事件添加到pending_list中 if (rev->persist == false) { //若是該事件不是持久事件還要從watch_table中移除 removeWatch(rev, i); } n--; } } MUTEX_RELEASE(); dlog("~~~~ -processReadReadies (%d) ~~~~", n); }
[cpp] view plaincopyprint?
static void firePending()
{
dlog("~~~~ +firePending ~~~~");
struct ril_event * ev = pending_list.next;
while (ev != &pending_list) { //遍歷pending_list鏈表,處理鏈表中的全部事件
struct ril_event * next = ev->next;
removeFromList(ev); //將處理完的事件從pending_list中移除
ev->func(ev->fd, 0, ev->param); //調用事件處理的回調函數
ev = next;
}
dlog("~~~~ -firePending ~~~~");
}
static void firePending() { dlog("~~~~ +firePending ~~~~"); struct ril_event * ev = pending_list.next; while (ev != &pending_list) { //遍歷pending_list鏈表,處理鏈表中的全部事件 struct ril_event * next = ev->next; removeFromList(ev); //將處理完的事件從pending_list中移除 ev->func(ev->fd, 0, ev->param); //調用事件處理的回調函數 ev = next; } dlog("~~~~ -firePending ~~~~"); }
hardware\ril\include\telephony\ril.h
[cpp] view plaincopyprint?
struct RIL_Env {
//動態庫完成請求後通知處理結果的接口
void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen);
//動態庫unSolicited Response通知接口
void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen);
//向Rild提交一個超時任務的接口
void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime);
};
struct RIL_Env { //動態庫完成請求後通知處理結果的接口 void (*OnRequestComplete)(RIL_Token t, RIL_Errno e,void *response, size_t responselen); //動態庫unSolicited Response通知接口 void (*OnUnsolicitedResponse)(int unsolResponse, const void *data,size_t datalen); //向Rild提交一個超時任務的接口 void (*RequestTimedCallback) (RIL_TimedCallback callback,void *param, const struct timeval *relativeTime); };
hardware\ril\rild\rild.c
s_rilEnv變量定義:
[cpp] view plaincopyprint?
static struct RIL_Env s_rilEnv = {
RIL_onRequestComplete,
RIL_onUnsolicitedResponse,
RIL_requestTimedCallback
};
static struct RIL_Env s_rilEnv = { RIL_onRequestComplete, RIL_onUnsolicitedResponse, RIL_requestTimedCallback };
在hardware\ril\libril\ril.cpp中實現了RIL_Env的各個接口函數
[cpp] view plaincopyprint?
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
size_t errorOffset;
pRI = (RequestInfo *)t;
if (!checkAndDequeueRequestInfo(pRI)) {
LOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
if (pRI->local > 0) {
// Locally issued command...void only!
// response does not go back up the command socket
LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber));
goto done;
}
appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber));
if (pRI->cancelled == 0) {
Parcel p;
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);
errorOffset = p.dataPosition();
p.writeInt32 (e);
if (response != NULL) {
// there is a response payload, no matter success or not.
ret = pRI->pCI->responseFunction(p, response, responselen);
/* if an error occurred, rewind and mark it */
if (ret != 0) {
p.setDataPosition(errorOffset);
p.writeInt32 (ret);
}
}
if (e != RIL_E_SUCCESS) {
appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e));
}
if (s_fdCommand < 0) {
LOGD ("RIL onRequestComplete: Command channel closed");
}
sendResponse(p);
}
done:
free(pRI);
}
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RequestInfo *pRI; int ret; size_t errorOffset; pRI = (RequestInfo *)t; if (!checkAndDequeueRequestInfo(pRI)) { LOGE ("RIL_onRequestComplete: invalid RIL_Token"); return; } if (pRI->local > 0) { // Locally issued command...void only! // response does not go back up the command socket LOGD("C[locl]< %s", requestToString(pRI->pCI->requestNumber)); goto done; } appendPrintBuf("[%04d]< %s",pRI->token, requestToString(pRI->pCI->requestNumber)); if (pRI->cancelled == 0) { Parcel p; p.writeInt32 (RESPONSE_SOLICITED); p.writeInt32 (pRI->token); errorOffset = p.dataPosition(); p.writeInt32 (e); if (response != NULL) { // there is a response payload, no matter success or not. ret = pRI->pCI->responseFunction(p, response, responselen); /* if an error occurred, rewind and mark it */ if (ret != 0) { p.setDataPosition(errorOffset); p.writeInt32 (ret); } } if (e != RIL_E_SUCCESS) { appendPrintBuf("%s fails by %s", printBuf, failCauseToString(e)); } if (s_fdCommand < 0) { LOGD ("RIL onRequestComplete: Command channel closed"); } sendResponse(p); } done: free(pRI); }
經過調用responseXXX將底層響應傳給客戶進程
[cpp] view plaincopyprint?
extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data,
size_t datalen)
{
int unsolResponseIndex;
int ret;
int64_t timeReceived = 0;
bool shouldScheduleTimeout = false;
if (s_registerCalled == 0) {
// Ignore RIL_onUnsolicitedResponse before RIL_register
LOGW("RIL_onUnsolicitedResponse called before RIL_register");
return;
}
unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
if ((unsolResponseIndex < 0)
|| (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
LOGE("unsupported unsolicited response code %d", unsolResponse);
return;
}
// Grab a wake lock if needed for this reponse,
// as we exit we'll either release it immediately
// or set a timer to release it later.
switch (s_unsolResponses[unsolResponseIndex].wakeType) {
case WAKE_PARTIAL:
grabPartialWakeLock();
shouldScheduleTimeout = true;
break;
case DONT_WAKE:
default:
// No wake lock is grabed so don't set timeout
shouldScheduleTimeout = false;
break;
}
// Mark the time this was received, doing this
// after grabing the wakelock incase getting
// the elapsedRealTime might cause us to goto
// sleep.
if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
timeReceived = elapsedRealtime();
}
appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
Parcel p;
p.writeInt32 (RESPONSE_UNSOLICITED);
p.writeInt32 (unsolResponse);
ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
if (ret != 0) {
// Problem with the response. Don't continue;
goto error_exit;
}
// some things get more payload
switch(unsolResponse) {
case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
p.writeInt32(s_callbacks.onStateRequest());
appendPrintBuf("%s {%s}", printBuf,
radioStateToString(s_callbacks.onStateRequest()));
break;
case RIL_UNSOL_NITZ_TIME_RECEIVED:
// Store the time that this was received so the
// handler of this message can account for
// the time it takes to arrive and process. In
// particular the system has been known to sleep
// before this message can be processed.
p.writeInt64(timeReceived);
break;
}
ret = sendResponse(p);
if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
// Unfortunately, NITZ time is not poll/update like everything
// else in the system. So, if the upstream client isn't connected,
// keep a copy of the last NITZ response (with receive time noted
// above) around so we can deliver it when it is connected
if (s_lastNITZTimeData != NULL) {
free (s_lastNITZTimeData);
s_lastNITZTimeData = NULL;
}
s_lastNITZTimeData = malloc(p.dataSize());
s_lastNITZTimeDataSize = p.dataSize();
memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
}
// For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT
// FIXME The java code should handshake here to release wake lock
if (shouldScheduleTimeout) {
// Cancel the previous request
if (s_last_wake_timeout_info != NULL) {
s_last_wake_timeout_info->userParam = (void *)1;
}
s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL,
&TIMEVAL_WAKE_TIMEOUT);
}
return;
error_exit:
if (shouldScheduleTimeout) {
releaseWakeLock();
}
}
extern "C" void RIL_onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) { int unsolResponseIndex; int ret; int64_t timeReceived = 0; bool shouldScheduleTimeout = false; if (s_registerCalled == 0) { // Ignore RIL_onUnsolicitedResponse before RIL_register LOGW("RIL_onUnsolicitedResponse called before RIL_register"); return; } unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE; if ((unsolResponseIndex < 0) || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) { LOGE("unsupported unsolicited response code %d", unsolResponse); return; } // Grab a wake lock if needed for this reponse, // as we exit we'll either release it immediately // or set a timer to release it later. switch (s_unsolResponses[unsolResponseIndex].wakeType) { case WAKE_PARTIAL: grabPartialWakeLock(); shouldScheduleTimeout = true; break; case DONT_WAKE: default: // No wake lock is grabed so don't set timeout shouldScheduleTimeout = false; break; } // Mark the time this was received, doing this // after grabing the wakelock incase getting // the elapsedRealTime might cause us to goto // sleep. if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { timeReceived = elapsedRealtime(); } appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse)); Parcel p; p.writeInt32 (RESPONSE_UNSOLICITED); p.writeInt32 (unsolResponse); ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen); if (ret != 0) { // Problem with the response. Don't continue; goto error_exit; } // some things get more payload switch(unsolResponse) { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: p.writeInt32(s_callbacks.onStateRequest()); appendPrintBuf("%s {%s}", printBuf, radioStateToString(s_callbacks.onStateRequest())); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: // Store the time that this was received so the // handler of this message can account for // the time it takes to arrive and process. In // particular the system has been known to sleep // before this message can be processed. p.writeInt64(timeReceived); break; } ret = sendResponse(p); if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) { // Unfortunately, NITZ time is not poll/update like everything // else in the system. So, if the upstream client isn't connected, // keep a copy of the last NITZ response (with receive time noted // above) around so we can deliver it when it is connected if (s_lastNITZTimeData != NULL) { free (s_lastNITZTimeData); s_lastNITZTimeData = NULL; } s_lastNITZTimeData = malloc(p.dataSize()); s_lastNITZTimeDataSize = p.dataSize(); memcpy(s_lastNITZTimeData, p.data(), p.dataSize()); } // For now, we automatically go back to sleep after TIMEVAL_WAKE_TIMEOUT // FIXME The java code should handshake here to release wake lock if (shouldScheduleTimeout) { // Cancel the previous request if (s_last_wake_timeout_info != NULL) { s_last_wake_timeout_info->userParam = (void *)1; } s_last_wake_timeout_info= internalRequestTimedCallback(wakeTimeoutCallback, NULL, &TIMEVAL_WAKE_TIMEOUT); } return; error_exit: if (shouldScheduleTimeout) { releaseWakeLock(); } }
這個函數處理modem從網絡端接收到的各類事件,如網絡信號變化,撥入的電話,收到短信等。而後傳給客戶進程。
[cpp] view plaincopyprint?
extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime) {
internalRequestTimedCallback (callback, param, relativeTime);
}
extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { internalRequestTimedCallback (callback, param, relativeTime); }
[cpp] view plaincopyprint?
static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param,
const struct timeval *relativeTime)
{
struct timeval myRelativeTime;
UserCallbackInfo *p_info;
p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo));
p_info->p_callback = callback;
p_info->userParam = param;
if (relativeTime == NULL) {
/* treat null parameter as a 0 relative time */
memset (&myRelativeTime, 0, sizeof(myRelativeTime));
} else {
/* FIXME I think event_add's tv param is really const anyway */
memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime));
}
ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info);
ril_timer_add(&(p_info->event), &myRelativeTime);
triggerEvLoop();
return p_info;
}
static UserCallbackInfo *internalRequestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { struct timeval myRelativeTime; UserCallbackInfo *p_info; p_info = (UserCallbackInfo *) malloc (sizeof(UserCallbackInfo)); p_info->p_callback = callback; p_info->userParam = param; if (relativeTime == NULL) { /* treat null parameter as a 0 relative time */ memset (&myRelativeTime, 0, sizeof(myRelativeTime)); } else { /* FIXME I think event_add's tv param is really const anyway */ memcpy (&myRelativeTime, relativeTime, sizeof(myRelativeTime)); } ril_event_set(&(p_info->event), -1, false, userTimerCallback, p_info); ril_timer_add(&(p_info->event), &myRelativeTime); triggerEvLoop(); return p_info; }
客戶端向Rild發送請求的接口,由各手機廠商實現。
hardware\ril\include\telephony\Ril.h
[cpp] view plaincopyprint?
typedef struct {
int version; //Rild版本
RIL_RequestFunc onRequest; //AP請求接口
RIL_RadioStateRequest onStateRequest;//BP狀態查詢
RIL_Supports supports;
RIL_Cancel onCancel;
RIL_GetVersion getVersion;//動態庫版本
} RIL_RadioFunctions;
typedef struct { int version; //Rild版本 RIL_RequestFunc onRequest; //AP請求接口 RIL_RadioStateRequest onStateRequest;//BP狀態查詢 RIL_Supports supports; RIL_Cancel onCancel; RIL_GetVersion getVersion;//動態庫版本 } RIL_RadioFunctions;
變量定義:
[cpp] view plaincopyprint?
static const RIL_RadioFunctions s_callbacks = {
RIL_VERSION,
onRequest,
currentState,
onSupports,
onCancel,
getVersion
};
static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion };
在hardware\ril\reference-ril\reference-ril.c中實現了RIL_RadioFunctions的各個接口函數
[cpp] view plaincopyprint?
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
ATResponse *p_response;
int err;
LOGD("onRequest: %s", requestToString(request));
/* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
* when RADIO_STATE_UNAVAILABLE.
*/
if (sState == RADIO_STATE_UNAVAILABLE
&& request != RIL_REQUEST_GET_SIM_STATUS
) {
RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
return;
}
/* Ignore all non-power requests when RADIO_STATE_OFF
* (except RIL_REQUEST_GET_SIM_STATUS)
*/
if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER
|| request == RIL_REQUEST_GET_SIM_STATUS)
) {
RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
return;
}
switch (request) {
case RIL_REQUEST_GET_SIM_STATUS: {
RIL_CardStatus *p_card_status;
char *p_buffer;
int buffer_size;
int result = getCardStatus(&p_card_status);
if (result == RIL_E_SUCCESS) {
p_buffer = (char *)p_card_status;
buffer_size = sizeof(*p_card_status);
} else {
p_buffer = NULL;
buffer_size = 0;
}
RIL_onRequestComplete(t, result, p_buffer, buffer_size);
freeCardStatus(p_card_status);
break;
}
case RIL_REQUEST_GET_CURRENT_CALLS:
requestGetCurrentCalls(data, datalen, t);
break;
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
case RIL_REQUEST_HANGUP:
requestHangup(data, datalen, t);
break;
case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
// 3GPP 22.030 6.5.5
// "Releases all held calls or sets User Determined User Busy
// (UDUB) for a waiting call."
at_send_command("AT+CHLD=0", NULL);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
// 3GPP 22.030 6.5.5
// "Releases all active calls (if any exist) and accepts
// the other (held or waiting) call."
at_send_command("AT+CHLD=1", NULL);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
// 3GPP 22.030 6.5.5
// "Places all active calls (if any exist) on hold and accepts
// the other (held or waiting) call."
at_send_command("AT+CHLD=2", NULL);
#ifdef WORKAROUND_ERRONEOUS_ANSWER
s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_ANSWER:
at_send_command("ATA", NULL);
#ifdef WORKAROUND_ERRONEOUS_ANSWER
s_expectAnswer = 1;
#endif /* WORKAROUND_ERRONEOUS_ANSWER */
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_CONFERENCE:
// 3GPP 22.030 6.5.5
// "Adds a held call to the conversation"
at_send_command("AT+CHLD=3", NULL);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_UDUB:
/* user determined user busy */
/* sometimes used: ATH */
at_send_command("ATH", NULL);
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
case RIL_REQUEST_SEPARATE_CONNECTION:
{
char cmd[12];
int party = ((int*)data)[0];
// Make sure that party is in a valid range.
// (Note: The Telephony middle layer imposes a range of 1 to 7.
// It's sufficient for us to just make sure it's single digit.)
if (party > 0 && party < 10) {
sprintf(cmd, "AT+CHLD=2%d", party);
at_send_command(cmd, NULL);
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
}
break;
case RIL_REQUEST_SIGNAL_STRENGTH:
requestSignalStrength(data, datalen, t);
break;
case RIL_REQUEST_REGISTRATION_STATE:
case RIL_REQUEST_GPRS_REGISTRATION_STATE:
requestRegistrationState(request, data, datalen, t);
break;
case RIL_REQUEST_OPERATOR:
requestOperator(data, datalen, t);
break;
case RIL_REQUEST_RADIO_POWER:
requestRadioPower(data, datalen, t);
break;
case RIL_REQUEST_DTMF: {
char c = ((char *)data)[0];
char *cmd;
asprintf(&cmd, "AT+VTS=%c", (int)c);
at_send_command(cmd, NULL);
free(cmd);
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
break;
}
case RIL_REQUEST_SEND_SMS:
requestSendSMS(data, datalen, t);
break;
case RIL_REQUEST_SETUP_DATA_CALL:
requestSetupDataCall(data, datalen, t);
break;
case RIL_REQUEST_SMS_ACKNOWLEDGE:
requestSMSAcknowledge(data, datalen, t);
break;
case RIL_REQUEST_GET_IMSI:
p_response = NULL;
err = at_send_command_numeric("AT+CIMI", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_GET_IMEI:
p_response = NULL;
err = at_send_command_numeric("AT+CGSN", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_SIM_IO:
requestSIM_IO(data,datalen,t);
break;
case RIL_REQUEST_SEND_USSD:
requestSendUSSD(data, datalen, t);
break;
case RIL_REQUEST_CANCEL_USSD:
p_response = NULL;
err = at_send_command_numeric("AT+CUSD=2", &p_response);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS,
p_response->p_intermediates->line, sizeof(char *));
}
at_response_free(p_response);
break;
case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
at_send_command("AT+COPS=0", NULL);
break;
case RIL_REQUEST_DATA_CALL_LIST:
requestDataCallList(data, datalen, t);
break;
case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
requestQueryNetworkSelectionMode(data, datalen, t);
break;
case RIL_REQUEST_OEM_HOOK_RAW:
// echo back data
RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
break;
case RIL_REQUEST_OEM_HOOK_STRINGS: {
int i;
const char ** cur;
LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen);
for (i = (datalen / sizeof (char *)), cur = (const char **)data ;
i > 0 ; cur++, i --) {
LOGD("> '%s'", *cur);
}
// echo back strings
RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen);
break;
}
case RIL_REQUEST_WRITE_SMS_TO_SIM:
requestWriteSmsToSim(data, datalen, t);
break;
case RIL_REQUEST_DELETE_SMS_ON_SIM: {
char * cmd;
p_response = NULL;
asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]);
err = at_send_command(cmd, &p_response);
free(cmd);
if (err < 0 || p_response->success == 0) {
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
} else {
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
at_response_free(p_response);
break;
}
case RIL_REQUEST_ENTER_SIM_PIN:
case RIL_REQUEST_ENTER_SIM_PUK:
case RIL_REQUEST_ENTER_SIM_PIN2:
case RIL_REQUEST_ENTER_SIM_PUK2:
case RIL_REQUEST_CHANGE_SIM_PIN:
case RIL_REQUEST_CHANGE_SIM_PIN2:
requestEnterSimPin(data, datalen, t);
break;
case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION:
requestSmsBroadcastActivation(0,data, datalen, t);
break;
case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG:
LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG");
requestSetSmsBroadcastConfig(0,data, datalen, t);
break;
case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG:
requestGetSmsBroadcastConfig(0,data, datalen, t);
break;
default:
RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
break;
}
}
static void onRequest (int request, void *data, size_t datalen, RIL_Token t) { ATResponse *p_response; int err; LOGD("onRequest: %s", requestToString(request)); /* Ignore all requests except RIL_REQUEST_GET_SIM_STATUS * when RADIO_STATE_UNAVAILABLE. */ if (sState == RADIO_STATE_UNAVAILABLE && request != RIL_REQUEST_GET_SIM_STATUS ) { RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); return; } /* Ignore all non-power requests when RADIO_STATE_OFF * (except RIL_REQUEST_GET_SIM_STATUS) */ if (sState == RADIO_STATE_OFF&& !(request == RIL_REQUEST_RADIO_POWER || request == RIL_REQUEST_GET_SIM_STATUS) ) { RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0); return; } switch (request) { case RIL_REQUEST_GET_SIM_STATUS: { RIL_CardStatus *p_card_status; char *p_buffer; int buffer_size; int result = getCardStatus(&p_card_status); if (result == RIL_E_SUCCESS) { p_buffer = (char *)p_card_status; buffer_size = sizeof(*p_card_status); } else { p_buffer = NULL; buffer_size = 0; } RIL_onRequestComplete(t, result, p_buffer, buffer_size); freeCardStatus(p_card_status); break; } case RIL_REQUEST_GET_CURRENT_CALLS: requestGetCurrentCalls(data, datalen, t); break; case RIL_REQUEST_DIAL: requestDial(data, datalen, t); break; case RIL_REQUEST_HANGUP: requestHangup(data, datalen, t); break; case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: // 3GPP 22.030 6.5.5 // "Releases all held calls or sets User Determined User Busy // (UDUB) for a waiting call." at_send_command("AT+CHLD=0", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: // 3GPP 22.030 6.5.5 // "Releases all active calls (if any exist) and accepts // the other (held or waiting) call." at_send_command("AT+CHLD=1", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: // 3GPP 22.030 6.5.5 // "Places all active calls (if any exist) on hold and accepts // the other (held or waiting) call." at_send_command("AT+CHLD=2", NULL); #ifdef WORKAROUND_ERRONEOUS_ANSWER s_expectAnswer = 1; #endif /* WORKAROUND_ERRONEOUS_ANSWER */ /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_ANSWER: at_send_command("ATA", NULL); #ifdef WORKAROUND_ERRONEOUS_ANSWER s_expectAnswer = 1; #endif /* WORKAROUND_ERRONEOUS_ANSWER */ /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_CONFERENCE: // 3GPP 22.030 6.5.5 // "Adds a held call to the conversation" at_send_command("AT+CHLD=3", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_UDUB: /* user determined user busy */ /* sometimes used: ATH */ at_send_command("ATH", NULL); /* success or failure is ignored by the upper layer here. it will call GET_CURRENT_CALLS and determine success that way */ RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; case RIL_REQUEST_SEPARATE_CONNECTION: { char cmd[12]; int party = ((int*)data)[0]; // Make sure that party is in a valid range. // (Note: The Telephony middle layer imposes a range of 1 to 7. // It's sufficient for us to just make sure it's single digit.) if (party > 0 && party < 10) { sprintf(cmd, "AT+CHLD=2%d", party); at_send_command(cmd, NULL); RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } } break; case RIL_REQUEST_SIGNAL_STRENGTH: requestSignalStrength(data, datalen, t); break; case RIL_REQUEST_REGISTRATION_STATE: case RIL_REQUEST_GPRS_REGISTRATION_STATE: requestRegistrationState(request, data, datalen, t); break; case RIL_REQUEST_OPERATOR: requestOperator(data, datalen, t); break; case RIL_REQUEST_RADIO_POWER: requestRadioPower(data, datalen, t); break; case RIL_REQUEST_DTMF: { char c = ((char *)data)[0]; char *cmd; asprintf(&cmd, "AT+VTS=%c", (int)c); at_send_command(cmd, NULL); free(cmd); RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); break; } case RIL_REQUEST_SEND_SMS: requestSendSMS(data, datalen, t); break; case RIL_REQUEST_SETUP_DATA_CALL: requestSetupDataCall(data, datalen, t); break; case RIL_REQUEST_SMS_ACKNOWLEDGE: requestSMSAcknowledge(data, datalen, t); break; case RIL_REQUEST_GET_IMSI: p_response = NULL; err = at_send_command_numeric("AT+CIMI", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_GET_IMEI: p_response = NULL; err = at_send_command_numeric("AT+CGSN", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_SIM_IO: requestSIM_IO(data,datalen,t); break; case RIL_REQUEST_SEND_USSD: requestSendUSSD(data, datalen, t); break; case RIL_REQUEST_CANCEL_USSD: p_response = NULL; err = at_send_command_numeric("AT+CUSD=2", &p_response); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, p_response->p_intermediates->line, sizeof(char *)); } at_response_free(p_response); break; case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: at_send_command("AT+COPS=0", NULL); break; case RIL_REQUEST_DATA_CALL_LIST: requestDataCallList(data, datalen, t); break; case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: requestQueryNetworkSelectionMode(data, datalen, t); break; case RIL_REQUEST_OEM_HOOK_RAW: // echo back data RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); break; case RIL_REQUEST_OEM_HOOK_STRINGS: { int i; const char ** cur; LOGD("got OEM_HOOK_STRINGS: 0x%8p %lu", data, (long)datalen); for (i = (datalen / sizeof (char *)), cur = (const char **)data ; i > 0 ; cur++, i --) { LOGD("> '%s'", *cur); } // echo back strings RIL_onRequestComplete(t, RIL_E_SUCCESS, data, datalen); break; } case RIL_REQUEST_WRITE_SMS_TO_SIM: requestWriteSmsToSim(data, datalen, t); break; case RIL_REQUEST_DELETE_SMS_ON_SIM: { char * cmd; p_response = NULL; asprintf(&cmd, "AT+CMGD=%d", ((int *)data)[0]); err = at_send_command(cmd, &p_response); free(cmd); if (err < 0 || p_response->success == 0) { RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } else { RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); } at_response_free(p_response); break; } case RIL_REQUEST_ENTER_SIM_PIN: case RIL_REQUEST_ENTER_SIM_PUK: case RIL_REQUEST_ENTER_SIM_PIN2: case RIL_REQUEST_ENTER_SIM_PUK2: case RIL_REQUEST_CHANGE_SIM_PIN: case RIL_REQUEST_CHANGE_SIM_PIN2: requestEnterSimPin(data, datalen, t); break; case RIL_REQUEST_GSM_SMS_BROADCAST_ACTIVATION: requestSmsBroadcastActivation(0,data, datalen, t); break; case RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG: LOGD("onRequest RIL_REQUEST_GSM_SET_BROADCAST_SMS_CONFIG"); requestSetSmsBroadcastConfig(0,data, datalen, t); break; case RIL_REQUEST_GSM_GET_BROADCAST_SMS_CONFIG: requestGetSmsBroadcastConfig(0,data, datalen, t); break; default: RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); break; } }
對每個RIL_REQUEST_XXX請求轉化成相應的ATcommand,發送給modem,而後睡眠等待,當收到ATcommand的最終響應後,線程被喚醒,將響應傳給客戶端進程。
[cpp] view plaincopyprint?
static RIL_RadioState currentState()
{
return sState;
}
static RIL_RadioState currentState() { return sState; }
[cpp] view plaincopyprint?
static int onSupports (int requestCode)
{
//@@@ todo
return 1;
}
static int onSupports (int requestCode) { //@@@ todo return 1; }
[cpp] view plaincopyprint?
static void onCancel (RIL_Token t)
{
//@@@todo
}
static void onCancel (RIL_Token t) { //@@@todo }
[cpp] view plaincopyprint?
static const char * getVersion(void)
{
return "android reference-ril 1.0";
}
static const char * getVersion(void) { return "android reference-ril 1.0"; }
因爲各手機廠商的AT指令差別,所以與modem交互層須要各手機廠商實現,以動態庫的形式提供。做爲介於modem與上層的中間層,即要與底層交互也要與上層通訊,所以就須要定義一個接口來銜接RILD與動態庫,RIL_Env和RIL_RadioFunctions接口就是libril.so與librefrence.so通訊的橋樑。是Rild架構中用於隔離通用代碼和廠商代碼的接口,RIL_Env由通用代碼實現,而RIL_RadioFunctions則是由廠商代碼實現。
RIL_Init的主要任務:
1. 向librefrence.so註冊libril.so提供的接口RIL_Env;
2. 建立一個mainLoop工做線程,用於初始化AT模塊,並監控AT模塊的狀態,一旦AT被關閉,則從新打開並初始化AT;
3. 當AT被打開後,mainLoop工做線程將向Rild提交一個定時事件,並觸發eventLoop來完成對modem的初始化;
4. 建立一個readLoop工做線程,用於從AT串口中讀取數據;
5.返回librefrence.so提供的接口RIL_RadioFunctions;
hardware\ril\reference-ril\reference-ril.c
[cpp] view plaincopyprint?
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
{
int ret;
int fd = -1;
int opt;
pthread_attr_t attr;
s_rilenv = env; //將ril.cpp中定義的RIL_Env註冊到reference-ril.c中的s_rilenv
while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
switch (opt) {
case 'p':
s_port = atoi(optarg);
if (s_port == 0) {
usage(argv[0]);
return NULL;
}
LOGI("Opening loopback port %d\n", s_port);
break;
case 'd':
s_device_path = optarg;
LOGI("Opening tty device %s\n", s_device_path);
break;
case 's':
s_device_path = optarg;
s_device_socket = 1;
LOGI("Opening socket %s\n", s_device_path);
break;
default:
usage(argv[0]);
return NULL;
}
}
if (s_port < 0 && s_device_path == NULL) {
usage(argv[0]);
return NULL;
}
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//建立一個mainLoop線程
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
//將reference-ril.c中定義的RIL_RadioFunctions返回並註冊到ril.cpp中的s_callbacks
return &s_callbacks;
}
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) { int ret; int fd = -1; int opt; pthread_attr_t attr; s_rilenv = env; //將ril.cpp中定義的RIL_Env註冊到reference-ril.c中的s_rilenv while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) { switch (opt) { case 'p': s_port = atoi(optarg); if (s_port == 0) { usage(argv[0]); return NULL; } LOGI("Opening loopback port %d\n", s_port); break; case 'd': s_device_path = optarg; LOGI("Opening tty device %s\n", s_device_path); break; case 's': s_device_path = optarg; s_device_socket = 1; LOGI("Opening socket %s\n", s_device_path); break; default: usage(argv[0]); return NULL; } } if (s_port < 0 && s_device_path == NULL) { usage(argv[0]); return NULL; } pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //建立一個mainLoop線程 ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL); //將reference-ril.c中定義的RIL_RadioFunctions返回並註冊到ril.cpp中的s_callbacks return &s_callbacks; }
mainLoop工做線程是用來初始化並監控AT模塊的,一旦AT模塊被關閉,就自動打開。
[cpp] view plaincopyprint?
static void * mainLoop(void *param)
{
int fd;
int ret;
AT_DUMP("== ", "entering mainLoop()", -1 );
//爲AT模塊設置回調函數
at_set_on_reader_closed(onATReaderClosed);
at_set_on_timeout(onATTimeout);
for (;;) {
fd = -1;
while (fd < 0) { //得到串口AT模塊的設備文件描述符
if (s_port > 0) {
fd = socket_loopback_client(s_port, SOCK_STREAM);
} else if (s_device_socket) {
if (!strcmp(s_device_path, "/dev/socket/qemud")) {
/* Qemu-specific control socket */
fd = socket_local_client( "qemud",
ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM );
if (fd >= 0 ) {
char answer[2];
if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 ||
memcmp(answer, "OK", 2) != 0)
{
close(fd);
fd = -1;
}
}
}
else
fd = socket_local_client( s_device_path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM );
} else if (s_device_path != NULL) {
fd = open (s_device_path, O_RDWR);
if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) {
/* disable echo on serial ports */
struct termios ios;
tcgetattr( fd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd, TCSANOW, &ios );
}
}
if (fd < 0) {
perror ("opening AT interface. retrying...");
sleep(10);
}
}
s_closed = 0;
//打開AT模塊,建立AT讀取線程s_tid_reader,fd爲modem設備文件句柄
ret = at_open(fd, onUnsolicited);
if (ret < 0) {
LOGE ("AT error %d on at_open\n", ret);
return 0;
}
//向Rild提交超時任務
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
sleep(1);
//若是AT模塊被關閉,則waitForClose返回,從新打開AT,若是AT已打開,則阻塞
waitForClose();
LOGI("Re-opening after close");
}
}
static void * mainLoop(void *param) { int fd; int ret; AT_DUMP("== ", "entering mainLoop()", -1 ); //爲AT模塊設置回調函數 at_set_on_reader_closed(onATReaderClosed); at_set_on_timeout(onATTimeout); for (;;) { fd = -1; while (fd < 0) { //得到串口AT模塊的設備文件描述符 if (s_port > 0) { fd = socket_loopback_client(s_port, SOCK_STREAM); } else if (s_device_socket) { if (!strcmp(s_device_path, "/dev/socket/qemud")) { /* Qemu-specific control socket */ fd = socket_local_client( "qemud", ANDROID_SOCKET_NAMESPACE_RESERVED,SOCK_STREAM ); if (fd >= 0 ) { char answer[2]; if ( write(fd, "gsm", 3) != 3 ||read(fd, answer, 2) != 2 || memcmp(answer, "OK", 2) != 0) { close(fd); fd = -1; } } } else fd = socket_local_client( s_device_path, ANDROID_SOCKET_NAMESPACE_FILESYSTEM,SOCK_STREAM ); } else if (s_device_path != NULL) { fd = open (s_device_path, O_RDWR); if ( fd >= 0 && !memcmp( s_device_path, "/dev/ttyS", 9 ) ) { /* disable echo on serial ports */ struct termios ios; tcgetattr( fd, &ios ); ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */ tcsetattr( fd, TCSANOW, &ios ); } } if (fd < 0) { perror ("opening AT interface. retrying..."); sleep(10); } } s_closed = 0; //打開AT模塊,建立AT讀取線程s_tid_reader,fd爲modem設備文件句柄 ret = at_open(fd, onUnsolicited); if (ret < 0) { LOGE ("AT error %d on at_open\n", ret); return 0; } //向Rild提交超時任務 RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); sleep(1); //若是AT模塊被關閉,則waitForClose返回,從新打開AT,若是AT已打開,則阻塞 waitForClose(); LOGI("Re-opening after close"); } }
經過at_open打開文件描述符爲fd的AT串口設備,並註冊回調函數ATUnsolHandler
[cpp] view plaincopyprint?
int at_open(int fd, ATUnsolHandler h)
{
int ret;
pthread_t tid;
pthread_attr_t attr;
s_fd = fd;
s_unsolHandler = h;
s_readerClosed = 0;
s_responsePrefix = NULL;
s_smsPDU = NULL;
sp_response = NULL;
/* Android power control ioctl */
#ifdef HAVE_ANDROID_OS
#ifdef OMAP_CSMI_POWER_CONTROL
ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK);
if(ret == 0) {
int ack_count;
int read_count;
int old_flags;
char sync_buf[256];
old_flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, old_flags | O_NONBLOCK);
do {
ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count);
read_count = 0;
do {
ret = read(fd, sync_buf, sizeof(sync_buf));
if(ret > 0)
read_count += ret;
} while(ret > 0 || (ret < 0 && errno == EINTR));
ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count);
} while(ack_count > 0 || read_count > 0);
fcntl(fd, F_SETFL, old_flags);
s_readCount = 0;
s_ackPowerIoctl = 1;
}
else
s_ackPowerIoctl = 0;
#else // OMAP_CSMI_POWER_CONTROL
s_ackPowerIoctl = 0;
#endif // OMAP_CSMI_POWER_CONTROL
#endif /*HAVE_ANDROID_OS*/
pthread_attr_init (&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//建立readerLoop工做線程,該線程用於從串口讀取數據
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
if (ret < 0) {
perror ("pthread_create");
return -1;
}
return 0;
}
int at_open(int fd, ATUnsolHandler h) { int ret; pthread_t tid; pthread_attr_t attr; s_fd = fd; s_unsolHandler = h; s_readerClosed = 0; s_responsePrefix = NULL; s_smsPDU = NULL; sp_response = NULL; /* Android power control ioctl */ #ifdef HAVE_ANDROID_OS #ifdef OMAP_CSMI_POWER_CONTROL ret = ioctl(fd, OMAP_CSMI_TTY_ENABLE_ACK); if(ret == 0) { int ack_count; int read_count; int old_flags; char sync_buf[256]; old_flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, old_flags | O_NONBLOCK); do { ioctl(fd, OMAP_CSMI_TTY_READ_UNACKED, &ack_count); read_count = 0; do { ret = read(fd, sync_buf, sizeof(sync_buf)); if(ret > 0) read_count += ret; } while(ret > 0 || (ret < 0 && errno == EINTR)); ioctl(fd, OMAP_CSMI_TTY_ACK, &ack_count); } while(ack_count > 0 || read_count > 0); fcntl(fd, F_SETFL, old_flags); s_readCount = 0; s_ackPowerIoctl = 1; } else s_ackPowerIoctl = 0; #else // OMAP_CSMI_POWER_CONTROL s_ackPowerIoctl = 0; #endif // OMAP_CSMI_POWER_CONTROL #endif /*HAVE_ANDROID_OS*/ pthread_attr_init (&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //建立readerLoop工做線程,該線程用於從串口讀取數據 ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr); if (ret < 0) { perror ("pthread_create"); return -1; } return 0; }
[cpp] view plaincopyprint?
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
#define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0); #define RIL_requestTimedCallback(a,b,c) s_rilenv->RequestTimedCallback(a,b,c)
向定時事件隊列中添加一個定時事件,該事件的處理函數爲initializeCallback,用於發送一些AT指令來初始化BP的modem。
Read loop 解析從Modem 發過來的迴應。若是遇到URC 則經過handleUnsolicited 上報的RIL_JAVA。若是是命令的應答,則經過handleFinalResponse 通知send_at_command 有應答結果。
[cpp] view plaincopyprint?
static void *readerLoop(void *arg)
{
for (;;) {
const char * line;
line = readline();
if (line == NULL) {
break;
}
if(isSMSUnsolicited(line)) { //判斷是不是SMS 通知
char *line1;
const char *line2;
line1 = strdup(line);
line2 = readline();
if (line2 == NULL) {
break;
}
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2); //回調通知SMS
}
free(line1);
} else {
processLine(line); //處理接收到的數據,根據line中的指令調用不一樣的回調函數
}
#ifdef HAVE_ANDROID_OS
if (s_ackPowerIoctl > 0) {
/* acknowledge that bytes have been read and processed */
ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount);
s_readCount = 0;
}
#endif /*HAVE_ANDROID_OS*/
}
onReaderClosed();
return NULL;
}
static void *readerLoop(void *arg) { for (;;) { const char * line; line = readline(); if (line == NULL) { break; } if(isSMSUnsolicited(line)) { //判斷是不是SMS 通知 char *line1; const char *line2; line1 = strdup(line); line2 = readline(); if (line2 == NULL) { break; } if (s_unsolHandler != NULL) { s_unsolHandler (line1, line2); //回調通知SMS } free(line1); } else { processLine(line); //處理接收到的數據,根據line中的指令調用不一樣的回調函數 } #ifdef HAVE_ANDROID_OS if (s_ackPowerIoctl > 0) { /* acknowledge that bytes have been read and processed */ ioctl(s_fd, OMAP_CSMI_TTY_ACK, &s_readCount); s_readCount = 0; } #endif /*HAVE_ANDROID_OS*/ } onReaderClosed(); return NULL; }
hardware\ril\libril\ril.cpp
[cpp] view plaincopyprint?
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) {
int ret;
int flags;
//版本驗證
if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) {
return;
}
if (callbacks->version < RIL_VERSION) {
LOGE ("RIL_register: upgrade RIL to version %d current version=%d",
RIL_VERSION, callbacks->version);
}
if (s_registerCalled > 0) {
LOGE("RIL_register has been called more than once. "Subsequent call ignored");
return;
}
//將reference-ril.c中定義的RIL_RadioFunctions註冊到ril.cpp中
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
s_registerCalled = 1;
for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) {
assert(i == s_commands[i].requestNumber); //序號驗證
}
for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) {
assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber);
}
// old standalone impl wants it here.
if (s_started == 0) {
RIL_startEventLoop();
}
// 獲得名爲rild的socket句柄
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
if (s_fdListen < 0) {
LOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
exit(-1);
}
// 監聽該socket
ret = listen(s_fdListen, 4);
if (ret < 0) {
LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno));
exit(-1);
}
/* 設置s_listen_event事件,一旦有客戶端鏈接,即s_fdListen可讀就會致使eventLoop工做線程中的select返回,由於該事件不是持久的,所以調用爲listenCallback處理完後,將從watch_table移除該事件,因此Rild只支持一個客戶端鏈接*/
ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL);
/* 添加s_listen_event事件,並觸發eventLoop工做線程 */
rilEventAddWakeup (&s_listen_event);
#if 1
// 獲得調試socket的句柄rild-debug
s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG);
if (s_fdDebug < 0) {
LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno);
exit(-1);
}
//監聽該socket
ret = listen(s_fdDebug, 4);
if (ret < 0) {
LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno));
exit(-1);
}
/* 設置s_debug_event事件 */
ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL);
/* 添加s_debug_event事件,並觸發eventLoop工做線程 */
rilEventAddWakeup (&s_debug_event);
#endif
}
extern "C" void RIL_register (const RIL_RadioFunctions *callbacks) { int ret; int flags; //版本驗證 if (callbacks == NULL || ((callbacks->version != RIL_VERSION)&& (callbacks->version < 2))) { return; } if (callbacks->version < RIL_VERSION) { LOGE ("RIL_register: upgrade RIL to version %d current version=%d", RIL_VERSION, callbacks->version); } if (s_registerCalled > 0) { LOGE("RIL_register has been called more than once. "Subsequent call ignored"); return; } //將reference-ril.c中定義的RIL_RadioFunctions註冊到ril.cpp中 memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions)); s_registerCalled = 1; for (int i = 0; i < (int)NUM_ELEMS(s_commands); i++) { assert(i == s_commands[i].requestNumber); //序號驗證 } for (int i = 0; i < (int)NUM_ELEMS(s_unsolResponses); i++) { assert(i + RIL_UNSOL_RESPONSE_BASE== s_unsolResponses[i].requestNumber); } // old standalone impl wants it here. if (s_started == 0) { RIL_startEventLoop(); } // 獲得名爲rild的socket句柄 s_fdListen = android_get_control_socket(SOCKET_NAME_RIL); if (s_fdListen < 0) { LOGE("Failed to get socket '" SOCKET_NAME_RIL "'"); exit(-1); } // 監聽該socket ret = listen(s_fdListen, 4); if (ret < 0) { LOGE("Failed to listen on control socket '%d': %s",s_fdListen, strerror(errno)); exit(-1); } /* 設置s_listen_event事件,一旦有客戶端鏈接,即s_fdListen可讀就會致使eventLoop工做線程中的select返回,由於該事件不是持久的,所以調用爲listenCallback處理完後,將從watch_table移除該事件,因此Rild只支持一個客戶端鏈接*/ ril_event_set (&s_listen_event, s_fdListen, false,listenCallback, NULL); /* 添加s_listen_event事件,並觸發eventLoop工做線程 */ rilEventAddWakeup (&s_listen_event); #if 1 // 獲得調試socket的句柄rild-debug s_fdDebug = android_get_control_socket(SOCKET_NAME_RIL_DEBUG); if (s_fdDebug < 0) { LOGE("Failed to get socket '" SOCKET_NAME_RIL_DEBUG "' errno:%d", errno); exit(-1); } //監聽該socket ret = listen(s_fdDebug, 4); if (ret < 0) { LOGE("Failed to listen on ril debug socket '%d': %s",s_fdDebug, strerror(errno)); exit(-1); } /* 設置s_debug_event事件 */ ril_event_set (&s_debug_event, s_fdDebug, true,debugCallback, NULL); /* 添加s_debug_event事件,並觸發eventLoop工做線程 */ rilEventAddWakeup (&s_debug_event); #endif }
打開監聽端口,接收來自客戶端進程的命令請求,當與客戶進程鏈接創建時調用listenCallback函數,建立單獨線程監視並處理全部事件源。
s_listen_event事件用於處理上層客戶端的socket鏈接,當獲得socket鏈接請求時,eventLoop工做線程裏的select返回並自動調用listenCallback回調函數進行處理:
[cpp] view plaincopyprint?
tatic void listenCallback (int fd, short flags, void *param) {
int ret;
int err;
int is_phone_socket;
RecordStream *p_rs;
commthread_data_t *user_data = NULL;
user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t));
struct sockaddr_un peeraddr;
socklen_t socklen = sizeof (peeraddr);
struct ucred creds;
socklen_t szCreds = sizeof(creds);
struct passwd *pwd = NULL;
assert (s_fdCommand < 0);
assert (fd == s_fdListen);
//接收一個客戶端的鏈接,並將該socket鏈接保存在變量s_fdCommand中
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
if (s_fdCommand < 0 ) {
LOGE("Error on accept() errno:%d", errno);
/* start listening for new connections again */
rilEventAddWakeup(&s_listen_event);
return;
}
/* 對客戶端權限判斷,判斷是不是進程組ID爲radio的進程發起的鏈接*/
errno = 0;
is_phone_socket = 0;
err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds);
if (err == 0 && szCreds > 0) {
errno = 0;
pwd = getpwuid(creds.uid);
if (pwd != NULL) {
if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) {
is_phone_socket = 1;
} else {
LOGE("RILD can't accept socket from process %s", pwd->pw_name);
}
} else {
LOGE("Error on getpwuid() errno: %d", errno);
}
} else {
LOGD("Error on getsockopt() errno: %d", errno);
}
if ( !is_phone_socket ) {
LOGE("RILD must accept socket from %s", PHONE_PROCESS);
close(s_fdCommand);
s_fdCommand = -1;
onCommandsSocketClosed();
/* start listening for new connections again */
rilEventAddWakeup(&s_listen_event);
return;
}
#if 0
if(s_dualSimMode) {
if(s_sim_num == 0) {
property_get(SIM_POWER_PROPERTY, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY, "1");
s_callbacks.powerSIM(NULL);
}
} else if(s_sim_num == 1) {
property_get(SIM_POWER_PROPERTY1, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY1, "1");
s_callbacks.powerSIM(NULL);
}
}
} else {
property_get(SIM_POWER_PROPERTY, prop, "0");
if(!strcmp(prop, "0")) {
property_set(SIM_POWER_PROPERTY, "1");
s_callbacks.powerSIM(NULL);
}
}
#endif
//p_rs爲RecordStream類型,它內部會分配一個緩衝區來存儲客戶端發送過來的數據
p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES);
//添加一個針對接收到的客戶端鏈接的處理事件,從而在eventLoop工做線程中處理該客戶端的各類請求
ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs);
rilEventAddWakeup (&s_commands_event);
onNewCommandConnect();
}
tatic void listenCallback (int fd, short flags, void *param) { int ret; int err; int is_phone_socket; RecordStream *p_rs; commthread_data_t *user_data = NULL; user_data =(commthread_data_t *)malloc(sizeof(commthread_data_t)); struct sockaddr_un peeraddr; socklen_t socklen = sizeof (peeraddr); struct ucred creds; socklen_t szCreds = sizeof(creds); struct passwd *pwd = NULL; assert (s_fdCommand < 0); assert (fd == s_fdListen); //接收一個客戶端的鏈接,並將該socket鏈接保存在變量s_fdCommand中 s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen); if (s_fdCommand < 0 ) { LOGE("Error on accept() errno:%d", errno); /* start listening for new connections again */ rilEventAddWakeup(&s_listen_event); return; } /* 對客戶端權限判斷,判斷是不是進程組ID爲radio的進程發起的鏈接*/ errno = 0; is_phone_socket = 0; err = getsockopt(s_fdCommand, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); if (err == 0 && szCreds > 0) { errno = 0; pwd = getpwuid(creds.uid); if (pwd != NULL) { if (strcmp(pwd->pw_name, PHONE_PROCESS) == 0) { is_phone_socket = 1; } else { LOGE("RILD can't accept socket from process %s", pwd->pw_name); } } else { LOGE("Error on getpwuid() errno: %d", errno); } } else { LOGD("Error on getsockopt() errno: %d", errno); } if ( !is_phone_socket ) { LOGE("RILD must accept socket from %s", PHONE_PROCESS); close(s_fdCommand); s_fdCommand = -1; onCommandsSocketClosed(); /* start listening for new connections again */ rilEventAddWakeup(&s_listen_event); return; } #if 0 if(s_dualSimMode) { if(s_sim_num == 0) { property_get(SIM_POWER_PROPERTY, prop, "0"); if(!strcmp(prop, "0")) { property_set(SIM_POWER_PROPERTY, "1"); s_callbacks.powerSIM(NULL); } } else if(s_sim_num == 1) { property_get(SIM_POWER_PROPERTY1, prop, "0"); if(!strcmp(prop, "0")) { property_set(SIM_POWER_PROPERTY1, "1"); s_callbacks.powerSIM(NULL); } } } else { property_get(SIM_POWER_PROPERTY, prop, "0"); if(!strcmp(prop, "0")) { property_set(SIM_POWER_PROPERTY, "1"); s_callbacks.powerSIM(NULL); } } #endif //p_rs爲RecordStream類型,它內部會分配一個緩衝區來存儲客戶端發送過來的數據 p_rs = record_stream_new(s_fdCommand, MAX_COMMAND_BYTES); //添加一個針對接收到的客戶端鏈接的處理事件,從而在eventLoop工做線程中處理該客戶端的各類請求 ril_event_set (&s_commands_event, s_fdCommand, 1,processCommandsCallback, p_rs); rilEventAddWakeup (&s_commands_event); onNewCommandConnect(); }
在listenCallback中首先接收客戶端的鏈接請求,並驗證客戶端的權限,同時將該客戶端以事件的形式添加到eventLoop工做線程中進行監控,當該客戶端有數據請求時,eventLoop工做線程從select中返回,並自動調用processCommandsCallback回調函數:
[cpp] view plaincopyprint?
static void processCommandsCallback(int fd, short flags, void *param) {
RecordStream *p_rs;
void *p_record;
size_t recordlen;
int ret;
assert(fd == s_fdCommand);
p_rs = (RecordStream *)param;
for (;;) { //循環處理客戶端發送過來的AT命令
//讀取一條AT命令
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
if (ret == 0 && p_record == NULL) {
break;
} else if (ret < 0) {
break;
} else if (ret == 0) { /* && p_record != NULL */
//處理客戶端發送過來的AT命令
processCommandBuffer(p_record, recordlen);
}
}
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
if (ret != 0) {
LOGE("error on reading command socket errno:%d\n", errno);
} else {
LOGW("EOS. Closing command socket.");
}
close(s_fdCommand);
s_fdCommand = -1;
ril_event_del(&s_commands_event);
record_stream_free(p_rs);
rilEventAddWakeup(&s_listen_event);
onCommandsSocketClosed();
}
}
static void processCommandsCallback(int fd, short flags, void *param) { RecordStream *p_rs; void *p_record; size_t recordlen; int ret; assert(fd == s_fdCommand); p_rs = (RecordStream *)param; for (;;) { //循環處理客戶端發送過來的AT命令 //讀取一條AT命令 ret = record_stream_get_next(p_rs, &p_record, &recordlen); if (ret == 0 && p_record == NULL) { break; } else if (ret < 0) { break; } else if (ret == 0) { /* && p_record != NULL */ //處理客戶端發送過來的AT命令 processCommandBuffer(p_record, recordlen); } } if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) { if (ret != 0) { LOGE("error on reading command socket errno:%d\n", errno); } else { LOGW("EOS. Closing command socket."); } close(s_fdCommand); s_fdCommand = -1; ril_event_del(&s_commands_event); record_stream_free(p_rs); rilEventAddWakeup(&s_listen_event); onCommandsSocketClosed(); } }
經過processCommandBuffer函數來處理每一條AT命令:
[cpp] view plaincopyprint?
static int processCommandBuffer(void *buffer, size_t buflen) {
Parcel p;
status_t status;
int32_t request;
int32_t token;
RequestInfo *pRI;
int ret;
p.setData((uint8_t *) buffer, buflen);
// status checked at end
status = p.readInt32(&request);
status = p.readInt32 (&token);
if (status != NO_ERROR) {
LOGE("invalid request block");
return 0;
}
if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) {
LOGE("unsupported request code %d token %d", request, token);
return 0;
}
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
pRI->token = token; //AT命令標號
pRI->pCI = &(s_commands[request]); //根據request找到s_commands命令數組中的指定AT命令
ret = pthread_mutex_lock(&s_pendingRequestsMutex);
assert (ret == 0);
pRI->p_next = s_pendingRequests;
s_pendingRequests = pRI;
ret = pthread_mutex_unlock(&s_pendingRequestsMutex);
assert (ret == 0);
//調用指定AT命令的dispatch函數,根據接收來自客戶進程的命令和參數,調用onRequest進行處理。
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
static int processCommandBuffer(void *buffer, size_t buflen) { Parcel p; status_t status; int32_t request; int32_t token; RequestInfo *pRI; int ret; p.setData((uint8_t *) buffer, buflen); // status checked at end status = p.readInt32(&request); status = p.readInt32 (&token); if (status != NO_ERROR) { LOGE("invalid request block"); return 0; } if (request < 1 || request >= (int32_t)NUM_ELEMS(s_commands)) { LOGE("unsupported request code %d token %d", request, token); return 0; } pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo)); pRI->token = token; //AT命令標號 pRI->pCI = &(s_commands[request]); //根據request找到s_commands命令數組中的指定AT命令 ret = pthread_mutex_lock(&s_pendingRequestsMutex); assert (ret == 0); pRI->p_next = s_pendingRequests; s_pendingRequests = pRI; ret = pthread_mutex_unlock(&s_pendingRequestsMutex); assert (ret == 0); //調用指定AT命令的dispatch函數,根據接收來自客戶進程的命令和參數,調用onRequest進行處理。 pRI->pCI->dispatchFunction(p, pRI); return 0; }
打電話的AT命令:{RIL_REQUEST_DIAL, dispatchDial, responseVoid},
發短信的AT命令:{RIL_REQUEST_SEND_SMS, dispatchStrings, responseSMS},
[cpp] view plaincopyprint?
static void dispatchDial (Parcel &p, RequestInfo *pRI) {
RIL_Dial dial; //RIL_Dial存儲了打電話的全部信息
RIL_UUS_Info uusInfo;
int32_t sizeOfDial;
int32_t t;
.................. //初始化dial變量
s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI);
.................
return;
}
static void dispatchDial (Parcel &p, RequestInfo *pRI) { RIL_Dial dial; //RIL_Dial存儲了打電話的全部信息 RIL_UUS_Info uusInfo; int32_t sizeOfDial; int32_t t; .................. //初始化dial變量 s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeOfDial, pRI); ................. return; }
s_callbacks.onRequest其實就是調用RIL_RadioFunctions中的onRequest函數,該函數在前面已介紹過了。
[cpp] view plaincopyprint?
static void onRequest (int request, void *data, size_t datalen, RIL_Token t)
{
switch (request) {
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
break;
}
}
static void onRequest (int request, void *data, size_t datalen, RIL_Token t) { switch (request) { case RIL_REQUEST_DIAL: requestDial(data, datalen, t); break; } }
[cpp] view plaincopyprint?
static void requestDial(void *data, size_t datalen, RIL_Token t)
{
RIL_Dial *p_dial;
char *cmd;
const char *clir;
int ret;
p_dial = (RIL_Dial *)data;
switch (p_dial->clir) {
case 1: clir = "I"; break; /*invocation*/
case 2: clir = "i"; break; /*suppression*/
default:
case 0: clir = ""; break; /*subscription default*/
}
//向串口發送AT指令
ret = at_send_command(cmd, NULL);
free(cmd);
//通知請求結果
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
}
static void requestDial(void *data, size_t datalen, RIL_Token t) { RIL_Dial *p_dial; char *cmd; const char *clir; int ret; p_dial = (RIL_Dial *)data; switch (p_dial->clir) { case 1: clir = "I"; break; /*invocation*/ case 2: clir = "i"; break; /*suppression*/ default: case 0: clir = ""; break; /*subscription default*/ } //向串口發送AT指令 ret = at_send_command(cmd, NULL); free(cmd); //通知請求結果 RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0); }
向AT發送完撥號指令後,經過RIL_onRequestComplete返回處理結果,RIL_onRequestComplete其實是RIL_Env中的OnRequestComplete函數,在前面咱們也介紹過了
[cpp] view plaincopyprint?
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
RequestInfo *pRI;
int ret;
size_t errorOffset;
pRI = (RequestInfo *)t;
//該請求已經處理,須要從請求隊列中移除該請求
if (!checkAndDequeueRequestInfo(pRI)) {
LOGE ("RIL_onRequestComplete: invalid RIL_Token");
return;
}
if (pRI->local > 0) {
...........
sendResponse(p);
}
done:
free(pRI);
}
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RequestInfo *pRI; int ret; size_t errorOffset; pRI = (RequestInfo *)t; //該請求已經處理,須要從請求隊列中移除該請求 if (!checkAndDequeueRequestInfo(pRI)) { LOGE ("RIL_onRequestComplete: invalid RIL_Token"); return; } if (pRI->local > 0) { ........... sendResponse(p); } done: free(pRI); }
[cpp] view plaincopyprint?
static int sendResponse (Parcel &p) {
return sendResponseRaw(p.data(), p.dataSize()); //將結果發送給JAVA RIL客戶端
}
static int sendResponse (Parcel &p) { return sendResponseRaw(p.data(), p.dataSize()); //將結果發送給JAVA RIL客戶端 }
[cpp] view plaincopyprint?
static int sendResponseRaw (const void *data, size_t dataSize) {
int fd = s_fdCommand;
int ret;
uint32_t header;
if (s_fdCommand < 0) {
return -1;
}
if (dataSize > MAX_COMMAND_BYTES) {
return -1;
}
pthread_mutex_lock(&s_writeMutex);
header = htonl(dataSize);
ret = blockingWrite(fd, (void *)&header, sizeof(header));
if (ret < 0) {
pthread_mutex_unlock(&s_writeMutex);
return ret;
}
ret = blockingWrite(fd, data, dataSize);
if (ret < 0) {
pthread_mutex_unlock(&s_writeMutex);
return ret;
}
pthread_mutex_unlock(&s_writeMutex);
return 0;
}
static int sendResponseRaw (const void *data, size_t dataSize) { int fd = s_fdCommand; int ret; uint32_t header; if (s_fdCommand < 0) { return -1; } if (dataSize > MAX_COMMAND_BYTES) { return -1; } pthread_mutex_lock(&s_writeMutex); header = htonl(dataSize); ret = blockingWrite(fd, (void *)&header, sizeof(header)); if (ret < 0) { pthread_mutex_unlock(&s_writeMutex); return ret; } ret = blockingWrite(fd, data, dataSize); if (ret < 0) { pthread_mutex_unlock(&s_writeMutex); return ret; } pthread_mutex_unlock(&s_writeMutex); return 0; }
撥打電話的時序圖以下:
Rild經過onRequest向動態庫提交一個請求,而後返回,動態庫處理完請求後,處理結果經過回調接口通知客戶端