短信发送流程应用层解析
一、涉及的类
- com.android.mms.ui.ComposeMessageActivity
- com.android.mms.data.WorkingMessage
- com.android.mms.transaction.MessageSender
- com.android.mms.transaction.SmsMessageSender
- com.android.mms.transaction.SmsSingleRecipientSender
- com.android.mms.transaction.SmsReceiverService
- com.android.mms.transaction.SmsReceiver
二、时序图
说明:从ui界面开始,到调用中间层SmsManger的方法发送短信,大体时序就是这样,参考代码是android 2.3
三、流程解析
3.1 ComposeMessageActivity工做
该类是咱们编辑短信的UI,与用户交互,以下图所示 android

当用户编辑完成,便可点击发送的按钮,将短信内容发送出去,点击sendbutton就会触发该button对应的监听器,因为ComposeMessageActivity实现了OnClickListener接口,因此最终调用到了onclick方法里。 数据库
1)onClick分析 app
该方法作了两件件事情: ide
一是调用isPreparedForSending方法判断当前短信是否准备发送,依据就是短信短信的接收者是否超过容许的上限,是否有接收者,以及短信是否有内容或者附件、主题之类的,不容许用户发送一条什么都没有的短信出去。 函数
二是,上面的检查经过调用confirmSendMessageIfNeeded方法开始发送流程。固然并非调用了该方法就必定能发送成功,该方法一样会作一系列的检查,直到符合要求了才会放行。 ui
2)confirmSendMessageIfNeeded分析 this
该方法的逻辑调用以下图所示: spa
3)sendMessage方法分析
上图能够看出最后都要走到sendMessage来,咱们来看看这个方法到底作了哪些工做。
经过查看代码咱们能够发现最最核心的工做就是: 把发送短信的工做交给WorkingMessage,mWorkingMessage.send(mDebugRecipients);其余的工做也仅仅是作一些辅助型的操做。
小结:到此为止发送短信的工做交给了WorkingMessage,那
ComposeMessageActivity主要的工做便是对双卡的处理。
3.2 WorkingMessage简单分析
1)send()分析
该方法作了五项工做:
一是 检查接收者列表时否为空,这里我就不作具体的分析。
二是将短信内容从8字节转换成7字节;
三是判断当前是不是发送彩信,咱们当前是短信发送,因此可定不会走彩信的发送流程。
四是,将短信的签名加到短信的内容上。
五是调用preSendSmsWorker()方法。
2)preSendSmsWorker分析
一是重置界面,将界面上的各个组件所有清除
二是调用sendSmsWorker方法
三是删除草稿。
3)sendSmsWorker()所作的工做
调用SmsMessageSender的sendMessage()方法
3.3 SmsMessageSender简析
1)sendMessage()
该方法会调用queueMessage()方法把处理发送的任务抛出去。 .net
2)queueMessage()
它的职责有两个:
一是将要发送的短息保存到数据库;
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
- boolean requestDeliveryReport = prefs.getBoolean(
- MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
- DEFAULT_DELIVERY_REPORT_MODE);
-
- for (int i = 0; i < mNumberOfDests; i++) {
- try {
- log("updating Database with sub = " + mSubscription);
- Sms.addMessageToUri(mContext.getContentResolver(),
- Uri.parse("content://sms/queued"), mDests[i],
- mMessageText, null, mTimestamp,
- true /* read */,
- requestDeliveryReport,
- mThreadId, mSubscription);
- } catch (SQLiteException e) {
- SqliteWrapper.checkSQLiteException(mContext, e);
- }
- }
二是,将任务转交到其余人,只不过它采用的方式是发广播;
- // Notify the SmsReceiverService to send the message out
- Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);
- intent.putExtra(SUBSCRIPTION, mSubscription);
- mContext.sendBroadcast(intent);
小结:该类作了一个很重要的工做就是讲要发送的短信保存进入数据库,而后发广播通知SmsReceiver;
3.4 SmsReceiver 到 SmsReceiverService 简析
实际上SmsReceiver这家伙也不是干事的人,它仅仅是拿到手里后立刻就转交给SmsReceiverService服务了,“这事不归我管,我就是一个送快递的“,SmsReceiver的角色就是这样的,调用的方法能够参考时序图;
3.5 SmsReceiverService 简析
讲了好久终于干活的来了,它既然是一个服务,固然它会走本身的声明周期函数,首先是onCrate,该方法近几年是初始化,而后是onStartCommand(),该方法也没作啥,仅仅是向ServiceHandler发送消息,看来人家作苦力都作出心得了。
1)ServiceHandler处理发送请求
- @Override
- public void handleMessage(Message msg) {
- int serviceId = msg.arg1;
- Intent intent = (Intent)msg.obj;
- if (intent != null) {
- String action = intent.getAction();
-
- int error = intent.getIntExtra("errorCode", 0);
- if (SMS_RECEIVED_ACTION.equals(action)) {
- handleSmsReceived(intent, error);
- } else if (SMS_CB_RECEIVED_ACTION.equals(action)) {
- handleCbSmsReceived(intent, error);
- } else if (ACTION_BOOT_COMPLETED.equals(action)) {
- handleBootCompleted();
- } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
- handleServiceStateChanged(intent);
- } else if (ACTION_SEND_MESSAGE.endsWith(action)) {
- handleSendMessage(intent);
- }
- }
- // NOTE: We MUST not call stopSelf() directly, since we need to
- // make sure the wake lock acquired by AlertReceiver is released.
- SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
- }
- }
这里接收到发送后会走handleSendMessage方法;
2)handleSendMessage()简析:
一、判断双卡是否均可以使用,若是是获取当前的卡并调用sendFirstQueuedMessage(int sub)
二、若是双卡不是均可以使用,就直接调用sendFirstQueuedMessage()方法;
注意:这里是调用的两个不一样的方法,看他们的参数你就知道了,但实际上sendFirstQueuedMessage()无参的函数最终仍是经过调用sendFirstQueuedMessage(int sub)来实现的;至关于最后仍是调用的sendFirstQueuedMessage(int sub)这个方法;
3)sendFirstQueuedMessage(int sub)简析
它首先是从数据库中取出短信,而后调用SmsSingleRecipientSender的sendMessage()方法发送;
小结:你们能够发现走了半天,最后仍是没有开始发送。
3.6 SmsSingleRecipientSender简析
sendMessage()说明:
一是对短信的内容进行分割
二是将短信保存到OUTBOX的数据库表里
三是将分割的短信分开发送
四是调用的SMSManger类的sendMultipartTextMessage()发送,将发送的具体操做转移给中间层。
具体代码以下:
- if (mMessageText == null) {
- // Don't try to send an empty message, and destination should be just
- // one.
- throw new MmsException("Null message body or have multiple destinations.");
- }
- SmsManager smsManager = SmsManager.getDefault();
- ArrayList<String> messages = null;
- if ((MmsConfig.getEmailGateway() != null) &&
- (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {
- String msgText;
- msgText = mDest + " " + mMessageText;
- mDest = MmsConfig.getEmailGateway();
- messages = smsManager.divideMessage(msgText);
- } else {
- messages = smsManager.divideMessage(mMessageText);
- // remove spaces from destination number (e.g. "801 555 1212" -> "8015551212")
- mDest = mDest.replaceAll(" ", "");
- }
- int messageCount = messages.size();
-
- if (messageCount == 0) {
- // Don't try to send an empty message.
- throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " +
- "empty messages. Original message is \"" + mMessageText + "\"");
- }
-
- boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
- if (!moved) {
- throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " +
- "to outbox: " + mUri);
- }
-
- ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount);
- ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
- for (int i = 0; i < messageCount; i++) {
- if (mRequestDeliveryReport) {
- // TODO: Fix: It should not be necessary to
- // specify the class in this intent. Doing that
- // unnecessarily limits customizability.
- deliveryIntents.add(PendingIntent.getBroadcast(
- mContext, 0,
- new Intent(
- MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
- mUri,
- mContext,
- MessageStatusReceiver.class),
- 0));
- }
- Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
- mUri,
- mContext,
- SmsReceiver.class);
-
- int requestCode = 0;
- if (i == messageCount -1) {
- // Changing the requestCode so that a different pending intent
- // is created for the last fragment with
- // EXTRA_MESSAGE_SENT_SEND_NEXT set to true.
- requestCode = 1;
- intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
- intent.putExtra(SUBSCRIPTION, mSubscription);
- }
- sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
- }
- try {
- smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents,
- deliveryIntents, mSubscription);
- } catch (Exception ex) {
- throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +
- " from SmsManager.sendTextMessage()");
- }
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- log("sendMessage: address=" + mDest + ", threadId=" + mThreadId +
- ", uri=" + mUri + ", msgs.count=" + messageCount);
- }