关闭

Android短信发送流程之普通短信发送(原)

标签: TelephonyMMSSMSandroid短信
2682人阅读 评论(0) 收藏 举报
分类:

        我们先来看最简单的流程入手分析,即收件人只有一个,而且不是长短信的情况


一、地址有效性检测


        当点击发送按钮时,触发onClick事件:
        @ComposeMessageActivity.java
        public void onClick(View v) {
            if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) {
                //确认发送
                confirmSendMessageIfNeeded();
            } else if ((v == mRecipientsPicker)) {
                launchMultiplePhonePicker();
            }
        }
        然后进行收件人地址信息的确认
        private void confirmSendMessageIfNeeded() {
            if (!isRecipientsEditorVisible()) {
                //当前的收件人编辑框不可见,说明所发送的对象已经存在短信的会话,也说明当前的收件人地址是ok的
                sendMessage(true);
                return;
            }
            //判断是否为MMS
            boolean isMms = mWorkingMessage.requiresMms();
            if (mRecipientsEditor.hasInvalidRecipient(isMms)) {
                //当前的收件人列表中包含无效地址
                if (mRecipientsEditor.hasValidRecipient(isMms)) {
                    //当前的收件人列表中有无效地址和有效地址,提示用户是否忽略,只发送有效的地址
                    String title = getResourcesString(R.string.has_invalid_recipient,
                            mRecipientsEditor.formatInvalidNumbers(isMms));
                    new AlertDialog.Builder(this)
                        .setTitle(title)
                        .setMessage(R.string.invalid_recipient_message)
                        .setPositiveButton(R.string.try_to_send,
                                new SendIgnoreInvalidRecipientListener())
                        .setNegativeButton(R.string.no, new CancelSendingListener())
                        .show();
                } else {
                    //当前的收件人列表中的地址全部无效,取消发送,提示用户
                    new AlertDialog.Builder(this)
                        .setTitle(R.string.cannot_send_message)
                        .setMessage(R.string.cannot_send_message_reason)
                        .setPositiveButton(R.string.yes, new CancelSendingListener())
                        .show();
                }
            } else {
                //收件人地址都是有效的,发送
                ContactList contacts = mRecipientsEditor.constructContactsFromInput(false);
                mDebugRecipients = contacts.serialize();
                sendMessage(true);
            }
        }
        经过地址有效性检测后,通过sendMessage()继续流程,这里传递的bCheckEcmMode参数代表是否检查当前Phone的状态,处于紧急状态时无法发送短信:
        private void sendMessage(boolean bCheckEcmMode) {
            if (bCheckEcmMode) {
                //判断当前是否为紧急呼叫模式
                String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
                if (Boolean.parseBoolean(inEcm)) {
                    try {
                        //紧急状态下,无法发送短彩信
                        startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), REQUEST_CODE_ECM_EXIT_DIALOG);
                        return;
                    } catch (ActivityNotFoundException e) {
                        Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);
                    }
                }
            }
            //判断当前是否有短信正在发送
            if (!mSendingMessage) {
                //重置收件人控件的监听器
                removeRecipientsListeners();
                //进入WorkingMessage处理流程
                mWorkingMessage.send(mDebugRecipients);


                mSentMessage = true;
                mSendingMessage = true;
                addRecipientsListeners();


                mScrollOnSend = true;   // in the next onQueryComplete, scroll the list to the end.
            }
            // But bail out if we are supposed to exit after the message is sent.
            if (mSendDiscreetMode) {
                finish();
            }
        }


