Android 短信发送流程

短信发送Framework流程,源代码的版本是4.4

1、通过Mms源代码可以知道短信发送最后调用的关键api如下:

SmsSingleRecipientSender.java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SmsManager smsManager = SmsManager.getDefault();  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ...  
  2. try {  
  3.             smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);  
  4.         } catch (Exception ex) {  
  5.             Log.e(TAG, "SmsMessageSender.sendMessage: caught", ex);  
  6.             throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +  
  7.                     " from SmsManager.sendTextMessage()");  
  8.         }  
  9. ...  
smsManager对应的文件是SmsManager.java

2、SmsManager源代码路径是frameworks/opt/telephony/src/java/android/telephony/gsm/SmsManager.java

SmsManager这里用了单例模式初始化

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** Singleton object constructed during class initialization. */  
  2.     private static final SmsManager sInstance = new SmsManager();  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.      * Get the default instance of the SmsManager 
  3.      * 
  4.      * @return the default instance of the SmsManager 
  5.      */  
  6.     public static SmsManager getDefault() {  
  7.         return sInstance;  
  8.     }  
sendMultipartTextMessage的实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void sendMultipartTextMessage(  
  2.             String destinationAddress, String scAddress, ArrayList<String> parts,  
  3.             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {  
  4.         if (TextUtils.isEmpty(destinationAddress)) {  
  5.             throw new IllegalArgumentException("Invalid destinationAddress");  
  6.         }  
  7.         if (parts == null || parts.size() < 1) {  
  8.             throw new IllegalArgumentException("Invalid message body");  
  9.         }  
  10.   
  11.   
  12.         if (parts.size() > 1) {  
  13.             try {  
  14.                 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));  
  15.                 if (iccISms != null) {  
  16.                     iccISms.sendMultipartText(ActivityThread.currentPackageName(),  
  17.                             destinationAddress, scAddress, parts,  
  18.                             sentIntents, deliveryIntents);  
  19.                 }  
  20.             } catch (RemoteException ex) {  
  21.                 // ignore it  
  22.             }  
  23.         } else {  
  24.             PendingIntent sentIntent = null;  
  25.             PendingIntent deliveryIntent = null;  
  26.             if (sentIntents != null && sentIntents.size() > 0) {  
  27.                 sentIntent = sentIntents.get(0);  
  28.             }  
  29.             if (deliveryIntents != null && deliveryIntents.size() > 0) {  
  30.                 deliveryIntent = deliveryIntents.get(0);  
  31.             }  
  32.             sendTextMessage(destinationAddress, scAddress, parts.get(0),  
  33.                     sentIntent, deliveryIntent);  
  34.         }  
  35.     }  

如果短信的内容被划分成了多个部分,将进入icc.sendMultipartText(),即如下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. try {  
  2.                ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));  
  3.                if (iccISms != null) {  
  4.                    iccISms.sendMultipartText(ActivityThread.currentPackageName(),  
  5.                            destinationAddress, scAddress, parts,  
  6.                            sentIntents, deliveryIntents);  
  7.                }  
  8.            } catch (RemoteException ex) {  
  9.                // ignore it  
  10.            }  
如果短信的内容只有一部分,则继续调用sendTextMessage(),即如下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="white-space:pre">  </span>    PendingIntent sentIntent = null;  
  2.             PendingIntent deliveryIntent = null;  
  3.             if (sentIntents != null && sentIntents.size() > 0) {  
  4.                 sentIntent = sentIntents.get(0);  
  5.             }  
  6.             if (deliveryIntents != null && deliveryIntents.size() > 0) {  
  7.                 deliveryIntent = deliveryIntents.get(0);  
  8.             }  
  9.             sendTextMessage(destinationAddress, scAddress, parts.get(0),  
  10.                     sentIntent, deliveryIntent);  
下面的流程主要针对sendTextMessage( )分析,sendMultipartText到此为止。

短信在发送之前会检查发送字符串是否超过最大长度,如果超过会被划分成几部分,对应这里的ArrayList<string> parts,

