日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android6.0的SMS(短信)源码分析--短信发送

發布時間:2025/3/15 Android 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android6.0的SMS(短信)源码分析--短信发送 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1?????SMS發送流程

1.1???SmsManager

Android發送短信的接口可以認為是SmsManager,當然并不是所有的App都可以發送短信的,必須配置相關的權限。App中可以通過SmsManager.getDefault()得到SmsManager的單例。首先來SmsManager主要提供的接口有哪些。

public static SmsManager

getDefault()獲取?SmsManager?的默認實例

public void

sendTextMessage(

??????????? String destinationAddress, String scAddress, String text,

??????????? PendingIntent sentIntent, PendingIntent deliveryIntent) {

??????? sendTextMessageInternal(destinationAddress, scAddress, text,

??????????? sentIntent, deliveryIntent, true?/* persistMessageForCarrierApp*/);

??? }發送一個基于?SMS?的文本

public void

sendDataMessage(

??????????? String destinationAddress, String scAddress, short destinationPort,

??????????? byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)

發送一個基于?SMS?的數據到指定的應用程序端口

public ArrayList<String>

divideMessage(String text)?當短信超過?SMS?消息的最大長度時,將短信分割為幾塊。

public void

sendMultipartTextMessage(

??????????? String destinationAddress, String scAddress, ArrayList<String> parts,

??????????? ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents)?發送一個基于SMS的多部分文本,調用者應用已經通過調用divideMessage?(String text)將消息分割成正確的大小

我們知道短信有長短信和普通短信的區別。長短信一般需要做分隔處理,而普通短信則不需要。這里重點研究的是普通短信。

普通短信的發送接口為SmsManager. sendTextMessage()。其函數原型和參數解釋如下:

public void?sendTextMessage(String?destinationAddress,?String?scAddress,?String?text,PendingIntent?sentIntent,?

PendingIntent?deliveryIntent)

destinationAddress:?收件人地址?
scAddress:?短信中心號碼,null為默認中心號碼?
sentIntent:?當消息發出時,成功或者失敗的信息報告通過PendingIntent來廣播。如果該參數為空,則發信程序會被所有位置程序檢查一遍,這樣會導致發送時間延長。
deliveryIntent:?當消息發送到收件人時,該PendingIntent會被廣播。pdu數據在狀態報告的extended data ("pdu")中。

下面是SmsManager. sendTextMessage()的具體實現。

??? public void sendTextMessage(

??????????? String destinationAddress, String scAddress, String text,

??????????? PendingIntent sentIntent, PendingIntent deliveryIntent) {

????????sendTextMessageInternal(destinationAddress, scAddress, text,

????????????sentIntent, deliveryIntent, true /* persistMessageForCarrierApp*/);

??? }

可以看到僅僅是轉調了內部方法sendTextMessageInternal()。

??? private void sendTextMessageInternal(String destinationAddress, String scAddress,

??????????? String text, PendingIntent sentIntent, PendingIntent deliveryIntent,

??????????? boolean persistMessageForCarrierApp) {

??????? if (TextUtils.isEmpty(destinationAddress)) {//對目的地址進行非空判斷

??????????? throw new IllegalArgumentException("Invalid destinationAddress");

??????? }

?

??????? if (TextUtils.isEmpty(text)) {//對發送的內容進行非空判斷

??????????? throw new IllegalArgumentException("Invalid message body");

??????? }

?

??????? try {

????????????ISms iccISms = getISmsServiceOrThrow();//獲取isim服務

????????????iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),

????????????????????destinationAddress,

????????????????????scAddress, text, sentIntent, deliveryIntent,

????????????????????persistMessageForCarrierApp);

??????? } catch (RemoteException ex) {

????????????// ignore it

??????? }

??? }

sendTextMessageInternal()首先是獲取了isms系統服務,然后調用了其sendTextForSubscriber()方法。這里可以看出Andorid的一貫風格:App總是將某個任務交給有能力完成該任務的服務去執行。而這里這個有能力完成短信發送任務的系統服務其實就是UiccSmsController(從其構造方法可以看出來它就是isim service),因此進入UiccSmsController.sendTextForSubscriber()。

??? public void sendTextForSubscriber(int subId, String callingPackage, String destAddr,

??????????? String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent,

??????????? boolean persistMessageForNonDefaultSmsApp) {

????????IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);

