Android4.2短信小记

一、短信发送流程

1.

ComposeMessageActivity.java

这个类中主要处理用户输入并且响应用户的点击事件。

在onClick()中,函数调用顺序confirmSendMessageIfNeeded()-> sendMessage(true)

2.

sendMessage中会调用到WorkingMessage的send方法:

       

mWorkingMessage.send(mDebugRecipients);



WorkingMessage的send方法会对此时消息做判断,如果包含Email或是MMS则启动彩信发送程序发送SendReq请求向MMSC. 彩信流程将会在以后介绍。

如果send方法判定为短信,则会new新线程。

new Thread(new Runnable() {
@Override
public void run() {
preSendSmsWorker(conv,msgText, recipientsInUI);
updateSendStats(conv);
}
}, "WorkingMessage.sendSMS").start();




3.

在新建线程中会调用preSendSmsWorker函式。

preSendSmsWorker其实只做以下几件事:

a. 调用MessageStatusListener的onPreMessageSent方法通知UI线程更新状态。

b. 调用sendSmsWorker函数去发送短信,参数包含了消息体接收人,所属线程id(此为消息所属会话线程ID,并非操作系统中的线程ID。

4.

sendSmsWorker函数中会创建SmsMessageSender实例并调用其sendMessage函式。

MessageSendersender = new SmsMessageSender(mActivity, dests, msgText, threadId);

sender.sendMessage(threadId);

5.

SmsMessageSender的sendMessage其实只是调用了自己的queueMessage。

queueMessage将消息入队,调用Framework中Telephony.java的内部类Sms,addMessageToUri将消息插入至SMS数据库(数据库的实现在smsprovider.java)

其中主要填写以下字段:

a. SUB_ID: 用于双卡标识

b. ADDRESS:发送地址

c. DATE:发送时间

d. READ:是否已读

e. SUBJECT:短信么有

f. BODY:消息体

g. STATUS:分为STATUS_COMPLETE,STATUS_PENDING,STATUS_FAILED,STATUS_NONE,此时会写为STATUS_PENDING。

h. THREAD_ID:会话线程ID.

值得注意的是STATUS与smsprovider在insert时会加入的TYPE, TYPE 中包含了MESSAGE_TYPE_INBOX,

MESSAGE_TYPE_SENT,

MESSAGE_TYPE_QUEUED,

MESSAGE_TYPE_OUTBOX等等。

此时我们是MESSAGE_TYPE_QUEUED类型。

6.

此时我们从Framework中回到app中。继续看queueMessage函式,在把数据加入队列后会发送广播消息ACTION_SEND_MESSAGE。此消息由SmsReceiver.java去接收。

mContext.sendBroadcast(newIntent(SmsReceiverService.ACTION_SEND_MESSAGE,
null,
mContext,
SmsReceiver.class));




7.

SmsReceiver.java接到消息就去startservice。这是编写android程序时常用的方法,在receiver中启动服务。在receiver中最好不处理长时间的数据,因为如果时间太长会阻塞UI线程并触发ANR。

public void onReceive(Context context, Intent intent) {
       onReceiveWithPrivilege(context, intent, false);
}
protected voidonReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
        if (!privileged &&intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)) {
            return;
        }
        intent.setClass(context,SmsReceiverService.class);
        intent.putExtra("result",getResultCode());
        beginStartingService(context, intent);
    }




8.

SmsReceiverService的handleMessage会接收到ACTION_SEND_MESSAGE,此时会调用handleSendMessage,它会判断是否在发送状态,如果不在发送中则会调用sendFirstQueuedMessage去发送队列中的消息。

      

if(ACTION_SEND_MESSAGE.endsWith(action)) {
            handleSendMessage();
        }
       private voidhandleSendMessage() {
            if (!mSending) {
                sendFirstQueuedMessage();
            }
       }



此队列就是我们之前调用framework的addMessageToUri函式插入的消息的队列。

9.

      

final Uri uri =Uri.parse("content://sms/queued");
        ContentResolverresolver = getContentResolver();
        Cursor c =SqliteWrapper.query(this, resolver, uri,
                       SEND_PROJECTION, null, null, "date ASC");