划分的具体实现对应smsManager.divideMessage(mMsgText)

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Divide a message text into several fragments, none bigger than 
  3.  * the maximum SMS message size. 
  4.  * 
  5.  * @param text the original message.  Must not be null. 
  6.  * @return an <code>ArrayList</code> of strings that, in order, 
  7.  *   comprise the original message 
  8.  * 
  9.  * @throws IllegalArgumentException if text is null 
  10.  */  
  11. public ArrayList<String> divideMessage(String text) {  
  12.     if (null == text) {  
  13.         throw new IllegalArgumentException("text is null");  
  14.     }  
  15.     return SmsMessage.fragmentText(text);  
  16. }  

很明显这里调用SmsMessage.fragmentText()

SmsMessage的路径是frameworks/opt/telephony/src/java/android/telephony/SmsMessage.java

fragmentText的具体实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Divide a message text into several fragments, none bigger than 
  3.  * the maximum SMS message text size. 
  4.  * 
  5.  * @param text text, must not be null. 
  6.  * @return an <code>ArrayList</code> of strings that, in order, 
  7.  *   comprise the original msg text 
  8.  * 
  9.  * @hide 
  10.  */  
  11. public static ArrayList<String> fragmentText(String text) {  
  12.     // This function is for MO SMS  
  13.     TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?  
  14.         com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) :  
  15.         com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);  
  16.   
  17.     // TODO(cleanup): The code here could be rolled into the logic  
  18.     // below cleanly if these MAX_* constants were defined more  
  19.     // flexibly...  
  20.   
  21.     int limit;  
  22.     if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {  
  23.         int udhLength;  
  24.         if (ted.languageTable != 0 && ted.languageShiftTable != 0) {  
  25.             udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;  
  26.         } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {  
  27.             udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;  
  28.         } else {  
  29.             udhLength = 0;  
  30.         }  
  31.   
  32.         if (ted.msgCount > 1) {  
  33.             udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;  
  34.         }  
  35.   
  36.         if (udhLength != 0) {  
  37.             udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;  
  38.         }  
  39.   
  40.         limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;  
  41.     } else {  
  42.         if (ted.msgCount > 1) {  
  43.             limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;  
  44.         } else {  
  45.             limit = SmsConstants.MAX_USER_DATA_BYTES;  
  46.         }  
  47.     }  
  48.   
  49.     int pos = 0;  // Index in code units.  
  50.     int textLen = text.length();  
  51.     ArrayList<String> result = new ArrayList<String>(ted.msgCount);  
  52.     while (pos < textLen) {  
  53.         int nextPos = 0;  // Counts code units.  
  54.         if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {  
  55.             if (useCdmaFormatForMoSms() && ted.msgCount == 1) {  
  56.                 // For a singleton CDMA message, the encoding must be ASCII...  
  57.                 nextPos = pos + Math.min(limit, textLen - pos);  
  58.             } else {  
  59.                 // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).  
  60.                 nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit,  
  61.                         ted.languageTable, ted.languageShiftTable);  
  62.             }  
  63.         } else {  // Assume unicode.  
  64.             nextPos = pos + Math.min(limit / 2, textLen - pos);  
  65.         }  
  66.         if ((nextPos <= pos) || (nextPos > textLen)) {  
  67.             Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +  
  68.                       nextPos + " >= " + textLen + ")");  
  69.             break;  
  70.         }  
  71.         result.add(text.substring(pos, nextPos));  
  72.         pos = nextPos;  
  73.     }  
  74.     return result;  
  75. }  
3、sendText()的实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void sendTextMessage(  
  2.             String destinationAddress, String scAddress, String text,  
  3.             PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  4.         if (TextUtils.isEmpty(destinationAddress)) {  
  5.             throw new IllegalArgumentException("Invalid destinationAddress");  
  6.         }  
  7.   
  8.         if (TextUtils.isEmpty(text)) {  
  9.             throw new IllegalArgumentException("Invalid message body");  
  10.         }  
  11.   
  12.         try {  
  13.             ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));  
  14.             if (iccISms != null) {  
  15.                 iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress,  
  16.                         scAddress, text, sentIntent, deliveryIntent);  
  17.             }  
  18.         } catch (RemoteException ex) {  
  19.             // ignore it  
  20.         }  
  21.     }  