??????? if (iccSmsIntMgr != null) {

????????????iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent,

????????????????????deliveryIntent, persistMessageForNonDefaultSmsApp);

??????? } else {

??????????? Rlog.e(LOG_TAG,"sendTextForSubscriber iccSmsIntMgr is null for" +

????????????????????????? " Subscription: " + subId);

??????????? sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE);

??????? }

??? }

首先是通過subId獲得對應的IccSmsInterfaceManager,然后調用了其sendText方法。里的subId是調用者SmsManager以參數的形式傳進來的。通過getSubscriptionId()獲取,其主要的邏輯就是如果設置成了默認方式,那就返回默認卡的subId。如果設置成了默認方式但并沒有設置默認卡,則發intent提示用戶設置。如果沒有設置為默認方式,而是通過SmsManager的構造參數傳遞進來的,則直接返回這個參數的值就行了。還有一種可能就是非默認,且SmsManager又是通過getDegault的方式得到的,那這個subId就可能會根據時間變化了,并且可能返回負數。我們不管這里如何得到卡的subId,直接進入ICCSmsInterface.sendText()。

??? public void sendText(String callingPackage, String destAddr, String scAddr,

??????????? String text, PendingIntent sentIntent, PendingIntent deliveryIntent,

??????????? boolean persistMessageForNonDefaultSmsApp) {

???????//檢查是否聲明了發短信的權限

??????? mPhone.getContext().enforceCallingPermission(

??????????????? Manifest.permission.SEND_SMS,

??????????????? "Sending SMS message");

????????sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent,

????????????persistMessageForNonDefaultSmsApp);//轉調了內部方法

??? }

轉調了內部方法sendTextInternal()。

private void sendTextInternal(String callingPackage, String destAddr, String scAddr,

??????????? String text, PendingIntent sentIntent, PendingIntent deliveryIntent,

??????????? boolean persistMessageForNonDefaultSmsApp) {

??????? if (Rlog.isLoggable("SMS", Log.VERBOSE)) {

??????????? log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +

??????????????? " text='"+ text + "' sentIntent=" +

??????????????? sentIntent + " deliveryIntent=" + deliveryIntent);

??????? }

???????//檢查該操作是否被用戶允許

??????? if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),

??????????????? callingPackage) != AppOpsManager.MODE_ALLOWED) {

??????????? return;

??????? }

??????? if (!persistMessageForNonDefaultSmsApp) {

????????????// Only allow carrier app to skip auto message persistence.

??????????? enforceCarrierPrivilege();

??????? }

??????? destAddr = filterDestAddress(destAddr);//對目的地址進行檢測

????????mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,

???????????? ???null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);

??? }

其實就是對短信的權限和目的地址的有效性進行了篩查。然后進行短信的Dispatch。

1.2???SmsDispatcher

SmsDispatcher總共派生出三個子類:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSmsDispatcher,在IccSmsInterfaceManager創建時只創建ImsSMSDispatcher,而在ImsSmsDispatcher創建過程中會對創建其他兩種制式的SmsDispatcher,IccSmsInterfaceManager把請求發送給ImsSMSDispatcher后,由ImsSMSDispatcher根據當前網絡狀態選擇使用CdmaSmsDispatcher還是GsmSmsDispatcher。這里主要以Cdma為例。因此調用的是CdmaSmsDispathcer.sendText()。

??? protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,

??????????? PendingIntent deliveryIntent, Uri messageUri, String callingPkg,

??????????? boolean persistMessage) {

????????//將短信內容包裝成pdu

????????SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(

????? ??????????scAddr, destAddr, text, (deliveryIntent != null), null);

??????? if (pdu != null) {

????????????//接著將短信包裝成tracker

??????????? HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);

????????????SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),messageUri, false /*isExpectMore*/, text, true /*isText*/, persistMessage);

????????????//carrier是運營商的意思,因此這里和運營商有關

????????????String carrierPackage = getCarrierAppPackageName();

??????????? if (carrierPackage != null) {//通過運行商的app發送短信

??????????????? Rlog.d(TAG, "Found carrier package.");

??????????????? TextSmsSender smsSender = new TextSmsSender(tracker);

??????????????? smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));

??????????? } else {

??????????????? Rlog.v(TAG, "No carrier package.");

????????????????sendSubmitPdu(tracker);//一般走這里

??????????? }

??????? } else {

??????????? Rlog.e(TAG, "CdmaSMSDispatcher.sendText(): getSubmitPdu() returned null");

??????????? if (sentIntent != null) {

??????????????? try {

??????????????????? sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);

??????????????? } catch (CanceledException ex) {

??????????????????? Rlog.e(TAG, "Intent has been canceled!");

??????????????? }

??????????? }

??????? }

?? ?}

進入sendSubmitPdu()

??? protected void sendSubmitPdu(SmsTracker tracker) {

????????//緊急回撥模式檢測

??????? if (SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false)) {

??????????? if (VDBG) {

??????????????? Rlog.d(TAG, "Block SMS in Emergency Callback mode");

??????????? }

??????????? tracker.onFailed(mContext, SmsManager.RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);

??????????? return;

??????? }

????????sendRawPdu(tracker);//這里

??? }

進入sendRawPdu()

protected void sendRawPdu(SmsTracker tracker) {

??????? HashMap map = tracker.mData;??//tracker中解析出map

????????byte pdu[] = (byte[]) map.get("pdu");//map中解析出pdu

?

??????? if (mSmsSendDisabled) {//短信發送被禁止了

??????????? Rlog.e(TAG, "Device does not support sending sms.");

??????????? tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);

??????????? return;

??????? }

?

??????? if (pdu == null) {//pdu

??????????? Rlog.e(TAG, "Empty PDU");

??????????? tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);

??????????? return;

??? ????}

?

????????// Get calling app package name via UID from Binder call

??????? 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.

??????????? Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS");

??????????? 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()。

??? protected void sendSms(SmsTracker tracker) {

??????? HashMap<String, Object> map = tracker.mData;

?

????????// byte[] smsc = (byte[]) map.get("smsc");? // unused for CDMA

??????? byte[] pdu = (byte[]) map.get("pdu");//再次從tracker中解出pdu

?

??????? Rlog.d(TAG, "sendSms: "

??????????????? + " isIms()=" + isIms()

??????????????? + " mRetryCount=" + tracker.mRetryCount

??????????????? + " mImsRetry=" + tracker.mImsRetry

??????????????? + " mMessageRef=" + tracker.mMessageRef

??????????????? + " SS=" + mPhone.getServiceState().getState());

?

????????sendSmsByPstn(tracker);//這里

??? }

進入sendSmsByPstn().

??? protected void sendSmsByPstn(SmsTracker tracker) {

??????? int ss = mPhone.getServiceState().getState();//獲取phone狀態

????????// if sms over IMS is not supported on data and voice is not available...

??????? if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {

??????????? tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);

??????????? return;

??????? }

????????//獲取一個發送完成的Message,一遍發送完成后回到HandleMessage

????????Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);

????????byte[] pdu = (byte[]) tracker.mData.get("pdu");//又解出pdu,好頻繁啊

?

??????? int currentDataNetwork = mPhone.getServiceState().getDataNetworkType();

??????? boolean imsSmsDisabled = (currentDataNetwork == TelephonyManager.NETWORK_TYPE_EHRPD

??????????????????? || (currentDataNetwork == TelephonyManager.NETWORK_TYPE_LTE

??????????????????? && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()))

??????????????????? && mPhone.getServiceState().getVoiceNetworkType()

??????????????????? == TelephonyManager.NETWORK_TYPE_1xRTT

??????????????????? && ((CDMAPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE;

?

????? ??// sms over cdma is used:

??????? //?? if sms over IMS is not supported AND

??????? //?? this is not a retry case after sms over IMS failed

??????? //???? indicated by mImsRetry > 0

??????? //注意攜帶了參數reply是一個EVENT_SEND_SMS_COMPLETE, tracker的消息

??????? if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled) {

????????????mCi.sendCdmaSms(pdu, reply);

??????? } else {

????????????mCi.sendImsCdmaSms(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++;//如果是重試,重試次數加1

??????? }

??? }

mCi我們在phone應用的分析中重點分析過,其實就是RILJ。因此進入到了RIL層。關于RIL在phone應用的分析中已經很詳細了,肯定是先構造一個RILRequest,然后將pdu數據寫入,接著send(rr),接著在processSolicited中處理發送結果,并調用rr.mResult.sendToTarget()將結果上傳到到上層(這里是smsDispatcher)。這里對于RILJ以下的處理過程就不贅述了。

當RILJ發送完畢,reply消息被發送,因此sms發送成功的消息被smsDispather接收并HandleMessage。在handleMessage()中直接調用了handleSendComplete()方法。

??? protected void handleSendComplete(AsyncResult ar) {

????????SmsTracker tracker = (SmsTracker) ar.userObj;//ar中解出tracker

????????PendingIntent sentIntent = tracker.mSentIntent;//tracker中解出sendIntent

?

??????? if (ar.result != null) {//解出回應消息

??????????? tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;

??????? } else {

??????????? Rlog.d(TAG, "SmsResponse was null");

??????? }

??????? if (ar.exception == null) {//如果沒有異常,表示發送成功

??????????? if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);

//如果需要等待對方接受的結果狀態,將tracker添加到pendinglist以等待結果

//需要注意的是這里的mSendItentmDeliveryIntent都是pendingIntent,就是留待以后觸發的意思,需要觸發是調用PendingIntent.send()-—網絡總結

??????????? if (tracker.mDeliveryIntent != null) {

????????????????// Expecting a status report.? Add it to the list.

????????????????deliveryPendingList.add(tracker);//留待以后觸發

??????????? }

????????????tracker.onSent(mContext);//發送消息廣播,內部調用了PendingIntent.send()

??????? } else {//如果有異常,表示發送短信失敗

??????????? if (DBG) Rlog.d(TAG, "SMS send failed");

????????????//首先獲取短信的狀態

????????????int ss = mPhone.getServiceState().getState();

????????????//短信發送失敗,可以重試,但服務不再Service狀態,直接將重試次數設到超過最大

??????????? if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {

????????????????// This is retry after failure over IMS but voice is not available.

??????????????? // Set retry to max allowed, so no retry is sent and

??????????????? //?? cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.

??????????????? tracker.mRetryCount = MAX_SEND_RETRIES;//設置最大重試次數,即不重試

?

??????????????? Rlog.d(TAG, "handleSendComplete: Skipping retry: "

??????????????? +" isIms()="+isIms()

??????????????? +" mRetryCount="+tracker.mRetryCount

??????????????? +" mImsRetry="+tracker.mImsRetry

??????????????? +" mMessageRef="+tracker.mMessageRef

??????????????? +" SS= "+mPhone.getServiceState().getState());

??????????? }

????????????// if sms over IMS is not supported on data and voice is not available...

??????????? if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {

??????????????? tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);

??????????? } else if ((((CommandException)(ar.exception)).getCommandError()

??????????????????? == CommandException.Error.SMS_FAIL_RETRY) &&

???????????????? ??tracker.mRetryCount < MAX_SEND_RETRIES) {

????????????????//發送失敗,重試,從這里看出重試次數有次數限制

??????????????? tracker.mRetryCount++;

??????????????? Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);

??????????????? sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);

??????????? } else {

????????????????int errorCode = 0;//默認沒有errorcode

??????????????? if (ar.result != null) {//根據ar設置errorcode

????????????????????errorCode = ((SmsResponse)ar.result).mErrorCode;

????????? ??????}

????????????????int error = RESULT_ERROR_GENERIC_FAILURE;//默認錯誤為這個

??????????????? if (((CommandException)(ar.exception)).getCommandError()

??????????????????????? == CommandException.Error.FDN_CHECK_FAILURE) {

???????????????????//如果底層特殊上報了error,則根據底層設置error

????????????????????error = RESULT_ERROR_FDN_CHECK_FAILURE;

??????????????? }

???????//將錯誤及錯誤code發送到上層,內部同樣調用了PendingIntent.send()觸發執行Intent

????????????????tracker.onFailed(mContext, error, errorCode);

??????????? }

??????? }

??? }

可以看到對于短信的發送失敗和成功狀態的處理,最后都是通過SmsTracker來處理的??偨YRILJ之上的短信發送過程如下圖所示。


1.3???SmsTracker與pendingItent

這里主要涉及到了PendingIntent,因此還有待研究!

1.4???小結

下圖是普通短信的處理流程??梢钥吹降氖?#xff0c;在上層,短信是通過源目地址以及String等體現出來的,接著往底層走是tracker,再接著到RILJ演變成了pdu數據,再到RILRequest下發到RILD。

?

在圖中也畫出了長短信的處理流程,可以看到長短信的處理與普通短信的處理基本類似,僅僅是多了分段處理(在App中)。


原文地址: http://blog.csdn.net/a34140974/article/details/50964080

總結

以上是生活随笔為你收集整理的Android6.0的SMS(短信)源码分析--短信发送的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。