转载请注明出处:http://blog.csdn.net/droyon/article/details/11699935
2,短彩信发送framework逻辑
短信在SmsSingleRecipientSender.java中包装了SentIntents,以及DeliveryIntents,信息的内容在message中,信息的目的发送地址在mDest中,然后调用下面的代码进行信息的发送
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
smsMessager对应的类为:SmsManager.java
2.1 进入SmsManager.java
public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { if (TextUtils.isEmpty(destinationAddress)) { throw new IllegalArgumentException("Invalid destinationAddress"); } if (parts == null || parts.size() < 1) { throw new IllegalArgumentException("Invalid message body"); } 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); } }
在这个类中,主要是根据parts的数量,进行跨进程调用ISms服务。如果是多条信息,执行:
iccISms.sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents);
这里调用的ISms服务的sendMultipartText方法。
如果是单条信息,执行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 = ISms.Stub.asInterface(ServiceManager.getService("isms")); if (iccISms != null) { iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent); } } catch (RemoteException ex) { // ignore it } }
同样的,要调用ISms服务。只不过方法变成了Isms服务的sendText方法
关于iSms服务的注册,它是在初始化phone进程时注册的
public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager iccSmsInterfaceManager) { this.mIccSmsInterfaceManager = iccSmsInterfaceManager; if(ServiceManager.getService("isms") == null) { ServiceManager.addService("isms", this); } }
然后我们进到IccSmsInterfaceManagerProxy.java中
2.2 IccSmsManagerProxy.java
public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { mIccSmsInterfaceManager.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent); } public void sendMultipartText(String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException { mIccSmsInterfaceManager.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents); }
代理类中进行实现
2.3 iccSmsManager.java
public void sendMultipartText(String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { mPhone.getContext().enforceCallingPermission( "android.permission.SEND_SMS", "Sending SMS message"); if (Log.isLoggable("SMS", Log.VERBOSE)) { int i = 0; for (String part : parts) { log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr + ", part[" + (i++) + "]=" + part); } } mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts, (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); }
public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { mPhone.getContext().enforceCallingOrSelfPermission( "android.permission.SEND_SMS", "Sending SMS message"); if (Log.isLoggable("SMS", Log.VERBOSE)) { log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr + " text='"+ text + "' sentIntent=" + sentIntent + " deliveryIntent=" + deliveryIntent); } mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent); }
最终他们都要调到mDispatcher的sendText或者sendMultipartText方法,mDispatcher的原型类:SMSDispatcher,它有两个子类,GsmSmsDispatcher.java以及CdmaSmsDispatcher.java
2.4,GsmSmsDispatcher.java
protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { int refNumber = getNextConcatenatedRef() & 0x00FF; int msgCount = parts.size(); int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN; mRemainingMessages = msgCount; TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; for (int i = 0; i < msgCount; i++) { TextEncodingDetails details = calculateLength(parts.get(i), false); if (encoding != details.codeUnitSize && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) { encoding = details.codeUnitSize; } encodingForParts[i] = details; } for (int i = 0; i < msgCount; i++) { SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); concatRef.refNumber = refNumber; concatRef.seqNumber = i + 1; // 1-based sequence concatRef.msgCount = msgCount; // TODO: We currently set this to true since our messaging app will never // send more than 255 parts (it converts the message to MMS well before that). // However, we should support 3rd party messaging apps that might need 16-bit // references // Note: It's not sufficient to just flip this bit to true; it will have // ripple effects (several calculations assume 8-bit ref). concatRef.isEightBits = true; SmsHeader smsHeader = new SmsHeader(); smsHeader.concatRef = concatRef; // Set the national language tables for 3GPP 7-bit encoding, if enabled. if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) { smsHeader.languageTable = encodingForParts[i].languageTable; smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable; } PendingIntent sentIntent = null; if (sentIntents != null && sentIntents.size() > i) { sentIntent = sentIntents.get(i); } PendingIntent deliveryIntent = null; if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1))); } }
遍历所有的短信part,然后执行sendNewSubmitPdu方法,这个方法在SmsDispatcher.java中是abstract的,真正的实现在其子类中:
protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message, SmsHeader smsHeader, int encoding, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable, smsHeader.languageShiftTable); if (pdu != null) { sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent); } else { Log.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null"); } }
实现方式为执行sendRawPdu。
以上是sendMultipartsText,让我们看看sendText方法在SmsDispatcher.java中的实现:
protected abstract void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent);
SmsDispatcher.java的设计方法为让其子类来决定sendText方法的实现方式,现贴出sendText的源码实现:
protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( scAddr, destAddr, text, (deliveryIntent != null)); if (pdu != null) { sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent); } else { Log.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null"); } }
我们看到其实现方式为执行sendRawPdu,到这里也就是说,无论是sendText还是sendMultipartsText方法,他们归根结底都是执行sendRawPdu方法,不同的是sendMultipartsText是遍历所有的短信parts,然后在调用sendRawPdu。
在这个方法的前一步会将信息的内容,要发送的目的地址,当前的系统时间等打包成SubmitPdu,关于短信pdu这部分,会稍后介绍,我们现在主要解析一下短信framework发送的主要逻辑。
下面我们看看sendRawPdu的方法实现:
protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (mSmsSendDisabled) { if (sentIntent != null) { try { sentIntent.send(RESULT_ERROR_NO_SERVICE); } catch (CanceledException ex) {} } Log.d(TAG, "Device does not support sending sms."); return; } if (pdu == null) { if (sentIntent != null) { try { sentIntent.send(RESULT_ERROR_NULL_PDU); } catch (CanceledException ex) {} } return; } HashMap<String, Object> map = new HashMap<String, Object>(); map.put("smsc", smsc); map.put("pdu", pdu); SmsTracker tracker = new SmsTracker(map, sentIntent, deliveryIntent); int ss = mPhone.getServiceState().getState(); if (ss != ServiceState.STATE_IN_SERVICE) { handleNotInService(ss, tracker); } else { String appName = getAppNameByIntent(sentIntent); if (mUsageMonitor.check(appName, SINGLE_PART_SMS)) { sendSms(tracker); } else { sendMessage(obtainMessage(EVENT_POST_ALERT, tracker)); } } }
在这个方法里,首先会检查一些状态,例如pdu是否为null,smsSendDisabled等,然后包装一个SmsTracher对象,在发送前还要检查一下Phone进程的状态,是否处于“离线”状态,关于这个状态,moderm会根据当前所处的信号强度,做出改变。
如果当前处于服务中,那么就可以进行我们短信的发送了,发送调用sendMessage或者sendSms进行短信的发送,关于sendMessage这个方法,参数为Message,message生成代码:
public final Message obtainMessage(int what, Object obj) { return Message.obtain(this, what, obj); }
也就是说这个message是和Handler相关的message。
PS:我不知道大家有没有注意,其实SmsDispatcher.java这个类就是个Handler。
在发送之前,会调用:
mUsageMonitor.check(appName, SINGLE_PART_SMS)
进行检查,所作的事情其实就是检查在一段时间内,等待发送的短信数目不超过MAX值,关于等待时间以及MAX数目:
SmsUsageMonitor.java
/** Default checking period for SMS sent without user permission. */ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; /** Default number of SMS sent in checking period without user permission. */ private static final int DEFAULT_SMS_MAX_COUNT = 100;
回到短信发送中,在此处,检查通过,故短信发送执行sendSms(tracker)
protected void sendSms(SmsTracker tracker) { 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); mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply); }
其中mCm对象是CommandInterface的引用
protected final CommandsInterface mCm;
很多人对它不是很熟悉,但一定很熟悉它的其中一个子类,那就是RIL.java。
也就是说,短信发送流程,在此处会调用RIL.java,执行sendSMS方法,参数为smsc的pdu字符串,短信内容以及时间等的pdu,以及一个Message,WHAT值为EVENT_SEND_SMS_COMPLETE,tracher对象作为其Object。我们进入到RIL.java中
2.5,RIL.java
public void sendSMS (String smscPDU, String pdu, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result); rr.mp.writeInt(2); rr.mp.writeString(smscPDU); rr.mp.writeString(pdu); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); }
关于RIL.java,它会和reference_ril.c进行配合,进行at指令的发送以及接收反馈等信息。reference_ril.c文件会被编译到reference-ril.so中。
在此处,RIL.java会将相应的pdu等信息打包,然后通过socket发送到reference_ril.c中,相关处理如下:
2.6,reference_ril.c
static void requestSendSMS(void *data, size_t datalen, RIL_Token t) { int err; const char *smsc; const char *pdu; int tpLayerLength; char *cmd1, *cmd2; RIL_SMS_Response response; ATResponse *p_response = NULL; smsc = ((const char **)data)[0]; pdu = ((const char **)data)[1]; tpLayerLength = strlen(pdu)/2; // "NULL for default SMSC" if (smsc == NULL) { smsc= "00"; } asprintf(&cmd1, "AT+CMGS=%d", tpLayerLength); asprintf(&cmd2, "%s%s", smsc, pdu); err = at_send_command_sms(cmd1, cmd2, "+CMGS:", &p_response); if (err != 0 || p_response->success == 0) goto error; memset(&response, 0, sizeof(response)); /* FIXME fill in messageRef and ackPDU */ RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response)); at_response_free(p_response); return; error: RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); at_response_free(p_response); }
调用AT命令,cmgs将信息发往moderm,进行相关流程处理。
最后,如果短信成功发送出去,还记得我们在发送时,从GsmSmsDispatcher.java传递到RIL.java中的Message吗,在发送之后,RIL.java会回调此Message,这个Message如下:
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
前面说了,What = EVENT_SEND_SMS_COMPLETE,Object = tricker。我们之前也说了SmsDispacher.java以及其子类是Handler,那么这个Message在那里处理的那?答案是在SmsDispacher.java中,处理逻辑代码如下:
case EVENT_SEND_SMS_COMPLETE: // An outbound SMS has been successfully transferred, or failed. handleSendComplete((AsyncResult) msg.obj); break;
protected void handleSendComplete(AsyncResult ar) { SmsTracker tracker = (SmsTracker) ar.userObj; PendingIntent sentIntent = tracker.mSentIntent; if (ar.exception == null) { if (false) { Log.d(TAG, "SMS send complete. Broadcasting " + "intent: " + sentIntent); } if (tracker.mDeliveryIntent != null) {//wanghailu,hailushijie@163.com ,hlwang // Expecting a status report. Add it to the list. int messageRef = ((SmsResponse)ar.result).messageRef; tracker.mMessageRef = messageRef; deliveryPendingList.add(tracker); } if (sentIntent != null) { try { if (mRemainingMessages > -1) { mRemainingMessages--; } if (mRemainingMessages == 0) { Intent sendNext = new Intent(); sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true); sentIntent.send(mContext, Activity.RESULT_OK, sendNext); } else { sentIntent.send(Activity.RESULT_OK); } } catch (CanceledException ex) {} } } else { if (false) { Log.d(TAG, "SMS send failed"); } int ss = mPhone.getServiceState().getState(); if (ss != ServiceState.STATE_IN_SERVICE) { handleNotInService(ss, tracker); } else if ((((CommandException)(ar.exception)).getCommandError() == CommandException.Error.SMS_FAIL_RETRY) && tracker.mRetryCount < MAX_SEND_RETRIES) { // Retry after a delay if needed. // TODO: According to TS 23.040, 9.2.3.6, we should resend // with the same TP-MR as the failed message, and // TP-RD set to 1. However, we don't have a means of // knowing the MR for the failed message (EF_SMSstatus // may or may not have the MR corresponding to this // message, depending on the failure). Also, in some // implementations this retry is handled by the baseband. tracker.mRetryCount++; Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker); sendMessageDelayed(retryMsg, SEND_RETRY_DELAY); } else if (tracker.mSentIntent != null) { int error = RESULT_ERROR_GENERIC_FAILURE; if (((CommandException)(ar.exception)).getCommandError() == CommandException.Error.FDN_CHECK_FAILURE) { error = RESULT_ERROR_FDN_CHECK_FAILURE; } // Done retrying; return an error to the app. try { Intent fillIn = new Intent(); if (ar.result != null) { fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode); } if (mRemainingMessages > -1) { mRemainingMessages--; } if (mRemainingMessages == 0) { fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true); } tracker.mSentIntent.send(mContext, error, fillIn); } catch (CanceledException ex) {} } } }
至此,短信发送流程大致如此,短信接收流程中framework部分的处理大致是发送流程的反方向。
首先检查AsyncResult对象中是否存在异常,如果成功发送的信息,那么不存在异常,如果发送失败,那么是存在Exception的,会进行异常的相应的逻辑处理,大体流程相似,故本处介绍无异常时的流程逻辑。
无论发送成功还是失败,大体都是执行tricker对象中的mSentIntents,这是一个PendingIntent,执行send会发送此广播,那么我们的上层应用Mms中的SmsReceiverService.java会收到这个广播,并进行相应的逻辑处理,逻辑代码大体如下:
private void handleSmsSent(Intent intent, int error) { Uri uri = intent.getData(); mSending = false; boolean sendNextMsg = intent.getBooleanExtra(EXTRA_MESSAGE_SENT_SEND_NEXT, false); if (LogTag.DEBUG_SEND) { Log.v(TAG, "handleSmsSent uri: " + uri + " sendNextMsg: " + sendNextMsg + " mResultCode: " + mResultCode + " = " + translateResultCode(mResultCode) + " error: " + error); } if (mResultCode == Activity.RESULT_OK) { if (LogTag.DEBUG_SEND || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handleSmsSent move message to sent folder uri: " + uri); } if (!Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_SENT, error)) { Log.e(TAG, "handleSmsSent: failed to move message " + uri + " to sent folder"); } if (sendNextMsg) { sendFirstQueuedMessage(); } // Update the notification for failed messages since they may be deleted. MessagingNotification.updateSendFailedNotification(this); } else if ((mResultCode == SmsManager.RESULT_ERROR_RADIO_OFF) || (mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE)) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "handleSmsSent: no service, queuing message w/ uri: " + uri); } // We got an error with no service or no radio. Register for state changes so // when the status of the connection/radio changes, we can try to send the // queued up messages. registerForServiceStateChanges(); // We couldn't send the message, put in the queue to retry later. Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_QUEUED, error); mToastHandler.post(new Runnable() { public void run() { Toast.makeText(SmsReceiverService.this, getString(R.string.message_queued), Toast.LENGTH_SHORT).show(); } }); } else if (mResultCode == SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE) { mToastHandler.post(new Runnable() { public void run() { Toast.makeText(SmsReceiverService.this, getString(R.string.fdn_check_failure), Toast.LENGTH_SHORT).show(); } }); } else { messageFailedToSend(uri, error); if (sendNextMsg) { sendFirstQueuedMessage(); } } }
主要是根据ResultCode进行一些逻辑处理,比如如果发送成功,那么会首先更新短信由待发送变为已发送状态,并且更新Notification等。
如果需要发送报告,那么相关的逻辑大体相似,不再详细介绍。
Ps:发送成功,回调会从moderm那里带回来一个MessageRef,这是一个int值,很重要噢。
短信发送framework层逻辑大体介绍到这里,framework层的短彩信逻辑还有好多,比如接收信息的流程,或者接收长短信的流程等,不再一一介绍了。