通过查询队列,取到队列中的消息后我们会构造SmsSingleRecipientSender实例,SmsSingleRecipientSender用于单笔消息的发送。SmsSingleRecipientSender的sendMessage函式将被调用。

       

SmsMessageSendersender = new SmsSingleRecipientSender(this,
                           address, msgText, threadId, status == Sms.STATUS_PENDING,msgUri);
       try {
    sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
            mSending = true;
        } catch (MmsExceptione) {
            mSending = false;
            messageFailedToSend(msgUri,SmsManager.RESULT_ERROR_GENERIC_FAILURE);
            success = false;
        }



10.

sendMessage()主要做了以下几件事:

a.  如果目的地址为EMail地址,则会调用MmsConfig的getEmailGateway()取得预配置的SMS Email发送网关地址作为发送目的地址;

b.  调用SmsManager 的divideMessage;

c. 修改数据库中消息的TYPE,由MESSAGE_TYPE_QUEUED至MESSAGE_TYPE_OUTBOX;

d. 调用SmsManager的sendMultipartTextMessage去发送消息,单卡多卡会出现很多区别,使用的isms服务也存在区别。

11.

      

if (parts.size() > 1) {
            try {
               ISms iccISms =ISms.Stub.asInterface(ServiceManager.getService("isms"));
                if(iccISms != null) {
                   iccISms.sendMultipartText(destinationAddress, scAddress, parts,
                            sentIntents, deliveryIntents);
                }
            } catch(RemoteException ex) {
                //ignore it
            }
        } 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);
        }



这里不管是长短信还是普通短信,注意:

ISms iccISms =ISms.Stub.asInterface(ServiceManager.getService("isms"));

搜索代码可以发现只有IccSmsInterfaceManagerProxy类在ServiceManager登记了isms服务:

public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager
           iccSmsInterfaceManager) {
       this.mIccSmsInterfaceManager = iccSmsInterfaceManager;
       if(ServiceManager.getService("isms") == null) {
            ServiceManager.addService("isms",this);
        }
    }




当是普通短信时,调用SmsManager的sendTextMessage函数,这里同样:

      

try {
            ISmsiccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
            if(iccISms != null) {
                iccISms.sendText(destinationAddress,scAddress, text, sentIntent, deliveryIntent);
            }
        } catch(RemoteException ex) {
            //ignore it
        }



继续看IccSmsInterfaceManagerProxy类的sendText,

mIccSmsInterfaceManager.sendText(destAddr, scAddr, text,sentIntent, deliveryIntent);

继续看IccSmsInterfaceManager类的sendText,

mDispatcher.sendText(destAddr, scAddr, text, sentIntent,deliveryIntent);

查看SMSDispatcher类的sendText,这是个abstract函数:

protected abstract void sendText(String destAddr, String scAddr,

            Stringtext, PendingIntent sentIntent, PendingIntent deliveryIntent);

搜索实现的类,CdmaSMSDispatcher和GsmSMSDispatcher都继承了SMSDispatcher。这里调用了GsmSMSDispatcher的sendText。在PhoneProxy的handleMessage中收到EVENT_RADIO_ON后调用:

mCommandsInterface.getVoiceRadioTechnology(

this.obtainMessage(EVENT_REQUEST_VOICE_RADIO_TECH_DONE));

之后:

case EVENT_VOICE_RADIO_TECH_CHANGED:

        caseEVENT_REQUEST_VOICE_RADIO_TECH_DONE:

            updatePhoneObject(newVoiceTech);

在此调用deleteAndCreatePhone(newVoiceRadioTech),关键之处是:

       

if (ServiceState.isCdma(newVoiceRadioTech)) {
           mActivePhone = PhoneFactory.getCdmaPhone();
        } else if(ServiceState.isGsm(newVoiceRadioTech)) {
           mActivePhone = PhoneFactory.getGsmPhone();
        }



根据手机类型,PhoneFactory创建相应的Phone:

