属性
ro.vendor.mtk_external_sim_support 必须为 1
ro.vendor.mtk_external_sim_only_slots 含义 vsimOnlySlots
ro.vendor.mtk_persist_vsim_disabled
persist.vendor.radio.external.sim 永久vsim (1= persist enabled, 0=disable persist vsim)
vendor.gsm.external.sim.enabled vsim是否启用
vendor.gsm.external.sim.inserted vsim是否插入 (1=loccalsim insert, 2=remote sim inserted)
vendor.gsm.modem.vsim.capability 设置为 2,2 表示都支持热插拔
相关 AT命令
vendor/mediatek/proprietary/hardware/ril/platformlib/common/libmtkrilutils/libmtkrilutils.c
"+ERSAIND",
"AT+ERSA",
"+ERSAAUTH",
"AT+ERSIMATO",
请求
const char* mtkRequestToString(int request) {
.....
// MTK-START: SIM
case RIL_REQUEST_SIM_GET_ATR: return "SIM_GET_ATR";
case RIL_REQUEST_SIM_GET_ICCID: return "RIL_REQUEST_SIM_GET_ICCID";
case RIL_REQUEST_SET_SIM_POWER: return "RIL_REQUEST_SET_SIM_POWER";
// ESIM -START
case RIL_REQUEST_GET_SLOT_STATUS: return "RIL_REQUEST_GET_SLOT_STATUS";
case RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING:
return "RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING";
case RIL_UNSOL_SIM_SLOT_STATUS_CHANGED: return "RIL_UNSOL_SIM_SLOT_STATUS_CHANGED";
// ESIM - END
...
case RIL_UNSOL_VIRTUAL_SIM_ON: return "RIL_UNSOL_VIRTUAL_SIM_ON";
case RIL_UNSOL_VIRTUAL_SIM_OFF: return "RIL_UNSOL_VIRTUAL_SIM_OFF";
...
// External SIM [START]
case RIL_REQUEST_VSIM_NOTIFICATION: return "RIL_REQUEST_VSIM_NOTIFICATION";
case RIL_REQUEST_VSIM_OPERATION: return "RIL_REQUEST_VSIM_OPERATION";
case RIL_UNSOL_VSIM_OPERATION_INDICATION: return "RIL_UNSOL_VSIM_OPERATION_INDICATION";
// External SIM [END]
上面这些代码都是默认启用
ril_service.cpp
... struct RadioImpl : public VENDOR_V3_20::IRadio { ... // External SIM [Start] ReturnsendVsimNotification(int32_t serial, uint32_t transactionId, uint32_t eventId, uint32_t simType); Return sendVsimOperation(int32_t serial, uint32_t transactionId, uint32_t eventId, int32_t result, int32_t dataLength, const hidl_vec & data); // External SIM [End] .... // External SIM [START] bool dispatchVsimEvent(int serial, int slotId, int request, uint32_t transactionId, uint32_t eventId, uint32_t simType) { RequestInfo *pRI = android::addRequestToList(serial, slotId, request); if (pRI == NULL) { return false; } RIL_VsimEvent args; args.transaction_id = transactionId; args.eventId = eventId; args.sim_type = simType; s_vendorFunctions->onRequest(request, &args, sizeof(args), pRI, pRI->socket_id); return true; } bool dispatchVsimOperationEvent(int serial, int slotId, int request, uint32_t transactionId, uint32_t eventId, int32_t result, int32_t dataLength, const hidl_vec & data) { RLOGD("dispatchVsimOperationEvent: enter id=%d", eventId); RequestInfo *pRI = android::addRequestToList(serial, slotId, request); if (pRI == NULL) { RLOGD("dispatchVsimOperationEvent: pRI is NULL."); return false; } RIL_VsimOperationEvent args; memset (&args, 0, sizeof(args)); // Transcation id args.transaction_id = transactionId; // Event id args.eventId = eventId; // Result args.result = result; // Data length args.data_length = dataLength; // Data array const uint8_t *uData = data.data(); args.data= (char *) calloc(1, (sizeof(char) * args.data_length * 2) + 1); memset(args.data, 0, ((sizeof(char) * args.data_length * 2) + 1)); for (int i = 0; i < args.data_length; i++) { sprintf((args.data + (i*2)), "%02X", uData[i]); } //RLOGD("dispatchVsimOperationEvent: id=%d, data=%s", args.eventId, args.data); s_vendorFunctions->onRequest(request, &args, sizeof(args), pRI, pRI->socket_id); free(args.data); return true; } Return RadioImpl::sendVsimNotification(int32_t serial, uint32_t transactionId, uint32_t eventId, uint32_t simType) { RLOGD("sendVsimNotification: serial %d", serial); dispatchVsimEvent(serial, mSlotId, RIL_REQUEST_VSIM_NOTIFICATION, transactionId, eventId, simType); return Void(); } Return RadioImpl::sendVsimOperation(int32_t serial, uint32_t transactionId, uint32_t eventId, int32_t result, int32_t dataLength, const hidl_vec & data) { RLOGD("sendVsimOperation: serial %d", serial); dispatchVsimOperationEvent(serial, mSlotId, RIL_REQUEST_VSIM_OPERATION, transactionId, eventId, result, dataLength, data); return Void(); } int radio::vsimNotificationResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response, size_t responseLen) { RLOGD("vsimNotificationResponse: serial %d, error: %d", serial, e); if (radioService[slotId]->mRadioResponse != NULL) { RadioResponseInfo responseInfo = {}; populateResponseInfo(responseInfo, serial, responseType, e); VsimEvent params = {}; if (response == NULL || responseLen != sizeof(RIL_VsimEvent)) { RLOGE("vsimNotificationResponse: Invalid response"); if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE; } else { RIL_VsimEvent *p_cur = ((RIL_VsimEvent *) response); params.transactionId = p_cur->transaction_id; params.eventId = p_cur->eventId; params.simType = p_cur->sim_type; } Return retStatus = radioService[slotId]->mRadioResponseMtk-> vsimNotificationResponse(responseInfo, params); radioService[slotId]->checkReturnStatus(retStatus, RADIO_MTK); } else { RLOGE("vsimNotificationResponse: radioService[%d]->mRadioResponse == NULL", slotId); } return 0; } int radio::vsimOperationResponse(int slotId, int responseType, int serial, RIL_Errno e, void *response, size_t responseLen) { RLOGD("vsimOperationResponse: serial %d", serial); if (radioService[slotId]->mRadioResponseMtk != NULL) { RadioResponseInfo responseInfo = {}; populateResponseInfo(responseInfo, serial, responseType, e); Return retStatus = radioService[slotId]->mRadioResponseMtk->vsimOperationResponse(responseInfo); radioService[slotId]->checkReturnStatus(retStatus, RADIO_MTK); } else { RLOGE("vsimOperationResponse: radioService[%d]->mRadioResponseMtk == NULL", slotId); } return 0; } int radio::onVsimEventIndication(int slotId, int indicationType, int token, RIL_Errno e, void *response, size_t responselen) { RLOGD("onVsimEventIndication: indicationType %d", indicationType); if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndicationMtk != NULL) { if (response == NULL || responselen == 0) { RLOGE("onVsimEventIndication: invalid response"); return 0; } VsimOperationEvent event = {}; RIL_VsimOperationEvent *response_data = (RIL_VsimOperationEvent *)response; event.transactionId = response_data->transaction_id; event.eventId = response_data->eventId; event.result = response_data->result; event.dataLength = response_data->data_length; event.data = convertCharPtrToHidlString(response_data->data); //RLOGD("onVsimEventIndication: id=%d, data_length=%d, data=%s", event.eventId, response_data->data_length, response_data->data); Return retStatus = radioService[slotId]->mRadioIndicationMtk->onVsimEventIndication( convertIntToRadioIndicationType(indicationType), event); radioService[slotId]->checkReturnStatus(retStatus, RADIO_MTK); } else { RLOGE("onVsimEventIndication: radioService[%d]->mRadioIndicationMtk == NULL", slotId); } return 0; } // External SIM [END]
定义
IRadioIndication.hal
/* * [SIM] Virtual SIM On Indication * @param info Response info struct containing response type, serial no. and error * @param result Indication Data * * Valid errors returned: * RadioError:NONE * RadioError:INVALID_ARGUMENTS * RadioError:GENERIC_FAILURE */ oneway onVirtualSimOn(RadioIndicationType type, int32_t simInserted); /* * [SIM] Virtual SIM Off Indication * @param info Response info struct containing response type, serial no. and error * @param result Indication Data * * Valid errors returned: * RadioError:NONE * RadioError:INVALID_ARGUMENTS * RadioError:GENERIC_FAILURE */ oneway onVirtualSimOff(RadioIndicationType type, int32_t simInserted); ..... // External SIM [Start] /* * Send raw data to external sim manager. * * @param type Type of radio indication * @param event vsim data payload */ oneway onVsimEventIndication(RadioIndicationType type, VsimOperationEvent event); // Exteranl SIM [End]
MTKRil.java
// External SIM [Start] protected RegistrantList mVsimIndicationRegistrants = new RegistrantList(); public void registerForVsimIndication(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); if (RILJ_LOGD) mtkRiljLog("registerForVsimIndication called..."); mVsimIndicationRegistrants.add(r); } public void unregisterForVsimIndication(Handler h) { if (RILJ_LOGD) mtkRiljLog("unregisterForVsimIndication called..."); mVsimIndicationRegistrants.remove(h); } public boolean sendVsimNotification( int transactionId, int eventId, int simType, Message message) { boolean result = true; vendor.mediatek.hardware.radio.V3_0.IRadio radioProxy = getRadioProxy(message); if (radioProxy != null) { RILRequest rr = obtainRequest(RIL_REQUEST_VSIM_NOTIFICATION, message, mRILDefaultWorkSource); if (RILJ_LOGD) { mtkRiljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ", eventId: " + eventId + ", simTpye: " + simType); } try { radioProxy.sendVsimNotification(rr.mSerial, transactionId, eventId, simType); } catch (RemoteException e) { handleRadioProxyExceptionForRR(rr, "sendVsimNotification", e); result = false; } } else { result = false; } return result; } public boolean sendVsimOperation(int transactionId, int eventId, int message, int dataLength, byte[] data, Message response) { boolean result = true; vendor.mediatek.hardware.radio.V3_0.IRadio radioProxy = getRadioProxy(response); if (radioProxy != null) { RILRequest rr = obtainRequest(RIL_REQUEST_VSIM_OPERATION, response, mRILDefaultWorkSource); if (RILJ_LOGD) { mtkRiljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); } if (RILJ_LOGV) { mtkRiljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ", eventId: " + eventId + ", length: " + dataLength); } ArrayListarrList = new ArrayList<>(); for (int i = 0; i < data.length; i++) { arrList.add(data[i]); } try { radioProxy.sendVsimOperation(rr.mSerial, transactionId, eventId, message, dataLength, arrList); } catch (RemoteException e) { handleRadioProxyExceptionForRR(rr, "sendVsimOperation", e); result = false; } } else { result = false; } return result; } // External SIM [End]
mediatek/proprietary/hardware/ril/fusion/mtk-ril/mdcomm/sim/RmcSimUrcEntryHandler.cpp
---需要补代码---
// External SIM [Start] #ifdef MTK_EXTERNAL_SIM_SUPPORT if (RfxRilUtils::isExternalSimSupport()) { RFX_HANDLER_CREATE(mVsimUrcHandler, RmcVsimUrcHandler, (slot_id, channel_id)); } else { mVsimUrcHandler = NULL; } #else mVsimUrcHandler = NULL; #endif // External SIM [End]
mediatek/proprietary/hardware/ril/gsm/mtk-ril/ril_sim.c
// External SIM [Start] #ifdef MTK_EXTERNAL_SIM_SUPPORT extern void requestSwitchExternalSim(RIL_SOCKET_ID rid); extern void onVsimEventDetected(const char *s, RIL_SOCKET_ID rid); extern void onVsimAuthEventDetected(const char *s, RIL_SOCKET_ID rid); extern void requestVsimNotification(void *data, size_t datalen, RIL_Token t); extern void requestVsimOperation(void *data, size_t datalen, RIL_Token t); extern int isVsimEnabledByRid(int rid); #endif // External SIM [End] ... extern int rilSimMain(int request, void *data, size_t datalen, RIL_Token t) { switch (request) { ... // Exteranl SIM [Start] #ifdef MTK_EXTERNAL_SIM_SUPPORT case RIL_REQUEST_VSIM_NOTIFICATION: requestVsimNotification(data, datalen, t); break; case RIL_REQUEST_VSIM_OPERATION: requestVsimOperation(data, datalen, t); break; #endif // External SIM [End] } ..... extern int rilSimUnsolicited(const char *s, const char *sms_pdu, RILChannelCtx* p_channel) { ... // External SIM [Start] #ifdef MTK_EXTERNAL_SIM_SUPPORT } else if (strStartsWith(s, "+EIND: 32")) { // Add for slow SIM card error handling. // Backgournd: get sim status try 30 times with 0.2 second sleep duration. // If the card can't get non-busy status within 6 second, then Java layer always can't // get correct sim status and broadcast them. // Solution: we need a sim status changed unsolicited message to trigger java layer once // modem complete SIM card initialization. // FIXME: Actually, we need an event represent the SIM card complete initialization. // Modem suggest AP use phonebook start to initialization event as a SIM card // initialization done. Might change to other exactly URC in the further. // Reference CR: ALPS02408560 if (isVsimEnabledByRid(rid) && isRecoverySimState[rid] == 1) { isRecoverySimState[rid] = 0; setSimStatusChanged(rid); } return 0; } else if (strStartsWith(s, "+ERSAIND:")) { onVsimEventDetected(s, rid); } else if (strStartsWith(s, "+ERSAAUTH:") || strStartsWith(s, "+ERSIMAUTH:")) { onVsimAuthEventDetected(s, rid); #endif // External SIM [End] }
mediatek/proprietary/hardware/ril/rilproxy/libril/ril.cpp
// M: ril proxy bool cacheUrc(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socket_id){ .... switch(unsolResponse) { ... // External SIM [Start] case RIL_UNSOL_VSIM_OPERATION_INDICATION: // External SIM [End] ....