首先我要从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) { }}
- 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
里面有这样的一段代码:
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
既然是抽象类,那肯定就有实现它的派生类,在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) }
在同级路径下打开ImsSmsDispatcher.java我们会发现,ImsSmsDispatcher持有了CdmaSMSDispatcher、GsmSMSDispatcher这两个对象的实例:
private SMSDispatcher mCdmaDispatcher;private SMSDispatcher mGsmDispatcher;
通过判断网络制式,分别调用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 support return 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()方法,如下:
@Override protected 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 , true ,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); return; } if (pdu == null) { Rlog.e(TAG, "Empty PDU"); tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0); return; } PendingIntent sentIntent = tracker.mSentIntent; PackageManager pm = mContext.getPackageManager(); int callingUid = Binder.getCallingUid(); String[] 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) { Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS"); tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0); return; } PackageInfo appInfo; try { appInfo = 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); return; } if (checkDestination(tracker)) { if (!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()方法:
@Override protected 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-MR if (((0x01 & pdu[0]) == 0x01)) { pdu[0] |= 0x04 pdu[1] = (byte) tracker.mMessageRef } } 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()方法又干了些什么事情。
@Override protected void sendSmsByPstn(SmsTracker tracker) { int ss = mPhone.getServiceState().getState(); if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { tracker.onFailed(mContext, getNotInServiceError(ss), 0); 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); if (0 == tracker.mImsRetry && !isIms()) { if (tracker.mRetryCount > 0) { if (((0x01 & pdu[0]) == 0x01)) { pdu[0] |= 0x04; pdu[1] = (byte) tracker.mMessageRef; } } 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); 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
0 0