Phone phone = new GSMPhone(sContext, sCommandsInterface,sPhoneNotifier);

在相应的构造函数中实例化SMSDispatcher mSMS:

mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor,mSmsUsageMonitor);

因此短信发送直接调用的是GsmSMSDispatcher的sendText。

12.

无论是sendMultipartText或sendText都会调用到ImsSMSDispatcher的相应函式,并且都会判断其发送方式CDMA或GSM. 两者的实例类为CdmaSMSDispatcher和GsmSMSDispatcher。

在sendText函式中会调用sendRawPdu函式,后会调用CdmaSMSDispatcher或GsmSMSDispatcher的sendSms函式,这里将会调用到Ril的sendSMS.

13.

Ril中将组装RILRequest,并发送至ril层。

14.

当RIL发送成功后processSolicited将接收到RIL_REQUEST_SEND_SMS的response.此时会触发消息并由SMSDispatcher的handleMessage接收,消息名为EVENT_SEND_SMS_COMPLETE,此时会调用handleSendComplete函式并把结果传入(AsyncResult)。

以下几件事会被handleSendComplete执行:

a. 如果发现mDeliveryIntent不等于空则表明需要传送报告,所以会将SmsTracker加入deliveryPendingList以等待传送报告回执。

b. 如果返回的exception不存在,则说明发送时未出现异常,所以会发送intent至SmsReceiver。(可能这里会感觉Ril怎么能知道通知谁并用什么action呢?其实都是得益于发送时传入的deliveryIntents与sentIntents,这个可以查看SmsSingleRecipientSender的sendMessage,每当你发送时都会事先构造好回执的intent.)SmsReceiverService收到MESSAGE_SENT_ACTION后会触发下一个队列中消息的发送。

二、短信接收流程

短信接收是从Ril.cpp通过socket与Ril.java的socket交流,在Ril.java中由RILReceiver进行监听。

             

for (;;) {
                       Parcel p;
                       length = readRilMessage(is, buffer);
                       ………………
                       processResponse(p);
                   }



在这个for循环中读取数据并处理得到的数据。

            

private void processResponse (Parcel p) {
                 int type;
                 type = p.readInt();
                 if (type == RESPONSE_UNSOLICITED) {
                      processUnsolicited (p);
                 } else if (type == RESPONSE_SOLICITED){
                      processSolicited (p);
                 }
                 releaseWakeLockIfDone();
             }



这里有主动上报(比如网络、短信、来电)和被动响应两种处理方式,短信属于主动上报,使用processUnsolicites进行处理。

          

case RIL_UNSOL_RESPONSE_NEW_SMS: {
               ……
               SmsMessage sms;
               sms = SmsMessage.newFromCMT(a);
               if (mGsmSmsRegistrant != null) {
                   mGsmSmsRegistrant
                        .notifyRegistrant(newAsyncResult(null, sms, null));
                }
           break;



最终触发以上方法mGsmSmsRegistrant.notifyRegistrant()。这个方法在GsmSMSDispatcher的构造函数中给CommandsInterface设置handle的处理方法:

        

mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);
        mCm.setOnSmsStatus(this,EVENT_NEW_SMS_STATUS_REPORT, null);
        mCm.setOnNewGsmBroadcastSms(this,EVENT_NEW_BROADCAST_SMS, null);



在SMSDispatcher的handleMessage函数中响应EVENT_NEW_SMS,最终在GsmSMSDispatcher的dispatchMessage函数中的dispatchNormalMessage处理,处理函数是dispatchPdus(pdus)。

       

protected void dispatchPdus(byte[][] pdus) {
             Intent intent = newIntent(Intents.SMS_RECEIVED_ACTION);
             intent.putExtra("pdus", pdus);
             intent.putExtra("format",getFormat());
             dispatch(intent, RECEIVE_SMS_PERMISSION);
         }
       public void dispatch(Intent intent, Stringpermission) {
             mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
             mContext.sendOrderedBroadcast(intent,permission, mResultReceiver,
                  this, Activity.RESULT_OK, null, null);
         }
