属性
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]
Return sendVsimNotification(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);
}
ArrayList arrList = 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]
....