1. 新建一条短信, 在发送短信之前, 首先创建的是一个会话Conversation, 以后所有与该接收人(一个或多个接收人)的消息交互, 都在该会话Conversation中. ComposeMessageActivity: private void initActivityState(Bundle bundle) { ... mConversation = Conversation.get(this, ContactList.getByNumbers(recipients, false /* don't block */, true /* replace number */), false); ... } 1.1. 在创建会话的过程中会初始化一些参数, 如ThreadId Conversation: public static Conversation get(Context context, ContactList recipients, boolean allowQuery) { ... // 重点: 创建获取ThreadId long threadId = getOrCreateThreadId(context, recipients); // 创建会话 conv = new Conversation(context, threadId, allowQuery); ... } 1.2. ThreadId贯穿着整个信息的发送流程, 因此我们需要查看ThreadId的创建流程 public static long getOrCreateThreadId(Context context, ContactList list) { ... long retVal = 0; try { retVal = Threads.getOrCreateThreadId(context, recipients, names); } catch (IllegalArgumentException e) { Log.e(TAG, " Failed to get or create threadId, exception : " + e); } ... } 1.3. 继续创建ThreadId Telephony$Threads: public static long getOrCreateThreadId(Context context, Setrecipients, Set recipientNames) { // 重点: THREAD_ID_CONTENT_URI = "content://mms-sms/threadID" Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon(); ... // 此处可以看见并没有对ThreadId的创建, 只有一个查询的过程 // 因此我们需要通过THREAD_ID_CONTENT_URI找到对应的ContentProvider, 看看查询的实现逻辑 Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), uri, ID_PROJECTION, null, null, null); if (cursor != null) { try { if (cursor.moveToFirst()) { return cursor.getLong(0); } else { Rlog.e(TAG, "getOrCreateThreadId returned no rows!"); } } finally { cursor.close(); } } } 1.4. 由于上面的步骤只看见ThreadId的查询过程, 并没有看见ThreadId的创建, 因此我们需要到短信的内容提供者MmsSmsProvider中看看ThreadId的具体查询过程 MmsSmsProvider: public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { ... switch(URI_MATCHER.match(uri)) { ... case URI_THREAD_ID: // 此处即为ThreadId的查询 List recipients = uri.getQueryParameters("recipient"); List recipientNames = uri.getQueryParameters("recipientNames"); // 获取ThreadId cursor = getThreadId(recipients,recipientNames); break; ... } } 1.5. 查看查询过程中ThreadId的具体查询过程 MmsSmsProvider: private synchronized Cursor getThreadId(List recipients,List recipientNames) { ... // 重点: 根据接收人获取地址id // 每个接收人的地址id, 在短信模块中有且只有一个addressId // 该addressId通过接收人的号码生成, 无论联系人的姓名怎样变化, 该id都不会发生改变 Set addressIds = getAddressIds(recipients); ... } 1.5.1. 查看联系人的addressId的查询和创建过程 MmsSmsProvider: private Set getAddressIds(List addresses) { ... for (String address : addresses) { if (!address.equals(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) { // 获取联系人的唯一addressId long id = getSingleAddressId(address); if (id != -1L) { result.add(id); } else { Log.e(LOG_TAG, "getAddressIds: address ID not found for " + address); } } } ... } 1.5.2. 继续查看联系人addressId的查询和创建过程 MmsSmsProvider: private long getSingleAddressId(String address) { ... // 前面是一些联系人的类型判断和查询参数的拼接 // 注意: sql中的PHONE_NUMBERS_EQUAL函数是android独有的 // 查询接收人的addressId cursor = db.query("canonical_addresses", ID_PROJECTION, selection, selectionArgs, null, null, null); if (cursor.getCount() == 0) { // 如果之前没有改接收人的addressId ContentValues contentValues = new ContentValues(1); contentValues.put(CanonicalAddressesColumns.ADDRESS, refinedAddress); db = mOpenHelper.getWritableDatabase(); // 创建接收人的addressId retVal = db.insert("canonical_addresses", CanonicalAddressesColumns.ADDRESS, contentValues); Log.d(LOG_TAG, "getSingleAddressId: insert new canonical_address for " + /*address*/ "xxxxxx" + ", _id=" + retVal); return retVal; } if (cursor.moveToFirst()) { // 如果已经有接收人的addressId, 直接获取返回 retVal = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID)); } ... } 1.6. 在获取完所有接收的addressId, 接下来继续看获取ThreadId的流程 MmsSmsProvider: private synchronized Cursor getThreadId(List recipients,List recipientNames) { ... // 获取接收人的addressId Set addressIds = getAddressIds(recipients); ... // 如果有多个接收人, 需要对接收人的addressIds进行处理, 保证唯一 // 防止因为顺序等原因导致重复 recipientIds = getSpaceSeparatedNumbers(getSortedSet(addressIds)); ... // 通过接收人的addressIds进行查询 Cursor cursor = db.rawQuery(THREAD_QUERY, selectionArgs); if (cursor.getCount() == 0) { // 如果没有查询到ThreadId, 则进行创建 // 插入ThreadId insertThread(recipientIds, recipients.size() ,addresses ,names); db = mOpenHelper.getReadableDatabase(); // 查询ThreadId cursor = db.rawQuery(THREAD_QUERY, selectionArgs); } if (cursor.getCount() > 1) { // 如果查询到ThreadId, 直接返回 Log.w(LOG_TAG, "getThreadId: why is cursorCount=" + cursor.getCount()); } return cursor; ... } 1.6.1. 查看插入ThreadId的步骤 MmsSmsProvider: private void insertThread(String recipientIds, int numberOfRecipients, String addresses ,String names) { ContentValues values = new ContentValues(4); long date = System.currentTimeMillis(); values.put(ThreadsColumns.DATE, date - date % 1000); // 时间 values.put(ThreadsColumns.RECIPIENT_IDS, recipientIds); // 接收人addressIds if (numberOfRecipients > 1) { values.put(Threads.TYPE, Threads.BROADCAST_THREAD); // 类型 } values.put(ThreadsColumns.MESSAGE_COUNT, 0);// 消息数量 values.put(ThreadsColumns.RECIPIENT_ADDRESSES, addresses);// 接收人的号码 values.put(ThreadsColumns.RECIPIENT_NAMES, names);// 接收人的姓名 // TABLE_THREADS = threads // 从此处可以看出, threads数据保存的是会话信息, threadId是每条会话信息的Id long result = mOpenHelper.getWritableDatabase().insert(TABLE_THREADS, null, values); Log.d(LOG_TAG, "insertThread: created new thread_id " + result + " for recipientIds " + /*recipientIds*/ "xxxxxxx"); getContext().getContentResolver().notifyChange(MmsSms.CONTENT_URI, null); } 2. 开始进入发送短信的流程 WorkingMessage: public void send(final String recipientsInUI, final int phoneId) { ... //TODO 如果是新建短信, 则threadId为0 long origThreadId = mConversation.getThreadId(); ... // 短信的发送 // Same rules apply as above. final String msgText = mText.toString(); // 启动线程完成发送短信的操作, 目的是不影响界面的返回 new Thread(new Runnable() { @Override public void run() { // 准备短信发送工作, 包含短信发送工作sendSmsWorker preSendSmsWorker(conv, mmsUri, msgText, recipientsInUI, phoneId); updateSendStats(conv); } }, "WorkingMessage.send SMS").start(); } 3. 准备短信的发送工作 WorkingMessage: private void preSendSmsWorker(Conversation conv, Uri mmsUri, String msgText, String recipientsInUI, int phoneId) { ... // 重点: long origThreadId = conv.getThreadId();// 新建短信的ThreadId为0 Log.d(TAG, "origThreadId: " + origThreadId); // Make sure we are still using the correct thread ID for our recipient set. long threadId = conv.ensureThreadId();// 创建ThreadId Log.d(TAG, "threadId: " + threadId); ... } 3.1 根据接收人确保ThreadId Conversation: public synchronized long ensureThreadId() { ... if (mThreadId <= 0) { mThreadId = getOrCreateThreadId(mContext, mRecipients); } ... } 3.2 获取或创建id, 如果接收人是之前没有过短信记录, 则创建ThreadId 注意: 如果接收人有多个, 而其中某个或者全部接收, 之前都有自己单独的信息记录, 此处依然会创建ThreadId public static long getOrCreateThreadId(Context context, ContactList list) { ... long retVal = 0; try { // recipients: 接收人的号码 // names: 接收人的姓名 retVal = Threads.getOrCreateThreadId(context, recipients, names); } catch (IllegalArgumentException e) { Log.e(TAG, " Failed to get or create threadId, exception : " + e); } ... } 3.3 通过接收人的号码和姓名获取或创建ThreadId Threads: public static long getOrCreateThreadId(Context context, Set recipients, Set recipientNames) { ... // 中间有一段设置查询参数 Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), uri, ID_PROJECTION, null, null, null); if (cursor != null) { try { if (cursor.moveToFirst()) { return cursor.getLong(0); } else { Rlog.e(TAG, "getOrCreateThreadId returned no rows!"); } } finally { cursor.close(); } } ... } 4. 获取到ThreadId, 即会话的id后, 继续消息发送的流程 WorkingMessage: private void preSendSmsWorker(Conversation conv, Uri mmsUri, String msgText, String recipientsInUI, int phoneId) { ... // 重点: long origThreadId = conv.getThreadId();// 新建短信的ThreadId为0 Log.d(TAG, "origThreadId: " + origThreadId); // Make sure we are still using the correct thread ID for our recipient set. long threadId = conv.ensureThreadId();// 创建ThreadId Log.d(TAG, "threadId: " + threadId); ... // 进行短信发送, 主要逻辑分为两步: // 1. 创建SmsMessageSender对象 // 2. 调用SmsMessageSender.sendMessage继续发起发送短信请求 sendSmsWorker(msgText, semiSepRecipients, threadId, phoneId); // Be paranoid and clean any draft SMS up. deleteDraftSmsMessage(threadId); } 5. 执行消息的发送 WorkingMessage: private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId, int phoneId) { ... // 1. 创建信息发送者 MessageSender sender; if (SignatureAppend.getInstance().isSignatureEnabled()) { Log.e(TAG, "sign:signatureText sender true"); sender = new SmsMessageSender(mActivity, dests, msgText, threadId,phoneId, signatureText); } else {sender = new SmsMessageSender(mActivity, dests, msgText, threadId,phoneId); Log.e(TAG, "sign:signatureText sender false"); } try { // 2. 进行信息的发送 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); } } 6. 将即将发送的消息, 添加到消息队列, 并发送广播 SmsMessageSender: public boolean sendMessage(long token) throws MmsException { return queueMessage(token); } private boolean queueMessage(long token) throws MmsException { ... // 获取编码模式: Auto, 7bit, 16bit requestDeliveryReport = prefs.getBoolean(SimSettingPreferenceActivity.SMS_DELIVERY_REPORT_MODE, DEFAULT_DELIVERY_REPORT_MODE); ... for (int i = 0; i < mNumberOfDests; i++) { // 将消息添加到消息队列 Sms.addMessageToUri(mContext.getContentResolver(), Uri.parse("content://sms/queued"), mDests[i], mMessageText, null, mSignatureText, mTimestamp, true /* read */, requestDeliveryReport, mThreadId, // SPRD: Add for multi-sim module. mPhoneId); } ... // 发送消息发送的广播 Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);// 发送到指定的广播接收者 intent.putExtra(Sms.PHONE_ID, mPhoneId); mContext.sendBroadcast(intent); ... } 7. 在SmsReceiver中接收处理SmsReceiverService.ACTION_SEND_MESSAGE的广播 SmsReceiver: protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) { ... intent.setClass(context, SmsReceiverService.class); intent.putExtra("result", getResultCode()); beginStartingService(context, intent); // 启动SmsReceiverService服务, 处理消息的发送 } 8. 在SmsReceiverService进行短信发送处理 SmsReceiverService: public int onStartCommand(Intent intent, int flags, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); // 发送消息到线程处理 } SmsReceiverService$ServiceHandler: public void handleMessage(Message msg) { ... else if (ACTION_SEND_MESSAGE.endsWith(action)) { // 处理发送消息 handleSendMessage(intent.getIntExtra(Sms.PHONE_ID, 0)); } ... } SmsReceiverService: private void handleSendMessage(int phoneId) { if (!mSending) { // 未发送 // 发送消息队列中的第一条消息 sendFirstQueuedMessage(phoneId); } } public synchronized void sendFirstQueuedMessage(int selectionPhoneId) { ... // 查询待发送的消息 final Uri uri = Uri.parse("content://sms/queued"); ContentResolver resolver = getContentResolver(); // date ASC so we send out in same order the user tried to send messages. Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, selection, null, "date ASC"); ... if (c.moveToFirst()) { // 查询到有待发送的消息 ... // 创建消息发送器 SmsMessageSender sender = new SmsSingleRecipientSender(this, address, msgText, threadId, status == Sms.STATUS_PENDING, msgUri, phoneId); ... // 发送消息 sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);; mSending = true; } } 9. 最终在SmsSingleRecipientSender中, 执行消息的发送 SmsSingleRecipientSender: public boolean sendMessage(long token) throws MmsException { ... // 消息管理 SmsManager smsManager = SmsManager.getDefault(mPhoneId); ArrayList messages = null; // 增加签名 SmsSignatureAppend smsSignatureAppend = new SmsSignatureAppend(mContext, mUri); // 增加签名后的消息内容 mMessageText = smsSignatureAppend.addSignatureToMsgText(mMessageText); ... // 获取编码类型, 0: Auto; 1: 7bit; 3: 16bit if (OperatorUtils.OPEN_MARKET && Settings.System.getInt(mContext.getContentResolver(), Settings.System.SMS_ENCODE_TYPE, 1) == 3) { messages = divideMessageFor16Bit(mMessageText); // 进行16bit编码进行消息分割 } else { messages = smsManager.divideMessage(mMessageText);// 进行7bit编码进行消息的分割 } } 9.1. 查看16bit编码进行消息分割 private ArrayList divideMessageFor16Bit(String text) { int msgCount; int limit; int count = text.length() * 2;// 如果是16bit, 短信允许的长度为70个字符 if (count > SmsMessage.MAX_USER_DATA_BYTES/*140*/) { // 说明短信的条数大于1条 // 因为java的除法没有小数, 因此这里直接+1条进行计算, 如5.2/2==(int)2; 而我们需要3, (5.2+1)/2==3 msgCount = (count + (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/ - 1)) / SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/; } else {// 说明短信的条数为1 msgCount = 1; } if (msgCount > 1) {// 如果短信的条数大于1, 则每条短信的长度为134, 会比只有1条短信少6个字节, 少的6个字节存储索引等数据 limit = SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/; } else {// 如果短信的条数小于1, 则短信的长度为140 limit = SmsMessage.MAX_USER_DATA_BYTES/*140*/; } ArrayList result = new ArrayList (msgCount); int pos = 0; // Index in code units. int textLen = text.length(); while (pos < textLen) { int nextPos = 0; // Counts code units. // limit/2: 实际的文本长度 nextPos = pos + Math.min(limit / 2, textLen - pos);// 获取截止的索引 if ((nextPos <= pos) || (nextPos > textLen)) { Log.e(TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " + nextPos + " >= " + textLen + ")"); break; } result.add(text.substring(pos, nextPos));// 保存截取的信息, 注意List是有序的 pos = nextPos; } return result; } 9.2. 查看7bit编码进行消息的分割 SmsManager: public ArrayList divideMessage(String text) { return SmsMessage.fragmentText(text); } public static ArrayList fragmentText(String text) { // This function is for MO SMS TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?// 此处用的是gsm格式 com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) :// 计算长度 com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);// 执行此处 // TODO(cleanup): The code here could be rolled into the logic // below cleanly if these MAX_* constants were defined more // flexibly... int limit; if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {// 执行此处 int udhLength; if (ted.languageTable != 0 && ted.languageShiftTable != 0) { udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES; } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) { udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE; } else { udhLength = 0;// 执行此处 } if (ted.msgCount > 1) { udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE/*6*/; } if (udhLength != 0) { udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH; } // 如果消息的条数大于1, 则limit为153, 如果消息的条数等于1, 则limit为160 limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;// } else { if (ted.msgCount > 1) { limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER; } else { limit = SmsConstants.MAX_USER_DATA_BYTES; } } // 以下进行短信的分割和16bit消息的分割一致 int pos = 0; // Index in code units. int textLen = text.length(); ArrayList result = new ArrayList (ted.msgCount); while (pos < textLen) { int nextPos = 0; // Counts code units. if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) { if (useCdmaFormatForMoSms() && ted.msgCount == 1) { // For a singleton CDMA message, the encoding must be ASCII... nextPos = pos + Math.min(limit, textLen - pos); } else { // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode). nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit, ted.languageTable, ted.languageShiftTable); } } else { // Assume unicode. nextPos = pos + Math.min(limit / 2, textLen - pos); } if ((nextPos <= pos) || (nextPos > textLen)) { Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " + nextPos + " >= " + textLen + ")"); break; } result.add(text.substring(pos, nextPos)); pos = nextPos; } return result; } 9.2.1 查看文本长度的计算 com.android.internal.telephony.gsm.SmsMessage: public static TextEncodingDetails calculateLength(CharSequence msgBody, boolean use7bitOnly) { TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly);//计算, 此处use7bitOnly==false ... } 9.2.2 继续文本的计算 GsmAlphabet: public static TextEncodingDetails countGsmSeptets(CharSequence s, boolean use7bitOnly) { ... // fast path for common case where no national language shift tables are enabled // 常见情况的快速路径,没有启用国家语言转换表 if (sEnabledSingleShiftTables.length + sEnabledLockingShiftTables.length == 0) {// 执行此处 TextEncodingDetails ted = new TextEncodingDetails(); int septets = GsmAlphabet.countGsmSeptetsUsingTables(s, use7bitOnly, 0, 0); // use7bitOnly此处为false if (septets == -1) { return null; } ted.codeUnitSize = SmsConstants.ENCODING_7BIT; ted.codeUnitCount = septets;// 编码后的消息长度 if (septets > SmsConstants.MAX_USER_DATA_SEPTETS/*160*/) { // 说明条数大于1条 ted.msgCount = (septets + (SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER/*153*/ - 1)) / SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER/*153*/;// 计算条数 ted.codeUnitsRemaining = (ted.msgCount * SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;// 获取剩余的数量 } else {// 说明条数为1条 ted.msgCount = 1; ted.codeUnitsRemaining = SmsConstants.MAX_USER_DATA_SEPTETS - septets;// 获取剩余的数量 } ted.codeUnitSize = SmsConstants.ENCODING_7BIT;// 设置为7bit编码 return ted; } ... } 9.2.3 继续文本长度的计算 GsmAlphabet: public static int countGsmSeptetsUsingTables(CharSequence s, boolean use7bitOnly,// s, false int languageTable, int languageShiftTable) {//0, 0 int count = 0; int sz = s.length(); SparseIntArray charToLanguageTable = sCharsToGsmTables[languageTable]; // GSM 7 bit Default Alphabet Extension Table SparseIntArray charToShiftTable = sCharsToShiftTables[languageShiftTable];// GSM 7 bit Default Alphabet Extension Table for (int i = 0; i < sz; i++) { char c = s.charAt(i); if (c == GSM_EXTENDED_ESCAPE) { Rlog.w(TAG, "countGsmSeptets() string contains Escape character, skipping."); continue; } if (charToLanguageTable.get(c, -1) != -1) { count++; } else if (charToShiftTable.get(c, -1) != -1) { count += 2; // escape + shift table index } else if (use7bitOnly) { count++; // encode as space } else { return -1; // caller must check for this case } } return count; } 10. 继续消息的发送流程 SmsSingleRecipientSender: public boolean sendMessage(long token) throws MmsException { ... if (OperatorUtils.OPEN_MARKET && Settings.System.getInt(mContext.getContentResolver(), Settings.System.SMS_ENCODE_TYPE, 1) == 3) { messages = divideMessageFor16Bit(mMessageText); } else { messages = smsManager.divideMessage(mMessageText);// 进行发送信息 } ... // 将消息移到发件箱, 因此在content://sms/queued中只会存在待发送的信息 boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0); ... ArrayList deliveryIntents = new ArrayList (messageCount); ArrayList sentIntents = new ArrayList (messageCount); for (int i = 0; i < messageCount; i++) { // mRequestDeliveryReport: 接收人接收到消息的状态的回复 if (mRequestDeliveryReport && (i == (messageCount - 1))) { // TODO: Fix: It should not be necessary to // specify the class in this intent. Doing that // unnecessarily limits customizability. deliveryIntents.add(PendingIntent.getBroadcast( mContext, 0, new Intent( MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION, mUri, mContext, MessageStatusReceiver.class), 0)); } else { deliveryIntents.add(null); } // 消息发送的意图 Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION, mUri, mContext, SmsReceiver.class); intent.putExtra("smssignature", mMessageText); int requestCode = 0; if (i == messageCount -1) { // Changing the requestCode so that a different pending intent // is created for the last fragment with // EXTRA_MESSAGE_SENT_SEND_NEXT set to true. requestCode = 1; intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true); intent.putExtra(Sms.PHONE_ID, mPhoneId); } sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0)); } ... // 执行消息的发送 smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents); } 11. 消息发送转移至IccSmsInterfaceManager SmsManager: public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList parts, ArrayList sentIntents, ArrayList deliveryIntents) { ... if (parts.size() > 1) { try { ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(TelephonyManager.getServiceName("isms", mPhoneId))); if (iccISms != null) { // 发送消息, 至此Mms中的流程已经走完, 下面进入framework层的流程 iccISms.sendMultipartText(ActivityThread.currentPackageName(), destinationAddress, scAddress, parts, sentIntents, deliveryIntents); } } catch (RemoteException ex) { // ignore it } } else { ... // 发送消息 sendTextMessage(destinationAddress, scAddress, parts.get(0), sentIntent, deliveryIntent); } } public void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { ... try { ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(TelephonyManager.getServiceName("isms", mPhoneId))); if (iccISms != null) { // 发送消息, 至此Mms中的流程已经走完, 下面进入framework层的流程 iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, scAddress, text, sentIntent, deliveryIntent); } } catch (RemoteException ex) { // ignore it } }