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

歡迎訪問 生活随笔!

生活随笔

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

Android

Android开发之Android5.1.1(CM12.1)源码中短信发送流程解析

發布時間:2025/3/15 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android开发之Android5.1.1(CM12.1)源码中短信发送流程解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先我要從SmsManager開始一步步深入了解,相信大家在學習Android基礎的時候接觸過這個類。它在/frameworks/opt/telephony/src/java/android/telephony路徑下,SmsManager:提供管理短信操作,如發送數據,文本和PDU短信。通過調用靜態方法SmsManager.getDefault() 獲取此對象。它里面提供了一系列發送短信的方法,我們就從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.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),destinationAddress,scAddress, text, sentIntent, deliveryIntent);} catch (RemoteException ex){// ignore it} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

先判斷地址和短信內容是否為空,并且拋出異常信息,然后通過ISms這樣一個東西調用sendTextForSubscriber()方法將短信往下一個類進行傳遞。

getISmsServiceOrThrow():獲取ISms服務。?
destinationAddress:收短信人的地址。?
scAddress:短信號碼中心,如果傳null則為默認短信號碼中心。?
text:短信內容。?
sentIntent:短信發送成功或者失敗的廣播。?
deliveryIntent:對方收到短信時候的廣播。?
getSubscriptionId():獲取訂閱id。?
ActivityThread.currentPackageName():當前的包名。

在上面接觸到ISms這樣一個東西,那么他是干嘛的呢?其實它一個接口,在frameworks/base/telephony/java/com/android/internal/telephony下面,我們會找到它,會發現它是是一個aidl文件,打開它是一個接口(interface),這是我們就要去找另外一個類了,在android5.1.1中有能力完成短信發送任務的系統服務它就是UiccSmsController.java。它在/frameworks/opt/telephony/src/java/com/android/internal/telephony路徑下面,UiccSmsController:提供一個進程間通信訪問ICC中的短信。打開它會發現這樣的繼承關系:

public class UiccSmsController extends ISms.Stub
  • 1
  • 1

里面有這樣的一段代碼:

public void sendText(String callingPackage, String destAddr, String scAddr,String text, PendingIntent sentIntent, PendingIntent deliveryIntent){sendTextForSubscriber(getDefaultSmsSubId(), callingPackage, destAddr,scAddr, text, sentIntent, deliveryIntent);}public void sendTextForSubscriber(int subId, String callingPackage,String destAddr, String scAddr,String text,PendingIntent sentIntent, PendingIntent deliveryIntent){sendTextWithOptionsUsingSubscriber(subId, callingPackage, destAddr,scAddr, text, sentIntent, deliveryIntent, -1, false, -1);}public void sendTextWithOptionsUsingSubscriber(int subId,String callingPackage, String destAddr,String scAddr, String text,PendingIntent sentIntent, PendingIntent deliveryIntent,int priority, boolean isExpectMore, int validityPeriod){mContext.enforceCallingPermission(android.Manifest.permission.SEND_SMS,"Sending SMS message");IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);if (iccSmsIntMgr.isShortSMSCode(destAddr)){iccSmsIntMgr.sendTextWithOptions(callingPackage, destAddr, scAddr,text, sentIntent, deliveryIntent, priority, isExpectMore,validityPeriod);return;}ArrayList<String> parts = new ArrayList<String>();parts.add(text);ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();sentIntents.add(sentIntent);ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();deliveryIntents.add(deliveryIntent);broadcastOutgoingSms(subId, callingPackage, destAddr, scAddr, false,parts, sentIntents, deliveryIntents, priority, isExpectMore,validityPeriod);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

可以看出現進行權限的操作,然后調用了IccSmsInterfaceManager 的sendTextWithOptions方法將短信進一步傳遞,后面進行廣播的處理。通過getDefaultSmsSubId()獲得了一個手機卡的默認SubId,在同級路徑下找到IccSmsInterfaceManager 類打開之后,又會發現,它調用SMSDispatcher的sendText()方法將短信進一步傳遞。在同級路徑下我們打開SMSDispatcher 會發現它是一個抽象類,并且繼承了Handler。如下:

public abstract class SMSDispatcher extends Handler
  • 1
  • 1

既然是抽象類,那肯定就有實現它的派生類,在Android5.1.1中我找到了三個派生類:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSmsDispatcher。但是在IccSmsInterfaceManager 中只創建了ImsSmsDispatcher。

protected IccSmsInterfaceManager(PhoneBase phone){mPhone = phone;mContext = phone.getContext();mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);mDispatcher = new ImsSMSDispatcher(phone, phone.mSmsStorageMonitor,phone.mSmsUsageMonitor);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在同級路徑下打開ImsSmsDispatcher.java我們會發現,ImsSmsDispatcher持有了CdmaSMSDispatcher、GsmSMSDispatcher這兩個對象的實例:

private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher;
  • 1
  • 2
  • 1
  • 2

通過判斷網絡制式,分別調用mCdmaDispatcher或者mGsmDispatcher的sendText()方法。?
判斷網絡制式:

/*** Determines whether or not to use CDMA format for MO SMS. If SMS over IMS* is supported, then format is based on IMS SMS format, otherwise format is* based on current phone type.** @return true if Cdma format should be used for MO SMS, false otherwise.*/private boolean isCdmaMo(){if (!isIms() || !shouldSendSmsOverIms()){// Either IMS is not registered or there is an active 1x voice call// while on eHRPD, use Voice technology to determine SMS format.return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType());}// IMS is registered with SMS supportreturn isCdmaFormat(mImsSmsFormat);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

這兒我們以mGsmDispatcher作為下一步講解對象,繼續研究短信的發送。在frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm路徑下打開GsmSMSDispatcher,找到sendText()方法,如下:

@Overrideprotected void sendText(String destAddr, String scAddr, String text,PendingIntent sentIntent,PendingIntent deliveryIntent,Uri messageUri, String callingPkg, int priority,boolean isExpectMore, int validityPeriod){SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddr, destAddr,text,(deliveryIntent != null), validityPeriod);if (pdu != null){HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,getFormat(),messageUri, isExpectMore,text /* fullMessageText */, true /* isText */,validityPeriod);String carrierPackage = getCarrierAppPackageName();if (carrierPackage != null){Rlog.d(TAG, "Found carrier package.");TextSmsSender smsSender = new TextSmsSender(tracker);smsSender.sendSmsByCarrierApp(carrierPackage,new SmsSenderCallback(smsSender));} else{Rlog.v(TAG, "No carrier package.");sendRawPdu(tracker);}} else{Rlog.e(TAG,"GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

我們會發現,首先將短信組裝成pdu格式,然后進一步將pdu組裝成為一個SmsTracker ,getCarrierAppPackageName():獲取手機內置的載體app,一般手機廠商都不會內置這個,所以一般都會走sendRawPdu()這個方法。這個方法在父類SMSDispatcher 中,所以我們又得去父類看:

protected void sendRawPdu(SmsTracker tracker){HashMap map = tracker.mData;byte pdu[] = (byte[]) map.get("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){Rlog.e(TAG, "Empty PDU");tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/* errorCode */);return;}PendingIntent sentIntent = tracker.mSentIntent;// Get calling app package name via UID from Binder callPackageManager pm = mContext.getPackageManager();int callingUid = Binder.getCallingUid();// Special case: We're being proxied by the telephony stack itself,// so use the intent generator's UID if one existsString[] packageNames;if (callingUid == android.os.Process.PHONE_UID && sentIntent != null&& sentIntent.getCreatorPackage() != null){packageNames = new String[]{ sentIntent.getCreatorPackage() };} else{packageNames = pm.getPackagesForUid(callingUid);}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 packagemanagerPackageInfo appInfo;try{// XXX this is lossy- apps can share a UIDappInfo = 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 appif (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)){sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));return;}sendSms(tracker);}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

從上面可以得知,先從tracker中取出data,之后再取出pdu。?
判斷短信發送是否可用?
pdu是否為空。?
checkDestination(tracker):判斷內置的short code和發送的short code是否一致。?
然后調用GsmSMSDispatcher的sendSms()方法:

@Overrideprotected void sendSms(SmsTracker tracker){HashMap<String, Object> map = tracker.mData;byte pdu[] = (byte[]) map.get("pdu");if (tracker.mRetryCount > 0){Rlog.d(TAG, "sendSms: " + " mRetryCount=" + tracker.mRetryCount+ " mMessageRef=" + tracker.mMessageRef + " SS="+ mPhone.getServiceState().getState());// 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-MRif (((0x01 & pdu[0]) == 0x01)){pdu[0] |= 0x04; // TP-RDpdu[1] = (byte) tracker.mMessageRef; // TP-MR}}Rlog.d(TAG, "sendSms: " + " isIms()=" + isIms() + " mRetryCount="+ tracker.mRetryCount + " mImsRetry=" + tracker.mImsRetry+ " mMessageRef=" + tracker.mMessageRef + " SS="+ mPhone.getServiceState().getState());sendSmsByPstn(tracker);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

可以看到上面需要對短信進行一個處理,判斷重試次數,如果大于0就將第一個字節賦值為0x04 至于為什么是0x04我也不知道,?
TP-RD:是否拒絕相同重復消息。?
TP-MR:消息基準值。?
現在來看GsmSMSDispatcher的sendSmsByPstn()方法又干了些什么事情。

@Overrideprotected void sendSmsByPstn(SmsTracker tracker){int 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 */);return;}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);// sms over gsm is used:// if sms over IMS is not supported AND// this is not a retry case after sms over IMS failed// indicated by mImsRetry > 0if (0 == tracker.mImsRetry && !isIms()){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-MRif (((0x01 & pdu[0]) == 0x01)){pdu[0] |= 0x04; // TP-RDpdu[1] = (byte) tracker.mMessageRef; // TP-MR}}if (tracker.mRetryCount == 0 && tracker.mExpectMore){mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc),IccUtils.bytesToHexString(pdu), reply);} else{mCi.sendSMS(IccUtils.bytesToHexString(smsc),IccUtils.bytesToHexString(pdu), reply);}} else{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++;}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

先是對手機狀態進行判斷,然后又將pdu取出來,然后弄了一個發送完成的消息。?
isIms():判斷IMS是否注冊,和SMS是否支持。自此就開始調用mCi了,也就是CommandsInterface類了,這個類在/frameworks/opt/telephony/src/java/com/android/internal/telephony路徑下,這個就進入額RIL層了,也就不是我研究的范圍了。其實在我修改過中是沒有修改到這一層,基本修改操作基本都是在調用sendRawPdu()方法之前完成。是不是已經腦殼都看糊了?好了,下面我們來看一張圖,總結一下,短信發送的流程!?

自此,希望大家能對短信的發送有個大體的認識,如果需要詳細的了解短信發送的每個細節,可以下載源代碼觀看。結合源代碼,觀看本文效果更佳!



原文地址: http://blog.csdn.net/poison_h/article/details/50972149

總結

以上是生活随笔為你收集整理的Android开发之Android5.1.1(CM12.1)源码中短信发送流程解析的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 黄色片小视频 | 综合图区亚洲 | 疯狂做受xxxx国产 | 色视频在线看 | 男人av影院 | 国产免费成人av | 欧美成人日韩 | 国产精品成人久久久久 | 精品999久久久一级毛片 | 欧美成人h版在线观看 | 拍摄av现场失控高潮数次 | 日本动漫艳母 | 天天射天天草 | √天堂中文官网8在线 | 免费毛片小视频 | 理论片午午伦夜理片影院99 | 91啦丨九色丨刺激 | 99色在线观看 | 日韩大片在线 | 久久机热这里只有精品 | 国产欧美高清 | www午夜| 午夜精品一区 | 少妇一级淫片免费视频 | 欧美成人国产精品高潮 | 天天看片天天射 | 亚洲色婷婷一区二区三区 | 国产精品久久在线 | 妞干网av| 久草视频在 | 黄色国产视频 | 成人免费xxxxxx视频 | 99视频在线免费观看 | 激情总合网 | 日韩精品一区二区三区视频 | 国产精品手机在线 | 欧美黑人孕妇孕交 | 久久久av电影 | 亚洲国产精品视频一区二区 | 亚洲一区二区三区麻豆 | 中日韩精品视频 | 综合久久网 | 特级新鲜大片片 | 亚洲午夜视频在线 | 红色假期黑色婚礼2 | 亚洲免费视频播放 | 欧美亚洲视频 | 娇喘顶撞深初h1v1 | 黄页网站在线看 | 国产综合婷婷 | 爱福利视频广场 | 午夜视频福利在线观看 | 日本激情免费 | 日韩成人在线免费视频 | 色爽黄 | 亚洲一区二区美女 | 亚洲成人av免费在线观看 | 四虎影视av | 成人免费在线看片 | 日本一二三区视频 | 青青毛片 | 中国极品少妇xxxx做受 | 国产一区二区三区影院 | 亚洲精品免费看 | 天堂网2020 | 中国一级特黄毛片 | jizz18欧美18| 国产一级片免费播放 | 理论片久久 | 麻豆高清免费国产一区 | a视频在线观看免费 | 欧美大片一区二区三区 | 国产精品99无码一区二区 | 国产精品久久午夜夜伦鲁鲁 | 欧美日韩中文字幕在线 | 亚洲精品久久久久久久久 | 毛片少妇| 中文在线资源 | 精品国产一区二区不卡 | 欧美在线观看a | 成人免费看高清电影在线观看 | www九九九| 亚洲人人爱| 天天干天天上 | 人人爱人人 | 青娱乐国产精品 | 国产一区日本 | 一本色道久久亚洲综合精品蜜桃 | 在线观看免费黄色小视频 | 中出一区 | 特黄级| 欧美亚洲视频一区 | 成人综合激情网 | 亚洲23p | 强迫凌虐淫辱の牝奴在线观看 | 欧美不卡影院 | 日本一区二区不卡视频 | 国产精品久久久久久福利 | 国产视频在线免费观看 |