二、创建短彩信的发送线程


        在sendMessage()中经过对当前紧急服务的处理,然后判断如果当前没有短信正在发送,则通过WorkingMessage发送短信。这里的WorkingMessage是处理当前所编辑的信息的工具类,没有父类,在ComposeMessageActivity界面被创建时或者短信被发送出去时创建,主要负责区分短彩信的流程以及发送短信时UI的更新
        @WorkingMessage.java
        public void send(final String recipientsInUI) {
            long origThreadId = mConversation.getThreadId();
            removeSubjectIfEmpty(true /* notify */);
            prepareForSave(true /* notify */);


            //拿到当前的会话
            final Conversation conv = mConversation;
            String msgTxt = mText.toString();


            if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {
                //彩信发送
                if (MmsConfig.getUaProfUrl() == null) {
                    String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +
                        "missing uaProfUrl setting.  uaProfUrl is required for MMS service, " +
                        "but can be absent for SMS.";
                    RuntimeException ex = new NullPointerException(err);
                    Log.e(TAG, err, ex);
                    // now, let's just crash.
                    throw ex;
                }
                final Uri mmsUri = mMessageUri;
                final PduPersister persister = PduPersister.getPduPersister(mActivity);


                final SlideshowModel slideshow = mSlideshow;
                final CharSequence subject = mSubject;
                final boolean textOnly = mAttachmentType == TEXT;




                //彩信发送线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final SendReq sendReq = makeSendReq(conv, subject);
                        slideshow.prepareForSend();
                        sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);
                        updateSendStats(conv);
                    }
                }, "WorkingMessage.send MMS").start();
            } else {
                //短信发送流程
                final String msgText = mText.toString();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        preSendSmsWorker(conv, msgText, recipientsInUI);


                        updateSendStats(conv);
                    }
                }, "WorkingMessage.send SMS").start();
            }


            // update the Recipient cache with the new to address, if it's different
            RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());
            // Mark the message as discarded because it is "off the market" after being sent.
            mDiscarded = true;
        }
        在上面的send流程中,WorkingMessage对短彩信进行分类,分别创建子线程进行发送,本节我们只关注短信流程,他是在preSendSmsWorker()中被发送的:
        private void preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI) {
            UserHappinessSignals.userAcceptedImeText(mActivity);
            //UI刷新
            mStatusListener.onPreMessageSent();
            //获取初始的线程ID
            long origThreadId = conv.getThreadId();
            //获取分配的线程ID
            long threadId = conv.ensureThreadId();
            String semiSepRecipients = conv.getRecipients().serialize();


            // recipientsInUI can be empty when the user types in a number and hits send
            if (LogTag.SEVERE_WARNING && ((origThreadId != 0 && origThreadId != threadId) || (!semiSepRecipients.equals(recipientsInUI) && !TextUtils.isEmpty(recipientsInUI)))) {
            }else {
                //发送短信
                sendSmsWorker(msgText, semiSepRecipients, threadId);
                //删除草稿
                deleteDraftSmsMessage(threadId);
            }
        }

        在上面的preSendSmsWorker中进行了四个处理:

            1、更新UI(更新编辑框等控件);

            2、获取当前发送的ThreadID;

            3、发送短信;

            4、删除草稿;

        接下来我们继续来看发送的过程:
        private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {
            //获取当前发送的收件人地址
            String[] dests = TextUtils.split(semiSepRecipients, ";");
            //获取MessageSender对象,传递进去4个参数分别为:收件人、信息文本、当前的threadId、SimID。
            MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId);
            try {
                //通过MessageSender发送出去
                sender.sendMessage(threadId);
                // Make sure this thread isn't over the limits in message count
                Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
            } catch (Exception e) {
                Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);
            }
            //更新UI
            mStatusListener.onMessageSent();
            MmsWidgetProvider.notifyDatasetChanged(mActivity);
        }

        经过上面WorkingMessage的sendSmsWorker过程,创建了MessageSender对象,并通过该对象的sendMessage()方法将信息发送出去,并在发送之后再次更新UI界面(正在发送中)。