private final BroadcastReceiver mResultReceiver = newBroadcastReceiver() {
       @Override
        publicvoid onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION) ||
                   intent.getAction().equals(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION)) {
               // Ignore this intent. Apps will process it.
            }else {
               // Assume the intent is one of the SMS receive intents that
               // was sent as an ordered broadcast. Check result and ACK.
               int rc = getResultCode();
               boolean success = (rc == Activity.RESULT_OK) || (rc ==Intents.RESULT_SMS_HANDLED);
 
               // For a multi-part message, this only ACKs the last part.
               // Previous parts were ACK'd as they were received.
               acknowledgeLastIncomingSms(success, rc, null);
 //子类调用接口mCm.acknowledgeLastIncomingGsmSms(success,resultToCause(result), response);
            }
        }
    };



最后,可以看出这个方法将短信通过顺序广播播放出去(action是SMS_RECEIVED_ACTION= "android.provider.Telephony.SMS_RECEIVED";),无论广播是否被中断最后都会调用mResultReceiver,这里会将已读或未读的状态告诉给对方。 如果短信广播中间没有受到終止,那么接下来的流程是:在最上层的 APP中Mms模块中transation中的PrivilegedSmsReceiver类接收到android.provider.Telephony.SMS_RECEIVED广播请求,并获取携带短信数据的intent,然后调用intent.setClass(context,SmsReceiverService.class); 启动SmsReceiverService服务类来处理短信并保存短信(短信内容号码在PrivilegedSmsReceiver中接收到的intent里面)。

       

protected void onReceiveWithPrivilege(Contextcontext, Intent intent, boolean privileged) {
        if(!privileged && intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)){
           return;
        }
       intent.setClass(context, SmsReceiverService.class);
       intent.putExtra("result", getResultCode());
       beginStartingService(context, intent);
    }



最上层的App中的Mms里面:发送和接收短信的过程:

PrivilegedSmsReceiver把intent传递到 SmsReceiverService中SmsReceiverService中

      

@Override
    public voidonCreate() {
        //Temporarily removed for this duplicate message track down.
//        if(Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
//           Log.v(TAG, "onCreate");
//        }
 
        //Start up the thread running the service. Note that we create a
        //separate thread because the service normally runs in the process's
        // mainthread, which we don't want to block.
       HandlerThread thread = new HandlerThread(TAG,Process.THREAD_PRIORITY_BACKGROUND);
       thread.start();
 
       mServiceLooper = thread.getLooper();
       mServiceHandler = new ServiceHandler(mServiceLooper);
    }
@Override
    public intonStartCommand(Intent intent, int flags, int startId) {
        //Temporarily removed for this duplicate message track down.
//        if(Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
//            Log.v(TAG, "onStart: #" + startId +": " + intent.getExtras());
//        }
 
       mResultCode = intent != null ? intent.getIntExtra("result", 0): 0;
 
        Messagemsg = mServiceHandler.obtainMessage();
       msg.arg1 = startId;
        msg.obj= intent;
       mServiceHandler.sendMessage(msg);
        returnService.START_NOT_STICKY;
    }
        启动service,调用 onStartCommand()把 intent转到Message里面,发送到ServiceHandler中处理
private final class ServiceHandler extends Handler {
        publicServiceHandler(Looper looper) {
           super(looper);
        }
 
        /**
         *Handle incoming transaction requests.
         * Theincoming requests are initiated by the MMSC Server or by the MMS Client itself.
         */
       @Override
        public voidhandleMessage(Message msg) {
            intserviceId = msg.arg1;
           Intent intent = (Intent)msg.obj;
            if(intent != null) {
               String action = intent.getAction();
 
               int error = intent.getIntExtra("errorCode", 0);
 
               if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
                   handleSmsSent(intent, error);
               } else 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();
               } else if (Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(action)) {
                   handleWapPushReceived(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);
        }
    }



接收短信时,调用 handleSmsReceived()保存短信,得到 messageUri,通知更新相关标识符:

保存短信的过程分为两种情况:替换和保存(更新和插入数据表(Inbox.CONTENT_URI))