Android平台 短信接送流程剖析(含编码)
//框架层分析:
//GsmSMSDispatcher.java
/** {@inheritDoc} */
@Override
protected int dispatchMessage(SmsMessageBase smsb) { //该函数的返回值会在handleMessage里进行判断是否为Activity.RESULT_OK。要注意该返回值不为Activity.RESULT_OK的情况。
// 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()) { //0x0100 0000 Short Message Type 0 The MS does not indicate the receipt of the type 0 short message to the user,and the message is not stored in the(U)SIM or ME.
// 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, Don't display or store it. Send Ack");
return Intents.RESULT_SMS_HANDLED;
}
if (mSmsReceiveDisabled) {
// Device doesn't support SMS service,
Log.d(TAG, "Received short message on device which doesn't support "
+ "SMS service. Ignored.");
return Intents.RESULT_SMS_HANDLED;
}
// Special case the message waiting indicator messages
if (sms.isMWISetMessage()) {
updateMessageWaitingIndicator(true);
handled = sms.isMwiDontStore();
if (Config.LOGD) {
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
}
} else if (sms.isMWIClearMessage()) {
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)) {
// It's a storable message and there's 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);
}
}
//SMSDispatcher.java
protected void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus); //pdu数据
intent.putExtra("encoding", getEncoding());
dispatch(intent, "android.permission.RECEIVE_SMS");
}
//应用层分析:
<!-- Require sender permissions to prevent SMS spoofing -->
<receiver android:name=".transaction.PrivilegedSmsReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
//PrivilegedSmsReceiver类从SmsReceiver派生。在SmsReceiver(extends BroadcastReceiver)类中的onReceiveWithPrivilege 会将服务SmsReceiverService启动,然后在handleSmsReceived函数中对接收的消息进行处理。
//SmsReceiverService.java
//入口
private void handleSmsReceived(Intent intent, int error) {
SmsMessage[] msgs = Intents.getMessagesFromIntent(intent); //解析intent,获取SmsMessage转①分析
Uri messageUri = insertMessage(this, msgs, error); //插入数据 转②分析
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
SmsMessage sms = msgs[0];
Log.v(TAG, "handleSmsReceived" + (sms.isReplace() ? "(replace)" : "") +
" messageUri: " + messageUri +
", address: " + sms.getOriginatingAddress() +
", body: " + sms.getMessageBody());
}
if (messageUri != null) {
// Called off of the UI thread so ok to block.
MessagingNotification.blockingUpdateNewMessageIndicator(this, true, false);
}
}
//①分析
//Telephony.java
public static final SmsMessage[] getMessagesFromIntent(Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
byte[][] pduObjs = new byte[messages.length][];
int encoding = intent.getIntExtra("encoding", -1);
for (int i = 0; i < messages.length; i++) {
pduObjs[i] = (byte[]) messages[i];
}
byte[][] pdus = new byte[pduObjs.length][];
int pduCount = pdus.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
for (int i = 0; i < pduCount; i++) {
pdus[i] = pduObjs[i];
if (-1 != encoding) {
msgs[i] = SmsMessage.createFromPdu(pdus[i], encoding);
} else {
msgs[i] = SmsMessage.createFromPdu(pdus[i]); //创建PDU
}
}
return msgs;
}
}
//②分析:
private Uri insertMessage(Context context, SmsMessage[] msgs, int error) {
// Build the helper classes to parse the messages.
SmsMessage sms = msgs[0];
if (sms.getMessageClass() == SmsMessage.MessageClass.CLASS_0) {
displayClassZeroMessage(context, sms); //直接显示
return null;
} else if (sms.isReplace()) {
return replaceMessage(context, msgs, error);
} else {
return storeMessage(context, msgs, error);//存储短信 转③分析
}
}
//③分析
private Uri storeMessage(Context context, SmsMessage[] msgs, int error) {
SmsMessage sms = msgs[0];
// Store the message in the content provider.
ContentValues values = extractContentValues(sms); //提取信息
values.put(Sms.ERROR_CODE, error);
int pduCount = msgs.length;
if (pduCount == 1) {
// There is only one part, so grab the body directly.
values.put(Inbox.BODY, replaceFormFeeds(sms.getDisplayMessageBody()));
} else {
// Build up the body from the parts.
StringBuilder body = new StringBuilder();
for (int i = 0; i < pduCount; i++) {
sms = msgs[i];
body.append(sms.getDisplayMessageBody());
}
values.put(Inbox.BODY, replaceFormFeeds(body.toString()));
}
// Make sure we've got a thread id so after the insert we'll be able to delete
// excess messages.
Long threadId = values.getAsLong(Sms.THREAD_ID);
String address = values.getAsString(Sms.ADDRESS); //注意对地址的处理
if (!TextUtils.isEmpty(address)) {
Contact cacheContact = Contact.get(address,true);
if (cacheContact != null) {
address = cacheContact.getNumber();
}
} else {
address = getString(R.string.unknown_sender);
values.put(Sms.ADDRESS, address);
}
if (((threadId == null) || (threadId == 0)) && (address != null)) {
threadId = Threads.getOrCreateThreadId(context, address);
values.put(Sms.THREAD_ID, threadId);
}
ContentResolver resolver = context.getContentResolver();
Uri insertedUri = SqliteWrapper.insert(context, resolver, Inbox.CONTENT_URI, values);
// Now make sure we're not over the limit in stored messages
Recycler.getSmsRecycler().deleteOldMessagesByThreadId(getApplicationContext(), threadId);
return insertedUri;
}