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; }