这里使用aidl的方式远程调用isms服务进行后续的发送流程,即

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. iccISms.sendText()  


,IccSmsInterfaceManagerProxy的路径是frameworks/opt/telephony/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java

关于isms服务的注册,它是在初始化phone进程时注册的

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public IccSmsInterfaceManagerProxy(Context context,  
  2.             IccSmsInterfaceManager iccSmsInterfaceManager) {  
  3.         this.mContext = context;  
  4.         mIccSmsInterfaceManager = iccSmsInterfaceManager;  
  5.         if(ServiceManager.getService("isms") == null) {  
  6.             ServiceManager.addService("isms"this);  
  7.         }  
  8.   
  9.         createWakelock();  
  10.     }  

iccISms.sendSms()的实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public void sendText(String callingPackage, String destAddr, String scAddr,  
  3.             String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  4.         mContext.enforceCallingPermission(  
  5.                 android.Manifest.permission.SEND_SMS,  
  6.                 "Sending SMS message");  
  7.         if (mIccSmsInterfaceManager.isShortSMSCode(destAddr)) {  
  8.             mIccSmsInterfaceManager.sendText(callingPackage, destAddr, scAddr, text,  
  9.                     sentIntent, deliveryIntent);  
  10.             return;  
  11.         }  
  12.         ArrayList<String> parts = new ArrayList<String>();  
  13.         parts.add(text);  
  14.         ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();  
  15.         sentIntents.add(sentIntent);  
  16.         ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();  
  17.         deliveryIntents.add(deliveryIntent);  
  18.         broadcastOutgoingSms(callingPackage, destAddr, scAddr, false, parts, sentIntents,  
  19.                 deliveryIntents, -1);  
  20.     }  
检查发送短信的APP是否有SEND_SMS权限,再调用broadcastOutgoingSms()

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private void broadcastOutgoingSms(String callingPackage, String destAddr, String scAddr,  
  2.             boolean multipart, ArrayList<String> parts,  
  3.             ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,  
  4.             int priority) {  
  5.         Intent broadcast = new Intent(Intent.ACTION_NEW_OUTGOING_SMS);  
  6.         broadcast.putExtra("destAddr", destAddr);  
  7.         broadcast.putExtra("scAddr", scAddr);  
  8.         broadcast.putExtra("multipart", multipart);  
  9.         broadcast.putExtra("callingPackage", callingPackage);  
  10.         broadcast.putExtra("callingUid", android.os.Binder.getCallingUid());  
  11.         broadcast.putStringArrayListExtra("parts", parts);  
  12.         broadcast.putParcelableArrayListExtra("sentIntents", sentIntents);  
  13.         broadcast.putParcelableArrayListExtra("deliveryIntents", deliveryIntents);  
  14.         broadcast.putExtra("priority", priority);  
  15.         mContext.sendOrderedBroadcastAsUser(broadcast, UserHandle.OWNER,  
  16.                 android.Manifest.permission.INTERCEPT_SMS,  
  17.                 mReceiver, null, Activity.RESULT_OK, destAddr, null);  
  18.     }  
发送广播,Action为ACTION_NEW_OUTGOING_SMS,广播接收器就是参数中的mReceiver,mReceiver的定义如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private BroadcastReceiver mReceiver = new BroadcastReceiver() {  
  2.         public void onReceive(Context context, Intent intent) {  
  3.             // check if the message was aborted  
  4.             if (getResultCode() != Activity.RESULT_OK) {  
  5.                 return;  
  6.             }  
  7.             String destAddr = getResultData();  
  8.             String scAddr = intent.getStringExtra("scAddr");  
  9.             String callingPackage = intent.getStringExtra("callingPackage");  
  10.             ArrayList<String> parts = intent.getStringArrayListExtra("parts");  
  11.             ArrayList<PendingIntent> sentIntents =  
  12.                     intent.getParcelableArrayListExtra("sentIntents");  
  13.             ArrayList<PendingIntent> deliveryIntents =  
  14.                     intent.getParcelableArrayListExtra("deliveryIntents");  
  15.   
  16.             if (intent.getIntExtra("callingUid"0) != 0) {  
  17.                 callingPackage = callingPackage + "\\" + intent.getIntExtra("callingUid", 0);  
  18.             }  
  19.   
  20.             if (intent.getBooleanExtra("multipart"false)) {  
  21.                 mIccSmsInterfaceManager.sendMultipartText(callingPackage, destAddr, scAddr,  
  22.                         parts, sentIntents, deliveryIntents);  
  23.                 return;  
  24.             }  
  25.   
  26.             PendingIntent sentIntent = null;  
  27.             if (sentIntents != null && sentIntents.size() > 0) {  
  28.                 sentIntent = sentIntents.get(0);  
  29.             }  
  30.             PendingIntent deliveryIntent = null;  
  31.             if (deliveryIntents != null && deliveryIntents.size() > 0) {  
  32.                 deliveryIntent = deliveryIntents.get(0);  
  33.             }  
  34.             String text = null;  
  35.             if (parts != null && parts.size() > 0) {  
  36.                 text = parts.get(0);  
  37.             }  
  38.             mIccSmsInterfaceManager.sendText(callingPackage, destAddr, scAddr, text,  
  39.                     sentIntent, deliveryIntent);  
  40.         }  
  41.     };  
