1.短信发送的起点是在短信编辑界面,点击发送按钮开始的
public class ComposeMessageActivity extends Activity ...{
....public void sendMessage(boolean bCheckEcmMode) { ....//这里面准备发送的数据处理,比如生成PDU数据,存储到数据mWorkingMessage.send(mDebugRecipients, mSelectedSubId); }
mWorkingMessage中具体发送短信的工作在preSendSmsWorker方法里面
private void preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI,
int subId, boolean hasBeenSplit) {
// just do a regular send. We’re already on a nonui thread so no need to fire
// off another thread to do this work.
/// M: Code analyze 047, For new feature ALPS00316567, add a parameter for msim . @{
sendSmsWorker是最主要的类,做了实际的发送工作,但他里面不是立即发送短信,而是发送短信的请求封装成SmsMessageSender,
sendSmsWorker(msgText, semiSepRecipients, threadId, subId);
/// @}
…
} .
SmsReceiverService
SmsMessageSender*******************************************
将待发送的短信存储到数据库表格中,content://sms/queued
然后再启动服务SmsReceiverService,让服务去单个发送每一条短信,SmsReceiverService重待发送短信表格中取出一条短信,然后交由
SmsSingleRecipientSender去发送。
MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId, subId);短信发送处理public boolean sendMessage(long token) throws MmsException {
号码处理,将其中的空格去除。得到有效的发送号码。
生成2个广播1.发送报告广播,2.发送短信广播
最终调用系统接口SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(mSubId);
SmsManager***************************************************************************************************public void sendMultipartTextMessage(String destinationAddress, String scAddress, ArrayList<String> parts,ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {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.Stub.asInterface(ServiceManager.getService("isms"));,这个的服务类型有多种,
发送彩信********************************************************************************************
sendMmsWorker(spliter.getMMSConversation(),mmsUri, persister, slideshow, sendReq, subId);
/// M: Code analyze 047, For new feature ALPS00316567, add a parameter for msim . @{private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId, int subId) {/// @}String[] dests = TextUtils.split(semiSepRecipients, ";");if (LogTag.VERBOSE || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {Log.d(LogTag.TRANSACTION, "sendSmsWorker sending message: recipients=" +semiSepRecipients + ", threadId=" + threadId);}MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId, subId);try {sender.sendMessage(threadId);// Make sure this thread isn't over the limits in message countRecycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);} catch (Exception e) {Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);}mStatusListener.onMessageSent();MmsWidgetProvider.notifyDatasetChanged(mActivity);} public boolean sendMessage(long token) throws MmsException {// In order to send the message one by one, instead of sending now, the message will split,// and be put into the queue along with each destinationsreturn queueMessage(token);}private boolean queueMessage(long token) throws MmsException {/// M:MmsLog.v(MmsApp.TXN_TAG, "queueMessage()");if ((mMessageText == null) || mMessageText.isEmpty() || (mNumberOfDests == 0)) {// Don't try to send an empty message.throw new MmsException("Null message body or dest.");}SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);boolean requestDeliveryReport = prefs.getBoolean(mSubId + "_" + SmsPreferenceActivity.SMS_DELIVERY_REPORT_MODE,DEFAULT_DELIVERY_REPORT_MODE);MmsLog.d(MmsApp.TXN_TAG, "SMS DR request=" + requestDeliveryReport);/// @}Uri smsUri = null;//star os add by liuweibolong timeStamp = System.currentTimeMillis();for (int i = 0; i < mNumberOfDests; i++) {try {if (LogTag.DEBUG_SEND) {Log.v(TAG, "queueMessage mDests[i]: " + mDests[i] + " mThreadId: " + mThreadId);}smsUri = mOpSmsMessageSender.queueMessage(mNumberOfDests,//star os modify by liuweibomContext.getContentResolver(), mDests[i], mMessageText, mTimestamp,requestDeliveryReport, mThreadId, mSubId, timeStamp);if (smsUri == null) {smsUri=Sms.addMessageToUri(mSubId,//star os modify by liuweibomContext.getContentResolver(),Uri.parse("content://sms/queued"), mDests[i],mMessageText, null, mTimestamp,true /* read */,requestDeliveryReport,mThreadId);}//star os add start by liuweiboIntent sentIt = new Intent("delay_send_sms", null, mContext,SmsReceiver.class);long msgId = Integer.valueOf(smsUri.toString().substring(14));sentIt.putExtra("message_id", msgId);mContext.sendBroadcast(sentIt);//star os add end by liuweibo} catch (SQLiteException e) {if (LogTag.DEBUG_SEND) {Log.e(TAG, "queueMessage SQLiteException", e);}SqliteWrapper.checkSQLiteException(mContext, e);}}// Notify the SmsReceiverService to send the message out//star os del start by liuweibo/*mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,null,mContext,SmsReceiver.class));*///star os del end by liuweiboreturn false;}
/frameworks/opt/telephony/src/java/android/telephony/SmsManager.java
sendStoredMultimediaMessage
/*** Send a system stored MMS message** This is used for sending a previously sent, but failed-to-send, message or* for sending a text message that has been stored as a draft.** @param messageUri the URI of the stored message* @param configOverrides the carrier-specific messaging configuration values to override for* sending the message.* @param sentIntent if not NULL this <code>PendingIntent</code> is* broadcast when the message is successfully sent, or failed* @throws IllegalArgumentException if messageUri is empty* {@hide}*/
public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
PendingIntent sentIntent) {
if (messageUri == null) {
throw new IllegalArgumentException("Empty message URI");
}
try {
IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
if (iMms != null) {
iMms.sendStoredMessage(
getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
configOverrides, sentIntent);
}
} catch (RemoteException ex) {
// ignore it
}
}
短信接收***********************************************************************************
首先系统发出android.provider.Telephony.Sms.Intents.SMS_DELIVER_ACTION广播,然后SmsReceiver接收,接收后启动
service SmsReceiverService处理
系统是什么地方发送广播:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java
/*** In the delivering state, the inbound SMS is processed and stored in the raw table.* The message is acknowledged before we exit this state. If there is a message to broadcast,* transition to {@link WaitingState} state to send the ordered broadcast and wait for the* results. When all messages have been processed, the halting state will release the wakelock.*/private class DeliveringState extends State {****@Overridepublic boolean processMessage(Message msg) {log("DeliveringState.processMessage:" + msg.what);log("DeliveringState.processMessage:" + msg.what);switch (msg.what) {case EVENT_BROADCAST_SMS:// if any broadcasts were sent, transition to waiting stateInboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj;if (processMessagePart(inboundSmsTracker)) {transitionTo(mWaitingState);} else {// if event is sent from SmsBroadcastUndelivered.broadcastSms(), and// processMessagePart() returns false, the state machine will be stuck in// DeliveringState until next message is received. Send message to// transition to idle to avoid that so that wakelock can be releasedlog("No broadcast sent on processing EVENT_BROADCAST_SMS in Delivering " +"state. Return to Idle state");sendMessage(EVENT_RETURN_TO_IDLE);}return HANDLED;****private boolean processMessagePart(InboundSmsTracker tracker) {****dispatchSmsDeliveryIntent(pdus, tracker.getFormat(), destPort, resultReceiver,IConcatenatedSmsFwkExt.UPLOAD_FLAG_NONE);/private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,BroadcastReceiver resultReceiver, int longSmsUploadFlag) {// MTKENDIntent intent = new Intent();intent.putExtra("pdus", pdus);intent.putExtra("format", format);if (destPort == 1) {intent.setAction(Intents.SMS_DELIVER_ACTION);***dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,AppOpsManager.OP_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM);
public void dispatchIntent(Intent intent, String permission, int appOp,Bundle opts, BroadcastReceiver resultReceiver, UserHandle user) {intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);******mContext.sendOrderedBroadcastAsUser(intent, user, permission, appOp, opts,resultReceiver, getHandler(), Activity.RESULT_OK, null, null);
到这里,消息广播就发送出去了。
将PDU数据插入到raw表中/*** Insert a message PDU into the raw table so we can acknowledge it immediately.* If the device crashes before the broadcast to listeners completes, it will be delivered* from the raw table on the next device boot. For singlepart messages, the deleteWhere* and deleteWhereArgs fields of the tracker will be set to delete the correct row after* the ordered broadcast completes.** @param tracker the tracker to add to the raw table* @return true on success; false on failure to write to database*/private int addTrackerToRawTable(InboundSmsTracker tracker, boolean deDup) {
短信接收时序图: