转:http://xiaoyuang.com/print.php?id=12586
首先,了解下彩信收发的宏观步骤:
a、 终端A向彩信中心(MMSC)发送一条彩信,通过WAP网关POST到MMSC
b、 MMSC通过PushProxy网关,向SMSC(短信中心)发送PUSH消息,SMSC转发到终端B
c、 终端B通过WAP网关利用GET方法从MMSC获取一条彩信
d、 MMSC通过PushProxy网关和SNSC向终端A发送一条传送报告(delivery report)
从上面这个步骤可以看出,彩信的接收分两个步骤:
1、接收到短信。
2、分析短信然后通过http来获取彩信附件。
因此彩信第一步跟短信的接收流程一样,在RILReceiver
接收到短信转到processUnsolicited进行处理。
GSM 方式(最近才知道短信的收发有两种,一种就是通过GSM,另一种是通过CDMA):
GSM其事件类型为
RIL_UNSOL_RESPONSE_NEW_SMS。先调用responseString从Parcel中获取数据,再使用
newFromCMT方法获取SmsMessage对象,最后调用mSMSRegistrant的notifyRegistrant方法设置消息类型
(what属性为EVENT_NEW_SMS)并转到SMSDispatcher进行处理。这个时候就会调用子类(GsmSMSDispatcher)的
dispatchMessage方法处理。
protected int dispatchMessage(SmsMessageBase smsb) {
// If sms is
null, means there was a parsing error.
if (smsb == null) {
return Intents.RESULT_SMS_GENERIC_ERROR;
}
SmsMessage sms = (SmsMessage) smsb;
boolean handled = false;
if (sms.isTypeZero()) {
// As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not
be
// Displayed/Stored/Notified. They should only be
acknowledged.
Log.d(TAG, "Received short message type 0, Dont display or store
it. Send Ack");
return Intents.RESULT_SMS_HANDLED;
}
// Special case the message waiting indicator messages
if (sms.isMWISetMessage()) {
mGsmPhone.updateMessageWaitingIndicator(true);
handled = sms.isMwiDontStore();
if (Config.LOGD) {
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" +
!handled);
}
} else if (sms.isMWIClearMessage()) {
mGsmPhone.updateMessageWaitingIndicator(false);
handled = sms.isMwiDontStore();
if (Config.LOGD) {
Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" +
!handled);
}
}
if (handled) {
return Intents.RESULT_SMS_HANDLED;
}
if (!mStorageAvailable &&
(sms.getMessageClass() != MessageClass.CLASS_0)) {
// Its a storable message and theres no storage available.
Bail.
// (See TS 23.038 for a description of class 0 messages.)
return Intents.RESULT_SMS_OUT_OF_MEMORY;
}
SmsHeader smsHeader = sms.getUserDataHeader();
// See if message is partial or port addressed.
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
// Message is not partial (not part of concatenated
sequence).
byte[][] pdus = new byte[1][];
pdus[0] = sms.getPdu();
if (smsHeader != null &&
smsHeader.portAddrs != null) {
if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH)
{
return mWapPush.dispatchWapPdu(sms.getUserData());
} else {
// The message was sent to a port, so concoct a URI for it.
dispatchPortAddressedPdus(pdus,
smsHeader.portAddrs.destPort);
}
} else {
// Normal short and non-port-addressed message, dispatch it.
dispatchPdus(pdus);
}
return Activity.RESULT_OK;
} else {
// Process the message part.
return processMessagePart(sms, smsHeader.concatRef,
smsHeader.portAddrs);
}
}
在这个方法里,将会判断接收到的短信是否长短信、是否彩信、是否普通短信。
首先获取SmsHeader,
如果SmsHeader或SmsHeader.concatRef均不为空,说明是长短信,则调用processMessagePart将短信分段存入
raw表,待所有分段都收到后,将其组装。然后根据端口的不同,按照彩信通知(WapPushOverSms的dispatchWapPdu方法)、指定端口的彩信(dispatchPortAddressedPdus)、长短信(dispatchPdus)进行分发处理。
继续分析彩信,如果是彩信就调用WapPushOverSms类dispatchWapPdu的方法。(该类的位置)
public int
dispatchWapPdu(byte[] pdu) {
if (Config.LOGD) Log.d(LOG_TAG, "Rx: " +
IccUtils.bytesToHexString(pdu));
int index = 0;
int transactionId = pdu[index++] &
0xFF;
int pduType = pdu[index++] & 0xFF;
int headerLength = 0;
if ((pduType != WspTypeDecoder.PDU_TYPE_PUSH)
&&
(pduType != WspTypeDecoder.PDU_TYPE_CONFIRMED_PUSH)) {
if (Config.LOGD) Log.w(LOG_TAG, "Received non-PUSH WAP PDU. Type =
" + pduType);
return Intents.RESULT_SMS_HANDLED;
}
pduDecoder = new WspTypeDecoder(pdu);
if (pduDecoder.decodeUintvarInteger(index) == false) {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Length
error.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
headerLength = (int)pduDecoder.getValue32();
index += pduDecoder.getDecodedDataLength();
int headerStartIndex = index;
if (pduDecoder.decodeContentType(index) == false) {
if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Header Content-Type
error.");
return Intents.RESULT_SMS_GENERIC_ERROR;
}
int binaryContentType;
String mimeType = pduDecoder.getValueString();
if (mimeType == null) {
binaryContentType = (int)pduDecoder.getValue32();
// TODO we should have more generic way to map binaryContentType
code to mimeType.