这里调用mIccSmsInterfaceManager.sendText()继续发送流程

mIccSmsInterfaceManager对应的类是IccSmsInterfaceManager,路径是

framework/opt/telephony/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
mIccSmsInterfaceManager.sendText()的实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void sendText(String callingPackage, String destAddr, String scAddr,  
  2.             String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  3.         int callingUid = Binder.getCallingUid();  
  4.   
  5.         String[] callingParts = callingPackage.split("\\\\");  
  6.         if (callingUid == android.os.Process.PHONE_UID &&  
  7.                                          callingParts.length > 1) {  
  8.             callingUid = Integer.parseInt(callingParts[1]);  
  9.         }  
  10.   
  11.         if (Binder.getCallingPid() != android.os.Process.myPid()) {  
  12.             mPhone.getContext().enforceCallingPermission(  
  13.                     Manifest.permission.SEND_SMS,  
  14.                     "Sending SMS message");  
  15.         }  
  16.         if (Rlog.isLoggable("SMS", Log.VERBOSE)) {  
  17.             log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +  
  18.                 " text='"+ text + "' sentIntent=" +  
  19.                 sentIntent + " deliveryIntent=" + deliveryIntent);  
  20.         }  
  21.         if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, callingUid,  
  22.                 callingParts[0]) != AppOpsManager.MODE_ALLOWED) {  
  23.             return;  
  24.         }  
  25.         mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);  
  26.     }  
这里调用mDispatcher.sendText()继续发送流程

mDispatcher对应的类是SmsDispatcher,源代码的路径是

framework/opt/telephony/src/java/com/android/internal/telephony/SMSDispatcher.java

SMSDispatcher是一个abstract类,继承它的子类有CdmaSMSDispatcher、GsmSMSDispatcher和IccSMSDispatcher,

这里的mDispatcher初始化如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected IccSmsInterfaceManager(PhoneBase phone) {  
  2.         mPhone = phone;  
  3.         mContext = phone.getContext();  
  4.         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);  
  5.         mDispatcher = new ImsSMSDispatcher(phone,  
  6.                 phone.mSmsStorageMonitor, phone.mSmsUsageMonitor);  
  7.     }  
mDispatcher.sendText()是一个abstract方法,所以是在IccSMSDispatcher中实现,代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     protected void sendText(String destAddr, String scAddr, String text,  
  3.             PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  4.         Rlog.d(TAG, "sendText");  
  5.         if (isCdmaMo()) {  
  6.             mCdmaDispatcher.sendText(destAddr, scAddr,  
  7.                     text, sentIntent, deliveryIntent);  
  8.         } else {  
  9.             mGsmDispatcher.sendText(destAddr, scAddr,  
  10.                     text, sentIntent, deliveryIntent);  
  11.         }  
  12.     }  
这里根据sim卡的类型决定调用CdmaSMSDispatcher还是GsmSMSDispatcher,这里选择Gsm继续跟进。

mGsmDispatcher对应的类是GsmSMSDispatcher,源代码路径是