三、通过SmsMessageSender拆分多个收件人


        上面创建的MessageSender对象,继承自MessageSender接口,主要方法只有三个:
        public boolean sendMessage(long token) throws MmsException {};
        private boolean queueMessage(long token) throws MmsException {};
        private String getOutgoingServiceCenter(long threadId) {};
        他的主要作用就是对当前收件人信息拆分后,把群发的短信构建成一个短信队列并保存在数据库中,然后通知SmsReceiverService将队列读取出来并发送出去。
        下面来看其具体实现过程。
        @SmsMessageSender.java
        public boolean sendMessage(long token) throws MmsException {
            return queueMessage(token);
        }
        private boolean queueMessage(long token) throws MmsException {
            if ((mMessageText == null) || (mNumberOfDests == 0)) {
                //空信息不能发送
                throw new MmsException("Null message body or dest.");
            }


            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 {
                    //将当前要发送的短消息放入发送队列中
                    Sms.addMessageToUri(mContext.getContentResolver(),
                            Uri.parse("content://sms/queued"), mDests[i],
                            mMessageText, null, mTimestamp,
                            true /* read */,
                            requestDeliveryReport,
                            mThreadId);
                } catch (SQLiteException e) {
                    if (LogTag.DEBUG_SEND) {
                        Log.e(TAG, "queueMessage SQLiteException", e);
                    }
                    SqliteWrapper.checkSQLiteException(mContext, e);
                }
            }
            //通知SmsReceiverService发送短信
            mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
                        null,
                        mContext,
                        SmsReceiver.class));
            return false;
        }
        在上面这个过程中,将收件人地址拆分后,生成一个短信队列放入"content://sms/queued"中,然后给SmsReceiver发送了通知,这里的SmsReceiver作用仅仅是将该通知转发给SmsReceiverService而已:
        @SmsReceiver.java
        public void onReceive(Context context, Intent intent) {
            onReceiveWithPrivilege(context, intent, false);
        }
        protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
            if (!privileged && intent.getAction().equals(Intents.SMS_DELIVER_ACTION)) {
                return;
            }


            //将请求转交给SmsReceiverService来处理
            intent.setClass(context, SmsReceiverService.class);
            intent.putExtra("result", getResultCode());
            beginStartingService(context, intent);
        }
        也就是说,SmsMessageSender将要发送的短信放入队列中之后,经过SmsReceiver将该消息发送给了SmsReceiverService, 这里的SmsReceiverService是负责短信的收发的Service。
        下面来看SmsReceiverService对于发送短消息的处理过程。
        这个Service被创建时,会创建一个子线程(HandlerThread)以及该线程的Handler对象(ServiceHandler):
        @SmsReceiverService.java
        public void onCreate() {
            //创建子线程处理各种消息
            HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
            thread.start();


            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
        }
        当该Service被启动时,就会对当前的请求进行处理:
        public int onStartCommand(Intent intent, int flags, int startId) {
            mResultCode = intent != null ? intent.getIntExtra("result", 0) : 0;
            //通知Handler处理当前的请求
            Message msg = mServiceHandler.obtainMessage();
            msg.arg1 = startId;
            msg.obj = intent;
            mServiceHandler.sendMessage(msg);
            return Service.START_NOT_STICKY;
        }
        然后看当前Handler的处理:
        private final class ServiceHandler extends Handler {
            public ServiceHandler(Looper looper) {
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                int serviceId = msg.arg1;
                Intent intent = (Intent)msg.obj;
                if (intent != null && MmsConfig.isSmsEnabled(getApplicationContext())) {
                    String action = intent.getAction();
                    int error = intent.getIntExtra("errorCode", 0);


                    if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
                        handleSmsSent(intent, error);
                    } else if (SMS_DELIVER_ACTION.equals(action)) {
                        handleSmsReceived(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();
                    } else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {
                        handleSendInactiveMessage();
                    }
                }
                SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
            }
        }
        从上面的case分支中我们看到,对于当前的发送短信的请求(ACTION_SEND_MESSAGE)将会通过handleSendMessage()来处理:
        private void handleSendMessage() {
            if (!mSending) {
                //当前没有其他任务时就触发发送的操作
                sendFirstQueuedMessage();
            }
        }
        public synchronized void sendFirstQueuedMessage() {
            boolean success = true;
            final Uri uri = Uri.parse("content://sms/queued");
            ContentResolver resolver = getContentResolver();
            //从队列中拿到要发送的短信
            Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, null, null, "date ASC");
            if (c != null) {
                try {
                    //发送队列中第一条短信
                    if (c.moveToFirst()) {
                        String msgText = c.getString(SEND_COLUMN_BODY);
                        String address = c.getString(SEND_COLUMN_ADDRESS);
                        int threadId = c.getInt(SEND_COLUMN_THREAD_ID);
                        int status = c.getInt(SEND_COLUMN_STATUS);
                        int msgId = c.getInt(SEND_COLUMN_ID);
                        Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);
                        //构建SmsSingleRecipientSender对象
                        SmsMessageSender sender = new SmsSingleRecipientSender(this,
                                address, msgText, threadId, status == Sms.STATUS_PENDING,
                                msgUri);


                        try {
                            //发送
                            sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
                            mSending = true;
                        } catch (MmsException e) {
                            mSending = false;
                            messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
                            success = false;
                            sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
                                    null,
                                    this,
                                    SmsReceiver.class));
                        }
                    }
                } finally {
                    c.close();
                }
            }
            if (success) {
                unRegisterForServiceStateChanges();
            }
        }

        我们看到,经过SmsReceiverService中Handler的处理,将数据库中的当前要发送的短信队列取出来,然后取出队列中第一个短消息任务,通过SmsSingleRecipientSender的sendMessage()方法发送出去。至此SmsReceiverService的流程就走完了,他的作用主要就是拿到队列中的第一条短消息,构建SmsSingleRecipientSender对象并发送出去


