UsimDataDownloadHandlerpublic class UsimDataDownloadHandler extends android.os.Handler Handler for SMS-PP data download messages.
See 3GPP TS 31.111 section 7.1.1 |
Fields Summary |
---|
private static final String | TAG | private static final int | BER_SMS_PP_DOWNLOAD_TAGBER-TLV tag for SMS-PP download. TS 31.111 section 9.1. | private static final int | DEV_ID_UICCDevice identity value for UICC (destination). | private static final int | DEV_ID_NETWORKDevice identity value for network (source). | private static final int | EVENT_START_DATA_DOWNLOADMessage containing new SMS-PP message to process. | private static final int | EVENT_SEND_ENVELOPE_RESPONSEResponse to SMS-PP download envelope command. | private static final int | EVENT_WRITE_SMS_COMPLETEResult of writing SM to UICC (when SMS-PP service is not available). | private final com.android.internal.telephony.CommandsInterface | mCi |
Methods Summary |
---|
private void | acknowledgeSmsWithError(int cause)
mCi.acknowledgeLastIncomingGsmSms(false, cause, null);
| private static int | getEnvelopeBodyLength(int scAddressLength, int tpduLength)Return the size in bytes of the envelope to send to the UICC, excluding the
SMS-PP download tag byte and length byte(s). If the size returned is <= 127,
the BER-TLV length will be encoded in 1 byte, otherwise 2 bytes are required.
// Add 4 bytes for device identities TLV + 1 byte for SMS TPDU tag byte
int length = tpduLength + 5;
// Add 1 byte for TPDU length, or 2 bytes if length > 127
length += (tpduLength > 127 ? 2 : 1);
// Add length of address tag, if present (+ 2 bytes for tag and length)
if (scAddressLength != 0) {
length = length + 2 + scAddressLength;
}
return length;
| private void | handleDataDownload(SmsMessage smsMessage)
int dcs = smsMessage.getDataCodingScheme();
int pid = smsMessage.getProtocolIdentifier();
byte[] pdu = smsMessage.getPdu(); // includes SC address
int scAddressLength = pdu[0] & 0xff;
int tpduIndex = scAddressLength + 1; // start of TPDU
int tpduLength = pdu.length - tpduIndex;
int bodyLength = getEnvelopeBodyLength(scAddressLength, tpduLength);
// Add 1 byte for SMS-PP download tag and 1-2 bytes for BER-TLV length.
// See ETSI TS 102 223 Annex C for encoding of length and tags.
int totalLength = bodyLength + 1 + (bodyLength > 127 ? 2 : 1);
byte[] envelope = new byte[totalLength];
int index = 0;
// SMS-PP download tag and length (assumed to be < 256 bytes).
envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG;
if (bodyLength > 127) {
envelope[index++] = (byte) 0x81; // length 128-255 encoded as 0x81 + length
}
envelope[index++] = (byte) bodyLength;
// Device identities TLV
envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.DEVICE_IDENTITIES.value());
envelope[index++] = (byte) 2;
envelope[index++] = (byte) DEV_ID_NETWORK;
envelope[index++] = (byte) DEV_ID_UICC;
// Address TLV (if present). Encoded length is assumed to be < 127 bytes.
if (scAddressLength != 0) {
envelope[index++] = (byte) ComprehensionTlvTag.ADDRESS.value();
envelope[index++] = (byte) scAddressLength;
System.arraycopy(pdu, 1, envelope, index, scAddressLength);
index += scAddressLength;
}
// SMS TPDU TLV. Length is assumed to be < 256 bytes.
envelope[index++] = (byte) (0x80 | ComprehensionTlvTag.SMS_TPDU.value());
if (tpduLength > 127) {
envelope[index++] = (byte) 0x81; // length 128-255 encoded as 0x81 + length
}
envelope[index++] = (byte) tpduLength;
System.arraycopy(pdu, tpduIndex, envelope, index, tpduLength);
index += tpduLength;
// Verify that we calculated the payload size correctly.
if (index != envelope.length) {
Rlog.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting.");
acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR);
return;
}
String encodedEnvelope = IccUtils.bytesToHexString(envelope);
mCi.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage(
EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid }));
| public void | handleMessage(android.os.Message msg)Handle UICC envelope response and send SMS acknowledgement.
AsyncResult ar;
switch (msg.what) {
case EVENT_START_DATA_DOWNLOAD:
handleDataDownload((SmsMessage) msg.obj);
break;
case EVENT_SEND_ENVELOPE_RESPONSE:
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
Rlog.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception);
acknowledgeSmsWithError(
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
return;
}
int[] dcsPid = (int[]) ar.userObj;
sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]);
break;
case EVENT_WRITE_SMS_COMPLETE:
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
Rlog.d(TAG, "Successfully wrote SMS-PP message to UICC");
mCi.acknowledgeLastIncomingGsmSms(true, 0, null);
} else {
Rlog.d(TAG, "Failed to write SMS-PP message to UICC", ar.exception);
mCi.acknowledgeLastIncomingGsmSms(false,
CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null);
}
break;
default:
Rlog.e(TAG, "Ignoring unexpected message, what=" + msg.what);
}
| int | handleUsimDataDownload(com.android.internal.telephony.uicc.UsimServiceTable ust, SmsMessage smsMessage)Handle SMS-PP data download messages. Normally these are automatically handled by the
radio, but we may have to deal with this type of SM arriving via the IMS stack. If the
data download service is not enabled, try to write to the USIM as an SMS, and send the
UICC response as the acknowledgment to the SMSC.
// If we receive an SMS-PP message before the UsimServiceTable has been loaded,
// assume that the data download service is not present. This is very unlikely to
// happen because the IMS connection will not be established until after the ISIM
// records have been loaded, after the USIM service table has been loaded.
if (ust != null && ust.isAvailable(
UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) {
Rlog.d(TAG, "Received SMS-PP data download, sending to UICC.");
return startDataDownload(smsMessage);
} else {
Rlog.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC.");
String smsc = IccUtils.bytesToHexString(
PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
smsMessage.getServiceCenterAddress()));
mCi.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc,
IccUtils.bytesToHexString(smsMessage.getPdu()),
obtainMessage(EVENT_WRITE_SMS_COMPLETE));
return Activity.RESULT_OK; // acknowledge after response from write to USIM
}
| private static boolean | is7bitDcs(int dcs)Returns whether the DCS is 7 bit. If so, set TP-UDL to the septet count of TP-UD;
otherwise, set TP-UDL to the octet count of TP-UD.
// See 3GPP TS 23.038 section 4
return ((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0);
| private void | sendSmsAckForEnvelopeResponse(com.android.internal.telephony.uicc.IccIoResult response, int dcs, int pid)Handle the response to the ENVELOPE command.
int sw1 = response.sw1;
int sw2 = response.sw2;
boolean success;
if ((sw1 == 0x90 && sw2 == 0x00) || sw1 == 0x91) {
Rlog.d(TAG, "USIM data download succeeded: " + response.toString());
success = true;
} else if (sw1 == 0x93 && sw2 == 0x00) {
Rlog.e(TAG, "USIM data download failed: Toolkit busy");
acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY);
return;
} else if (sw1 == 0x62 || sw1 == 0x63) {
Rlog.e(TAG, "USIM data download failed: " + response.toString());
success = false;
} else {
Rlog.e(TAG, "Unexpected SW1/SW2 response from UICC: " + response.toString());
success = false;
}
byte[] responseBytes = response.payload;
if (responseBytes == null || responseBytes.length == 0) {
if (success) {
mCi.acknowledgeLastIncomingGsmSms(true, 0, null);
} else {
acknowledgeSmsWithError(
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR);
}
return;
}
byte[] smsAckPdu;
int index = 0;
if (success) {
smsAckPdu = new byte[responseBytes.length + 5];
smsAckPdu[index++] = 0x00; // TP-MTI, TP-UDHI
smsAckPdu[index++] = 0x07; // TP-PI: TP-PID, TP-DCS, TP-UDL present
} else {
smsAckPdu = new byte[responseBytes.length + 6];
smsAckPdu[index++] = 0x00; // TP-MTI, TP-UDHI
smsAckPdu[index++] = (byte)
CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR; // TP-FCS
smsAckPdu[index++] = 0x07; // TP-PI: TP-PID, TP-DCS, TP-UDL present
}
smsAckPdu[index++] = (byte) pid;
smsAckPdu[index++] = (byte) dcs;
if (is7bitDcs(dcs)) {
int septetCount = responseBytes.length * 8 / 7;
smsAckPdu[index++] = (byte) septetCount;
} else {
smsAckPdu[index++] = (byte) responseBytes.length;
}
System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length);
mCi.acknowledgeIncomingGsmSmsWithPdu(success,
IccUtils.bytesToHexString(smsAckPdu), null);
| public int | startDataDownload(SmsMessage smsMessage)Start an SMS-PP data download for the specified message. Can be called from a different
thread than this Handler is running on.
if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, smsMessage))) {
return Activity.RESULT_OK; // we will send SMS ACK/ERROR based on UICC response
} else {
Rlog.e(TAG, "startDataDownload failed to send message to start data download.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
|
|