Android平台 短信发送流程剖析(含编码)
本文对Android平台短信发送流程进行了走读和剖析,特别是编码部分,今天将流程整理出来,以便平时参考,也希望对大家有用!!!
先上图,下面2个图是用PPT画的,这里截图附上来:
流程图1:
流程图2:
发送流程编码解析:
从上图中的GsmSMSDispatcher的sendText开始分析
//GsmSMSDispatcher.java /** {@inheritDoc} */ @Override // ①入口 protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu ( //转②分析 scAddr, destAddr, text, (deliveryIntent != null)); HashMap map = SmsTrackerMapFactory(destAddr, scAddr, text, pdu); SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent, RadioTechnologyFamily.RADIO_TECH_3GPP); sendRawPdu(tracker); //转I分析 } ②分析: //SmsMessage.java public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested) { return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); //转③分析 } ③分析 //SmsMessage.java public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header) { return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,ENCODING_UNKNOWN/*默认编码方式*/); //转④分析 } ④分析 编码核心函数 //SmsMessage.java public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header, int encoding) { // 3 // Perform null parameter checks. if (message == null || destinationAddress == null) { return null; } SubmitPdu ret = new SubmitPdu(); // MTI = SMS-SUBMIT, UDHI = header != null byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); //MTI :bit 0 和 bit1 UDHI:bit6 // 0x01 = 0000 0001 0x40 = 0010 0000 ByteArrayOutputStream bo = getSubmitPduHead( scAddress, destinationAddress, mtiByte, statusReportRequested, ret); //转⑤分析 // User Data (and length) //TP-DCS 和TP-UDL byte[] userData; if (encoding == ENCODING_UNKNOWN) { // First, try encoding it with the GSM alphabet encoding = ENCODING_7BIT; //默认先采用ENCODING_7BIT编码模式 } try { if (encoding == ENCODING_7BIT) { userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); //采用ENCODING_7BIT进行编码,若出现编码异常,函数会抛出异常:EncodeException,转至⑥处。编码成功转至⑦。stringToGsm7BitPackedWithHeader分析转⑧处 } else { //assume UCS-2 try { userData = encodeUCS2(message, header); } catch(UnsupportedEncodingException uex) { Log.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); return null; } } } catch (EncodeException ex) { //⑥ 7bit编码模式失败后,就采用UCS-2进行编码 // Encoding to the 7-bit alphabet failed. Let's see if we can // send it as a UCS-2 encoded message try { userData = encodeUCS2(message, header); encoding = ENCODING_16BIT; } catch(UnsupportedEncodingException uex) { Log.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); return null; } } if (encoding == ENCODING_7BIT) { //⑦ 7bit编码成功 if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { // Message too long return null; } // TP-Data-Coding-Scheme // Default encoding, uncompressed // To test writing messages to the SIM card, change this value 0x00 // to 0x12, which means "bits 1 and 0 contain message class, and the // class is 2". Note that this takes effect for the sender. In other // words, messages sent by the phone with this change will end up on // the receiver's SIM card. You can then send messages to yourself // (on a phone with this change) and they'll end up on the SIM card. //0x12 = 0001 0010 未压缩,class2,存储到SIM卡 //0x00 = 0000 0000 未压缩,class0,GSM7bit编码 bo.write(0x00); } else { // assume UCS-2 if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { // Message too long return null; } // TP-Data-Coding-Scheme // Class 3, UCS-2 encoding, uncompressed bo.write(0x0b); //0x0b = 0000 1011 未压缩,class3,UCS-2编码 } // (no TP-Validity-Period) bo.write(userData, 0, userData.length); ret.encodedMessage = bo.toByteArray(); return ret; } ⑤分析 //SmsMessage.java private static ByteArrayOutputStream getSubmitPduHead( String scAddress, String destinationAddress, byte mtiByte, boolean statusReportRequested, SubmitPdu ret) //scAddress为短信中心号码,destinationAddress为目标地址号码 //mtiByte为MTI和UDHI 编码数据,见上面分析,statusReportRequested为状态报告 //ret 下面会写入数据到ret { ByteArrayOutputStream bo = new ByteArrayOutputStream( MAX_USER_DATA_BYTES + 40); // SMSC address with length octet, or 0 if (scAddress == null) { ret.encodedScAddress = null; } else { ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( scAddress); } // TP-Message-Type-Indicator (and friends) if (statusReportRequested) { // Set TP-Status-Report-Request bit. //TP-SRR bit 5 ,0x20 = 0010 0000 mtiByte |= 0x20; if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); } bo.write(mtiByte); // space for TP-Message-Reference //TP-MR bo.write(0); byte[] daBytes; daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); // destination address length in BCD digits, ignoring TON byte and pad // TODO Should be better. bo.write((daBytes.length - 1) * 2 - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); // destination address bo.write(daBytes, 0, daBytes.length); // TP-Protocol-Identifier //TP--PID bo.write(0); return bo; } ⑧分析 //GsmAlphabet.java public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header) throws EncodeException { //这里传进来的head为null if (header == null || header.length == 0) { return stringToGsm7BitPacked(data); //转⑨分析 } int headerBits = (header.length + 1) * 8; int headerSeptets = (headerBits + 6) / 7; byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true); // Paste in the header ret[1] = (byte)header.length; System.arraycopy(header, 0, ret, 2, header.length); return ret; } ⑨分析 //GsmAlphabet.java public static byte[] stringToGsm7BitPacked(String data) throws EncodeException { return stringToGsm7BitPacked(data, 0, true); //转⑩分析 } ⑩分析 //GsmAlphabet.java public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset, boolean throwException) throws EncodeException { int dataLen = data.length(); int septetCount = countGsmSeptets(data, throwException) + startingSeptetOffset; // 当传入的字符串data中含有charToGsm, charToGsmExtended中没有的字符时(例如汉字),该函数会抛出异常,这样在调用处⑥会捕获该异常。然后会采用UCS-2方式进行编码。 if (septetCount > 255) { throw new EncodeException("Payload cannot exceed 255 septets"); } int byteCount = ((septetCount * 7) + 7) / 8; byte[] ret = new byte[byteCount + 1]; // Include space for one byte length prefix. for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7; i < dataLen && septets < septetCount; i++, bitOffset += 7) { char c = data.charAt(i); int v = GsmAlphabet.charToGsm(c, throwException); if (v == GSM_EXTENDED_ESCAPE) { v = GsmAlphabet.charToGsmExtended(c); // Lookup the extended char. packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE); bitOffset += 7; septets++; } packSmsChar(ret, bitOffset, v); septets++; } ret[0] = (byte) (septetCount); // Validated by check above. return ret; } I分析: //SMSDispatcher.java protected void sendRawPdu(SmsTracker tracker) { HashMap map = tracker.mData; byte pdu[] = (byte[]) map.get("pdu"); PendingIntent sentIntent = tracker.mSentIntent; 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; } int ss = mPhone.getServiceState().getState(); // if IMS not registered on data and voice is not available... if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) { handleNotInService(ss, tracker); } else { String appName = getAppNameByIntent(sentIntent); if (mCounter.check(appName, SINGLE_PART_SMS)) { sendSms(tracker); // 转II分析 } else { sendMessage(obtainMessage(EVENT_POST_ALERT, tracker)); } } } II分析: //GsmSMSDispatcher.java /** {@inheritDoc} */ @Override 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); if (tracker.mRetryCount > 0 || !isIms()) { // this is retry, use old method mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply); } else { mCm.sendImsGsmSms(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply); } }
发表评论
文章已被作者锁定,不允许评论。
-
资料上传备份
2012-07-02 07:28 0对付对付对付对付 -
Android-sharedUserId数据权限
2012-05-02 10:16 1445Android-sharedUserId数据权限 An ... -
Android Service学习之本地服务
2012-04-18 10:28 863转: Android Service学习之本地服务 htt ... -
match_parent和fill_parent的区别 .
2012-02-18 11:49 1840match_parent和fill_parent的区别 有 ... -
Android中SQLiteOpenHelper类的onUpgrade方法的作用
2012-02-09 11:50 4601Android中SQLiteOpenHelper类的onUpg ... -
Android启动各种系统服务线程
2012-02-09 10:59 1936Android启动各种系统服务 ... -
android
2012-02-08 09:22 0Android数据库内容变化的监听 首先介绍内容监 ... -
在线升级Android应用程序的思路
2012-02-07 11:34 880在线升级Android应用程序的思路 http://www. ... -
Android数据库内容变化的监听
2012-02-07 11:31 6033Android数据库内容变化的监听 首先介绍内容监 ... -
android中的数据库操作
2012-02-07 10:50 1451android中的数据库操作 ... -
SQLiteOpenHelper类与自动升级数据库
2012-02-07 10:31 2283SQLiteOpenHelper类与自动升级数据库 S ... -
SQLite外键的实现
2012-02-07 10:30 1717SQLite外键的实现 SQLite现在的版本还不支持 ... -
Android到处都在使用的回调分析
2011-12-21 15:53 3546Android到处都在使用的回调分析 ... -
android中LayoutInflater的使用
2011-12-21 11:35 1932android中LayoutInflater的使用 ... -
SIM卡满处理流程分析
2011-12-19 15:15 1881SIM卡满处理流程分析 //框架层分析 // SMSD ... -
短信发送状态报告流程分析
2011-12-19 15:07 2392短信发送状态报告流程分析 //应用层分析: //Sms ... -
Android平台 短信接送流程剖析(含编码)
2011-12-16 15:29 3227Android平台 短信接送流程剖析(含编码) ... -
修改语言环境方法
2011-12-16 15:20 1039修改语言环境方法 private void se ... -
Android 应用程序签名
2011-11-27 11:34 1641Android 应用程序签名 转:http://www ... -
理解Android 上的安全性
2011-11-27 11:18 1473理解 Android 上的安全性 ...
相关推荐
对于开发者来说,通过集成这样的SDK,可以大大简化短信发送的流程,无需关心底层通信协议和短信网关的细节,只需按照SDK提供的API进行调用即可。 【标签】“短信发送”进一步明确了这个SDK的核心功能,即它的主要...
以下以QRD平台为例,详细介绍短信发送的过程: 1. **UI接口调用**:首先,上层UI会调用`innerfacelay.java`中的发送接口,即`SendMultipartTextMessageExtra()`。该接口为扩展接口,用于支持双卡项目中的短信发送...
本篇文章将详细解析Android 4.4版本中RIL如何处理短信接收的流程。 1. **RIL接收到短信的初步处理**: 当手机接收到短信时,RIL会通过无线电控制器(Radio Controller,ATC)接收到AT命令`+CMT:`,这表明有新的...
通过分析这个项目源码,开发者可以学习到Android应用的完整生命周期,从设计、编码、调试到发布,以及如何处理特定场景下的用户交互。这对于提升个人Android开发技能和了解实际项目开发流程具有极大的价值。
5. **验证与激活**:设备会发送一个测试短信给网络,以验证短信服务是否已经正确配置和激活。如果一切正常,用户就可以开始使用短信功能了。 在实际应用中,开发者或工程师可能需要对这些过程进行调试和优化,以...
通过对恶意代码的分析,可以掌握恶意代码的恶意操作,例如读取短信、监控短信收发、读取联系人、后台发送邮件等操作。同时,也可以掌握犯罪嫌疑人的手机号码及电子邮箱等个人信息。这些信息对于公安机关打击移动...
4. 短信发送成功后,GSM驱动返回确认信息,RILD向上层反馈发送状态。 五、调试与优化 在开发或维护过程中,调试RIL和GSM驱动至关重要。可以使用adb logcat查看RIL的日志,分析通信过程中的错误。同时,利用模拟器...
2. **短信发送**:用户通过界面输入短信内容,应用程序将内容传至短信协议栈,经过编码后通过无线网络发送到目标手机或SMSC。 3. **短信存储**:在MTK平台上,短信存储采用特定的文件格式,一般为SQLite数据库文件...
短信猫测试工具是一种专门用于测试和管理短信猫设备的软件应用。短信猫,又称为GSM调制解调器,是一种能够通过手机网络发送和...在实际应用中,还需要关注法规要求,避免违反相关的短信发送政策,如垃圾短信的限制。
5. **短信服务**: 发送和接收短信的流程也通过RIL进行,包括短信编码、解码以及通过AT命令进行传输。 6. **位置信息**: RIL获取并上报基站信息,用于手机定位服务。 **4. RIL的扩展与定制** 由于不同的基带处理器...
在iOS平台上,可以利用MFMessageComposeViewController进行短信发送,而MessageUI框架则提供了接收短信的接口。 在“手机短信收发程序”中,关键的类可能是SmsTest,这个类可能包含了发送短信、接收短信、管理短信...
在Android开发中,倒计时(CountDownTimer)是一个常用的功能,尤其在用户验证环节,如短信验证码的发送与接收。这个"Android 倒计时(用于短信验证)"项目是一个实现此类功能的示例代码,允许在实体机或虚拟机上...
通讯功能涵盖电话拨打和短信发送,满足基本通信需求。个人中心则是用户的个性化设置区域,包括显示所有联系人、还原联系人和备份功能。此外,系统界面设计注重用户体验,通过直观的布局和易用的交互方式,使得用户...
"05大话企业级Android开发_MVC讲解及简单短信和拨号器实现.pdf"可能讲解了Model-View-Controller(MVC)架构模式,通过短信发送和拨号器功能的实现来阐述这一设计模式在Android应用中的应用。 通过这些章节的学习,...
智能办公OA系统的开发不是孤立的,需要遵循软件开发的通用流程,包括需求分析、系统设计、编码实现、测试验证、部署上线等。此外,系统设计还需考虑易用性、安全性、可维护性等因素,确保系统的稳定性和用户的良好...
`PduParser`作为Android系统中处理PDU的关键组件,它的源码解析对于理解Android短信服务的底层机制至关重要。通过深入学习`PduParser`,开发者不仅可以掌握短信数据的解析,还能更好地理解和应对与短信相关的各种...
在设计过程中,作者遵循了标准的软件开发流程,包括需求分析、功能确定、编码、调试、程序运行以及优化。论文详细描述了每个阶段的具体步骤和实施方法,体现了作者对Android平台的理解和应用能力。 此外,论文还...
通过这个毕业设计项目,开发者不仅可以掌握Android应用的基本开发流程,还能深入理解电话和短信管理的相关API,以及如何在实际应用中处理隐私和安全问题。同时,这也为撰写相关领域的学术论文提供了实践基础。