四、通过SmsSingleRecipientSender拆分长短信


        SmsSingleRecipientSender类继承自SmsMessageSender,他所提供的方法只有一个:
        public boolean sendMessage(long token) throws MmsException {};
        其处理内容就是对长短消息进行分割。然后注册两个广播(一个用于广播当前正在发送,另一个广播短信的送达状态报告),之后通过SmsManager发送出去。
        @SmsSingleRecipientSender.java
        public boolean sendMessage(long token) throws MmsException {
            if (mMessageText == null) {
                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);
                mDest = PhoneNumberUtils.stripSeparators(mDest);
                mDest = Conversation.verifySingleRecipient(mContext, mThreadId, mDest);
            }
            int messageCount = messages.size();


            if (messageCount == 0) {
                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 && (i == (messageCount - 1))) {
                    //所有短信被发送完毕后,在最后一条短信后面添加送达报告的Intent
                    deliveryIntents.add(PendingIntent.getBroadcast(
                                mContext, 0,
                                new Intent(
                                    MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
                                    mUri,
                                    mContext,
                                    MessageStatusReceiver.class),
                                0));
                } else {
                    deliveryIntents.add(null);
                }
                //对于拆分后的短消息,需要在每条信息发送完毕后发送该Intent,从而接着发送剩下的拆分短信
                Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
                        mUri,
                        mContext,
                        SmsReceiver.class);


                int requestCode = 0;
                if (i == messageCount -1) {
                    //收到该附加数据说明当前的拆分短信已经发送完毕
                    requestCode = 1;
                    intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
                }
                sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
            }
            try {
                //发送
                smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
            } catch (Exception ex) {
                throw new MmsException("SmsMessageSender.sendMessage: caught " + ex + " from SmsManager.sendTextMessage()");
            }
            return false;
        }
        经过上面的准备过程,在通过SmsManager发送信息之前,还添加了两个Intent:SmsReceiverService.MESSAGE_SENT_ACTION和MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION。这两个Intent的作用分别是:
        MESSAGE_STATUS_RECEIVED_ACTION:当所有长短信(或短消息)发送完毕后,发送该Intent。
        MESSAGE_SENT_ACTION:分割后的短消息,每发送一条,都会发送该Intent,当最后一条发送完毕后,将会在该Intent中附加EXTRA_MESSAGE_SENT_SEND_NEXT=true的数据
        具体细节在发送完毕后再分析。
        接下来看SmsManager,这里的SmsManager是单例模型,通过其自己的getDefault()或者getSmsManagerForSubscriber()方法就可以得到该对象。
        @SmsManager.java
        public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
            if (TextUtils.isEmpty(destinationAddress)) {
                throw new IllegalArgumentException("Invalid destinationAddress");
            }
            if (parts == null || parts.size() < 1) {
                throw new IllegalArgumentException("Invalid message body");
            }


            if (parts.size() > 1) {
                //长短信发送
                try {
                    ISms iccISms = getISmsServiceOrThrow();
                    iccISms.sendMultipartText(ActivityThread.currentPackageName(),
                            destinationAddress, scAddress, parts,
                            sentIntents, deliveryIntents);
                } catch (RemoteException ex) {
                }
            } else {
                //普通短信发送
                PendingIntent sentIntent = null;
                PendingIntent deliveryIntent = null;
                if (sentIntents != null && sentIntents.size() > 0) {
                    sentIntent = sentIntents.get(0);
                }
                if (deliveryIntents != null && deliveryIntents.size() > 0) {
                    deliveryIntent = deliveryIntents.get(0);
                }
                sendTextMessage(destinationAddress, scAddress, parts.get(0),
                        sentIntent, deliveryIntent);
            }
        }
        在上面的流程中区分了长短信和普通短信的流程,我们目前只分析普通短消息,继续看sendTextMessage():
        public void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
            if (TextUtils.isEmpty(destinationAddress)) {
                throw new IllegalArgumentException("Invalid destinationAddress");
            }


            if (TextUtils.isEmpty(text)) {
                throw new IllegalArgumentException("Invalid message body");
            }


            try {
                //继续
                ISms iccISms = getISmsServiceOrThrow();
                iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, scAddress, text, sentIntent, deliveryIntent);
            } catch (RemoteException ex) {
            }
        }

        到这里,SmsMessage通过调用iccISms对象的sendText()方法将短信继续传递,而SmsMessage的流程就此结束。