framework/opt/telephony/src/java/com/android/internal/telephony/GsmSMSDispatcher.java

mGsmDispatcher.sendText()的流程如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     protected void sendText(String destAddr, String scAddr, String text,  
  3.             PendingIntent sentIntent, PendingIntent deliveryIntent) {  
  4.         SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(  
  5.                 scAddr, destAddr, text, (deliveryIntent != null));  
  6.         if (pdu != null) {  
  7.             HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);  
  8.             SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,  
  9.                     getFormat());  
  10.             sendRawPdu(tracker);  
  11.         } else {  
  12.             Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");  
  13.         }  
  14.     }  
这里构造了SubmitPdu和SmsTracker对象,然后执行sendRawPdu(),这个方法是在父类SMSDiapatcher中实现的,代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected void sendRawPdu(SmsTracker tracker) {  
  2. n style="white-space:pre">  </span>...  
  3.   
  4.     // checkDestination() returns true if the destination is not a premium short code or the  
  5.     // sending app is approved to send to short codes. Otherwise, a message is sent to our  
  6.     // handler with the SmsTracker to request user confirmation before sending.  
  7.     if (checkDestination(tracker)) {  
  8.         // check for excessive outgoing SMS usage by this app  
  9.         if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {  
  10.             sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));  
  11.             return;  
  12.         }  
  13.   
  14.         int ss = mPhone.getServiceState().getState();  
  15.   
  16.         // if sms over IMS is not supported on data and voice is not available...  
  17.         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {  
  18.             handleNotInService(ss, tracker.mSentIntent);  
  19.         } else {  
  20.             sendSms(tracker);  
  21.         }  
  22.     }  
  23. }  
这里调用sendSms()继续发送流程,sendSms()是一个abstract方法,所以这里是在子类GsmSMSDispatcher中实现的,代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. protected void sendSms(SmsTracker tracker) {  
  3.     HashMap<String, Object> map = tracker.mData;  
  4.   
  5.     byte smsc[] = (byte[]) map.get("smsc");  
  6.     byte pdu[] = (byte[]) map.get("pdu");  
  7.   
  8.     Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);  
  9.   
  10.     if (tracker.mRetryCount > 0) {  
  11.         Rlog.d(TAG, "sendSms: "  
  12.                 + " mRetryCount=" + tracker.mRetryCount  
  13.                 + " mMessageRef=" + tracker.mMessageRef  
  14.                 + " SS=" + mPhone.getServiceState().getState());  
  15.   
  16.         // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type  
  17.         //   TP-RD (bit 2) is 1 for retry  
  18.         //   and TP-MR is set to previously failed sms TP-MR  
  19.         if (((0x01 & pdu[0]) == 0x01)) {  
  20.             pdu[0] |= 0x04// TP-RD  
  21.             pdu[1] = (byte) tracker.mMessageRef; // TP-MR  
  22.         }  
  23.     }  
  24.     Rlog.d(TAG, "sendSms: "  
  25.             +" isIms()="+isIms()  
  26.             +" mRetryCount="+tracker.mRetryCount  
  27.             +" mImsRetry="+tracker.mImsRetry  
  28.             +" mMessageRef="+tracker.mMessageRef  
  29.             +" SS=" +mPhone.getServiceState().getState());  
  30.   
  31.     // sms over gsm is used:  
  32.     //   if sms over IMS is not supported AND  
  33.     //   this is not a retry case after sms over IMS failed  
  34.     //     indicated by mImsRetry > 0  
  35.     if (0 == tracker.mImsRetry && !isIms()) {  
  36.         if (tracker.mRetryCount > 0) {  
  37.             // per TS 23.040 Section 9.2.3.6:  If TP-MTI SMS-SUBMIT (0x01) type  
  38.             //   TP-RD (bit 2) is 1 for retry  
  39.             //   and TP-MR is set to previously failed sms TP-MR  
  40.             if (((0x01 & pdu[0]) == 0x01)) {  
  41.                 pdu[0] |= 0x04// TP-RD  
  42.                 pdu[1] = (byte) tracker.mMessageRef; // TP-MR  
  43.             }  
  44.         }  
  45.         mCi.sendSMS(IccUtils.bytesToHexString(smsc),  
  46.                 IccUtils.bytesToHexString(pdu), reply);  
  47.     } else {  
  48.         mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc),  
  49.                 IccUtils.bytesToHexString(pdu), tracker.mImsRetry,  
  50.                 tracker.mMessageRef, reply);  
  51.         // increment it here, so in case of SMS_FAIL_RETRY over IMS  
  52.         // next retry will be sent using IMS request again.  
  53.         tracker.mImsRetry++;  
  54.     }  
  55. }  
