Android开发之Android5.1.1(CM12.1)源码中短信发送流程解析
2017-04-18 09:04
453 查看
首先我要从SmsManager开始一步步深入了解,相信大家在学习Android基础的时候接触过这个类。它在/frameworks/opt/telephony/src/java/android/telephony路径下,SmsManager:提供管理短信操作,如发送数据,文本和PDU短信。通过调用静态方法SmsManager.getDefault() 获取此对象。它里面提供了一系列发送短信的方法,我们就从sendTextMessage()方法说起,首先我们来看看这个方法:
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中的短信。打开它会发现这样的继承关系:
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。如下:
1
既然是抽象类,那肯定就有实现它的派生类,在Android5.1.1中我找到了三个派生类:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSmsDispatcher。但是在IccSmsInterfaceManager 中只创建了ImsSmsDispatcher。
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
在同级路径下打开ImsSmsDispatcher.java我们会发现,ImsSmsDispatcher持有了CdmaSMSDispatcher、GsmSMSDispatcher这两个对象的实例:
2
1
2
通过判断网络制式,分别调用mCdmaDispatcher或者mGsmDispatcher的sendText()方法。
判断网络制式:
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()方法,如下:
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 中,所以我们又得去父类看:
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()方法:
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()方法又干了些什么事情。
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
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) { // ignore it } }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.Stub1
1
里面有这样的一段代码:
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 Handler1
1
既然是抽象类,那肯定就有实现它的派生类,在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); }1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
在同级路径下打开ImsSmsDispatcher.java我们会发现,ImsSmsDispatcher持有了CdmaSMSDispatcher、GsmSMSDispatcher这两个对象的实例:
private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher;1
2
1
2
通过判断网络制式,分别调用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 /* fullMessageText */, true /* isText */,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/* errorCode */); return; } if (pdu == null) { Rlog.e(TAG, "Empty PDU"); tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/* errorCode */); return; } PendingIntent sentIntent = tracker.mSentIntent; // Get calling app package name via UID from Binder call PackageManager pm = mContext.getPackageManager(); int callingUid = Binder.getCallingUid(); // Special case: We're being proxied by the telephony stack itself, // so use the intent generator's UID if one exists 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) { // Refuse to send SMS if we can't get the calling package name. Rlog.e(TAG, "Can't get calling app package name: refusing to send SMS"); tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/* errorCode */); return; } // Get package info via packagemanager PackageInfo appInfo; try { // XXX this is lossy- apps can share a UID 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/* errorCode */); return; } // checkDestination() returns true if the destination is not a premium // short code or the // sending app is approved to send to short codes. Otherwise, a message // is sent to our // handler with the SmsTracker to request user confirmation before // sending. if (checkDestination(tracker)) { // check for excessive outgoing SMS usage by this app 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; // TP-RD pdu[1] = (byte) tracker.mMessageRef; // TP-MR } } 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 sms over IMS is not supported on data and voice is not // available... if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { tracker.onFailed(mContext, getNotInServiceError(ss), 0/* errorCode */); 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); // sms over gsm is used: // if sms over IMS is not supported AND // this is not a retry case after sms over IMS failed // indicated by mImsRetry > 0 if (0 == tracker.mImsRetry && !isIms()) { if (tracker.mRetryCount > 0) { // 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; // TP-RD pdu[1] = (byte) tracker.mMessageRef; // TP-MR } } 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); // increment it here, so in case of SMS_FAIL_RETRY over IMS // next retry will be sent using IMS request again. 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
相关文章推荐
- Android开发之Android5.1.1(CM12.1)源码中短信发送流程解析
- android短彩信源码解析-短信发送流程
- Android短彩信源码解析-短信发送流程(二)
- Android短彩信源码解析-短信发送流程(三)
- Android短彩信源码解析-短信发送流程(一)
- Android短彩信源码解析-短信发送流程(二)
- Android Mms短信的发送流程,短信发送源码解析
- Android短彩信源码解析-短信发送流程(三)
- Android软件开发之发送短信与系统短信库解析(三十)
- Android软件开发之发送短信与系统短信库解析(三十)
- Android软件开发之发送短信与系统短信库解析
- (转)Android软件开发之发送短信与系统短信库解析(三十)
- Android软件开发之发送短信与系统短信库解析
- Android软件开发之发送短信与系统短信库解析
- Android软件开发之发送短信与系统短信库解析
- Android软件开发之发送短信与系统短信库解析(三十)
- Android软件开发之发送短信与系统短信库解析
- 插件化系列开发之九--Android 全面插件化 RePlugin 流程与源码解析
- Android短信发送和接收流程源码分析