五、发送单条短信


        上面的iccISms对象是UiccSmsController的客户端:
        private static ISms getISmsService() {
            return ISms.Stub.asInterface(ServiceManager.getService("isms"));
        }
        所以接下来我们需要进入UiccSmsController的流程中分析:
        @UiccSmsController.java
        public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
            sendTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);
        }
        public void sendTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
            IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
            if (iccSmsIntMgr != null) {
                //通过IccSmsInterfaceManager发送短信
                iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);
            } else {
            }
        }
        在上面的UiccSmsController中将任务交给IccSmsInterfaceManager来继续处理。
        IccSmsInterfaceManager这个类没有父类,他在创建PhoneProxy的时候进行初始化,其作用是把请求发送给相应的处理者。比如对于sendText()将会转交给ImsSMSDispatcher来实现。
        @IccSmsInterfaceManager.java
        public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
            //是否声明了发短信的权限
            mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message");
            //该操作是否被用户允许
            if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) {
                return;
            }
            //调用ImsSMSDispatcher发送
            destAddr = filterDestAddress(destAddr);
            mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, null, callingPackage);
        }
        在上面这个过程中,先进行两级权限检查,然后通过ImsSMSDispatcher发送信息。
        SMSDispatcher总共派生出三个子类:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSMSDispatcher,在IccSmsInterfaceManager创建时只创建ImsSMSDispatcher,而在ImsSMSDispatcher创建过程中会对创建其他两种制式的SMSDispatcher,IccSmsInterfaceManager把请求发送给ImsSMSDispatcher后,由ImsSMSDispatcher根据当前网络状态选择使用CdmaSMSDispatcher还是GsmSMSDispatcher。
        @ImsSMSDispatcher.java
        protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
            //根据当前网络类型发送,我们只分析GSM
            if (isCdmaMo()) {
                mCdmaDispatcher.sendText(destAddr, scAddr,
                        text, sentIntent, deliveryIntent, messageUri, callingPkg);
            } else {
                mGsmDispatcher.sendText(destAddr, scAddr,
                        text, sentIntent, deliveryIntent, messageUri, callingPkg);
            }
        }
        在上面的过程中,根据当前网络环境使用不同的SMSDispatcher,对于GSM网络来说,当前使用的是GsmSMSDispatcher对象。
        这是Framework层与RILJ最接近的对象,他将请求发送给RILJ。
        @GsmSMSDispatcher.java
        protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
            //对短信内容进行编码
            SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( scAddr, destAddr, text, (deliveryIntent != null));
            if (pdu != null) {
                if (messageUri == null) {
                    if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
                        //写入发件箱
                        messageUri = writeOutboxMessage(
                                getSubId(),
                                destAddr,
                                text,
                                deliveryIntent != null,
                                callingPkg);
                    }
                } else {
                    //移到发件箱
                    moveToOutbox(getSubId(), messageUri, callingPkg);
                }
                HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
                //发送
                SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), messageUri, false);
                sendRawPdu(tracker);
            } else {
            }
        }
        在上面的过程中,对短消息内容进行编码,然后把短消息写入(或移入)发件箱,然后利用当前的发地址、收地址、文本、附加Intent等信息创建SmsTracker对象,然后调用sendRawPdu(),这个方法是在GsmSMSDispatcher的父类SMSDispatcher中实现的:
        @SMSDispatcher.java
        protected void sendRawPdu(SmsTracker tracker) {
            HashMap map = tracker.mData;
            byte pdu[] = (byte[]) map.get("pdu");


            if (mSmsSendDisabled) {
                tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
                return;
            }
            if (pdu == null) {
                tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
                return;
            }
            PackageManager pm = mContext.getPackageManager();
            String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());


            if (packageNames == null || packageNames.length == 0) {
                // Refuse to send SMS if we can't get the calling package name.
                tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
                return;
            }


            // Get package info via packagemanager
            PackageInfo appInfo;
            try {
                // XXX this is lossy- apps can share a UID
                appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
            } catch (PackageManager.NameNotFoundException e) {
                Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
                tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
                return;
            }


            // checkDestination() returns true if the destination is not a premium short code or the
            // sending app is approved to send to short codes. Otherwise, a message is sent to our
            // handler with the SmsTracker to request user confirmation before sending.
            if (checkDestination(tracker)) {
                // check for excessive outgoing SMS usage by this app
                if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
                    sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
                    return;
                }
                //发送
                sendSms(tracker);
            }
        }
        这里会对要发送的信息以及当前环境进行检测,然后进入sendSms()流程,这个方法又回到了GsmSMSDispatcher中实现:
        @GsmSMSDispatcher.java
        protected void sendSms(SmsTracker tracker) {
            HashMap<String, Object> map = tracker.mData;
            byte pdu[] = (byte[]) map.get("pdu");


            if (tracker.mRetryCount > 0) {
                // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type
                //   TP-RD (bit 2) is 1 for retry
                //   and TP-MR is set to previously failed sms TP-MR
                if (((0x01 & pdu[0]) == 0x01)) {
                    pdu[0] |= 0x04; // TP-RD
                    pdu[1] = (byte) tracker.mMessageRef; // TP-MR
                }
            }


            // Send SMS via the carrier app.
            BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker);


            Intent intent = new Intent(Intents.SMS_SEND_ACTION);
            String carrierPackage = getCarrierAppPackageName(intent);
            if (carrierPackage != null) {
                intent.setPackage(carrierPackage);
                intent.putExtra("pdu", pdu);
                intent.putExtra("smsc", (byte[]) map.get("smsc"));
                intent.putExtra("format", getFormat());
                if (tracker.mSmsHeader != null && tracker.mSmsHeader.concatRef != null) {
                    SmsHeader.ConcatRef concatRef = tracker.mSmsHeader.concatRef;
                    intent.putExtra("concat.refNumber", concatRef.refNumber);
                    intent.putExtra("concat.seqNumber", concatRef.seqNumber);
                    intent.putExtra("concat.msgCount", concatRef.msgCount);
                }
                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                Rlog.d(TAG, "Sending SMS by carrier app.");
                mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS,
                        AppOpsManager.OP_RECEIVE_SMS, resultReceiver,
                        null, Activity.RESULT_CANCELED, null, null);
            } else {
                //发送
                sendSmsByPstn(tracker);
            }
        }
        然后来看sendSmsByPstn():
        protected void sendSmsByPstn(SmsTracker tracker) {
            int ss = mPhone.getServiceState().getState();
            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
                tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
                return;
            }
            //拿到SmsTracker中保存的信息
            HashMap<String, Object> map = tracker.mData;


            byte smsc[] = (byte[]) map.get("smsc");
            byte[] pdu = (byte[]) map.get("pdu");
            Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);


            if (0 == tracker.mImsRetry && !isIms()) {
                if (tracker.mRetryCount > 0) {
                    if (((0x01 & pdu[0]) == 0x01)) {
                        pdu[0] |= 0x04; // TP-RD
                        pdu[1] = (byte) tracker.mMessageRef; // TP-MR
                    }
                }
                if (tracker.mRetryCount == 0 && tracker.mExpectMore) {
                    //调用RILJ发送短信
                    mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc),
                            IccUtils.bytesToHexString(pdu), reply);
                } else {
                    mCi.sendSMS(IccUtils.bytesToHexString(smsc),
                            IccUtils.bytesToHexString(pdu), reply);
                }
            } else {
                //通过IMS发送短信
                mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc),
                        IccUtils.bytesToHexString(pdu), tracker.mImsRetry,
                        tracker.mMessageRef, reply);
                // increment it here, so in case of SMS_FAIL_RETRY over IMS
                // next retry will be sent using IMS request again.
                tracker.mImsRetry++;
            }
        }
        在上面的发送之前,将SmsTracker中的内容解析出来,通过RILJ发送出去。并且注册了该请求的回应消息EVENT_SEND_SMS_COMPLETE,用于处理短信接收时的流程。

        以上就是普通单收件人,短信的发送流程。

        整个过程的流程图如下:


        下一节来介绍长短信的发送流程

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:303492次
    • 积分:3627
    • 等级:
    • 排名:第9394名
    • 原创:72篇
    • 转载:0篇
    • 译文:0篇
    • 评论:112条
    最新评论