这里最终调用mCi.sendSms()继续发送流程,

mCi对应的类是CommandInterface,CommandInterface是一个Interface,RIL是它的一个子类,

也就是说短信发送在此处会调用RIL.java,执行sendText()方法,代码如下:

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void  
  2.     sendSMS (String smscPDU, String pdu, Message result) {  
  3.         RILRequest rr  
  4.                 = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);  
  5.   
  6.         constructGsmSendSmsRilRequest(rr, smscPDU, pdu);  
  7.   
  8.         if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));  
  9.   
  10.         send(rr);  
  11.     }  
程序交给send(RILRequest req)继续执行,代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected void  
  2.     send(RILRequest rr) {  
  3.         Message msg;  
  4.   
  5.         if (mSocket == null) {  
  6.             rr.onError(RADIO_NOT_AVAILABLE, null);  
  7.             rr.release();  
  8.             return;  
  9.         }  
  10.   
  11.         msg = mSender.obtainMessage(EVENT_SEND, rr);  
  12.   
  13.         acquireWakeLock();  
  14.   
  15.         msg.sendToTarget();  
  16.     }  
接下来RIL会将pdu等信息打包,通过socket发送给下层处理,最终形成at指令发送短信。

如果短信发送成功,还记得在发送时,从GsmSmsDispatcher.java传递到RIL.java中的Message吗,在发送之后,RIL.java会回调此Message,这个Message如下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);  
What = EVENT_SEND_SMS_COMPLETE,Object = tricker。SmsDispacher.java本身是一个Handler,所以这个Message最终在SmsDispacher.java中处理,处理逻辑代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public void handleMessage(Message msg) {  
  3.         switch (msg.what) {  
  4.         case EVENT_SEND_SMS_COMPLETE:  
  5.             // An outbound SMS has been successfully transferred, or failed.  
  6.             handleSendComplete((AsyncResult) msg.obj);  
  7.             break;  
handleSendComplete的实现如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. protected void handleSendComplete(AsyncResult ar) {  
  2.         SmsTracker tracker = (SmsTracker) ar.userObj;  
  3.         PendingIntent sentIntent = tracker.mSentIntent;  
  4.   
  5.         if (ar.result != null) {  
  6.             tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;  
  7.         } else {  
  8.             Rlog.d(TAG, "SmsResponse was null");  
  9.         }  
  10.   
  11.         if (ar.exception == null) {  
  12.             if (DBG) Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent);  
  13.   
  14.             if (SmsApplication.shouldWriteMessageForPackage(  
  15.                     tracker.mAppInfo.applicationInfo.packageName, mContext)) {  
  16.                 // Persist it into the SMS database as a sent message  
  17.                 // so the user can see it in their default app.  
  18.                 tracker.writeSentMessage(mContext);  
  19.             }  
  20.   
  21.             if (tracker.mDeliveryIntent != null) {  
  22.                 // Expecting a status report.  Add it to the list.  
  23.                 deliveryPendingList.add(tracker);  
  24.             }  
  25.   
  26.             if (sentIntent != null) {  
  27.                 try {  
  28.                     if (mRemainingMessages > -1) {  
  29.                         mRemainingMessages--;  
  30.                     }  
  31.   
  32.                     if (mRemainingMessages == 0) {  
  33.                         Intent sendNext = new Intent();  
  34.                         sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true);  
  35.                         sentIntent.send(mContext, Activity.RESULT_OK, sendNext);  
  36.                     } else {  
  37.                         sentIntent.send(Activity.RESULT_OK);  
  38.                     }  
  39.                 } catch (CanceledException ex) {}  
  40.             }  
  41.         } else {  
  42.             if (DBG) Rlog.d(TAG, "SMS send failed");  
  43.   
  44.             int ss = mPhone.getServiceState().getState();  
  45.   
  46.             if ( tracker.mImsRetry > 0 && ss != ServiceState.STATE_IN_SERVICE) {  
  47.                 // This is retry after failure over IMS but voice is not available.  
  48.                 // Set retry to max allowed, so no retry is sent and  
  49.                 //   cause RESULT_ERROR_GENERIC_FAILURE to be returned to app.  
  50.                 tracker.mRetryCount = MAX_SEND_RETRIES;  
  51.   
  52.                 Rlog.d(TAG, "handleSendComplete: Skipping retry: "  
  53.                 +" isIms()="+isIms()  
  54.                 +" mRetryCount="+tracker.mRetryCount  
  55.                 +" mImsRetry="+tracker.mImsRetry  
  56.                 +" mMessageRef="+tracker.mMessageRef  
  57.                 +" SS= "+mPhone.getServiceState().getState());  
  58.             }  
  59.   
  60.             // if sms over IMS is not supported on data and voice is not available...  
  61.             if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {  
  62.                 handleNotInService(ss, tracker.mSentIntent);  
  63.             } else if ((((CommandException)(ar.exception)).getCommandError()  
  64.                     == CommandException.Error.SMS_FAIL_RETRY) &&  
  65.                    tracker.mRetryCount < MAX_SEND_RETRIES) {  
  66.                 // Retry after a delay if needed.  
  67.                 // TODO: According to TS 23.040, 9.2.3.6, we should resend  
  68.                 //       with the same TP-MR as the failed message, and  
  69.                 //       TP-RD set to 1.  However, we don't have a means of  
  70.                 //       knowing the MR for the failed message (EF_SMSstatus  
  71.                 //       may or may not have the MR corresponding to this  
  72.                 //       message, depending on the failure).  Also, in some  
  73.                 //       implementations this retry is handled by the baseband.  
  74.                 tracker.mRetryCount++;  
  75.                 Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);  
  76.                 sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);  
  77.             } else if (tracker.mSentIntent != null) {  
  78.                 int error = RESULT_ERROR_GENERIC_FAILURE;  
  79.   
  80.                 if (((CommandException)(ar.exception)).getCommandError()  
  81.                         == CommandException.Error.FDN_CHECK_FAILURE) {  
  82.                     error = RESULT_ERROR_FDN_CHECK_FAILURE;  
  83.                 }  
  84.                 // Done retrying; return an error to the app.  
  85.                 try {  
  86.                     Intent fillIn = new Intent();  
  87.                     if (ar.result != null) {  
  88.                         fillIn.putExtra("errorCode", ((SmsResponse)ar.result).mErrorCode);  
  89.                     }  
  90.                     if (mRemainingMessages > -1) {  
  91.                         mRemainingMessages--;  
  92.                     }  
  93.   
  94.                     if (mRemainingMessages == 0) {  
  95.                         fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);  
  96.                     }  
  97.   
  98.                     tracker.mSentIntent.send(mContext, error, fillIn);  
  99.                 } catch (CanceledException ex) {}  
  100.             }  
  101.         }  
  102.     }  
至此就是短信发送的在framework中的大体流程

首先检查AsyncResult对象中是否存在异常,如果成功发送的信息,那么不存在异常,如果发送失败,那么是存在Exception的,会进行异常的相应的逻辑处理,大体流程相似,故本处介绍无异常时的流程逻辑。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (SmsApplication.shouldWriteMessageForPackage(  
  2.                     tracker.mAppInfo.applicationInfo.packageName, mContext)) {  
  3.                 // Persist it into the SMS database as a sent message  
  4.                 // so the user can see it in their default app.  
  5.                 tracker.writeSentMessage(mContext);  
  6.             }  
这里判断发送短信的app是否是默认短信,如果不是则保存该条短信到TelephonyProvider中。

最后会发送一个广播,这个广播的intent是PendingIntent,是在Mms中构造的,SmsReceiverService.java会接受该广播并处理,比如保存短信的状态,失败或者发送成功。

发送流程大概就是这样了。


转自:http://blog.csdn.net/aiai373824745/article/details/20614371
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值