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 1409Android-sharedUserId数据权限 An ... -
Android Service学习之本地服务
2012-04-18 10:28 800转: Android Service学习之本地服务 htt ... -
match_parent和fill_parent的区别 .
2012-02-18 11:49 1783match_parent和fill_parent的区别 有 ... -
Android中SQLiteOpenHelper类的onUpgrade方法的作用
2012-02-09 11:50 4561Android中SQLiteOpenHelper类的onUpg ... -
Android启动各种系统服务线程
2012-02-09 10:59 1898Android启动各种系统服务 ... -
android
2012-02-08 09:22 0Android数据库内容变化的监听 首先介绍内容监 ... -
在线升级Android应用程序的思路
2012-02-07 11:34 822在线升级Android应用程序的思路 http://www. ... -
Android数据库内容变化的监听
2012-02-07 11:31 5992Android数据库内容变化的监听 首先介绍内容监 ... -
android中的数据库操作
2012-02-07 10:50 1410android中的数据库操作 ... -
SQLiteOpenHelper类与自动升级数据库
2012-02-07 10:31 2240SQLiteOpenHelper类与自动升级数据库 S ... -
SQLite外键的实现
2012-02-07 10:30 1658SQLite外键的实现 SQLite现在的版本还不支持 ... -
Android到处都在使用的回调分析
2011-12-21 15:53 3503Android到处都在使用的回调分析 ... -
android中LayoutInflater的使用
2011-12-21 11:35 1899android中LayoutInflater的使用 ... -
SIM卡满处理流程分析
2011-12-19 15:15 1843SIM卡满处理流程分析 //框架层分析 // SMSD ... -
短信发送状态报告流程分析
2011-12-19 15:07 2351短信发送状态报告流程分析 //应用层分析: //Sms ... -
Android平台 短信接送流程剖析(含编码)
2011-12-16 15:29 3196Android平台 短信接送流程剖析(含编码) ... -
修改语言环境方法
2011-12-16 15:20 995修改语言环境方法 private void se ... -
Android 应用程序签名
2011-11-27 11:34 1603Android 应用程序签名 转:http://www ... -
理解Android 上的安全性
2011-11-27 11:18 1427理解 Android 上的安全性 ...
相关推荐
短信发送流程图形剖析(含编码)Android平台整理.pdf
实验项目名称 通讯录 实验目的与要求: 目的:练习掌握 Android 软件开发基本编程技术、Android 系统 SQLite 数据库的使用、通话、短信的使用等,设计制作一 Android 通讯录软件。 要求: (1)每位同学独立设计...
本书以Android应用程序的开发为主题,并结合真实的案例向读者详细介绍了Android的基本组件的使用及应用程序开发的整个流程。本书的讲述由浅入深,实例全面并典型,几乎囊括了所有和Android应用相关的项目。全书分为...
7 3.1.5 还原与备份功能 7 3.2 系统界面设计 8 4 系统编码实现 14 前 言 随着移动通信与Internet向移动终端的普及,网络和用户对移动终端的要求越来越高 ,而Symbian,Windows Mobile,PalmOS等手机平台过于封闭,不...
他还是一位资深的Java软件开发工程师和Android/iOS移动应用开发工程师,活跃于CocoaChina、开源中国、CSDN等社区,CSDN博客专家,在CSDN博客撰写了系列微信公众平台二次开发的教程,深受欢迎并被广泛传播,也因此...
此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...
Java发送短信包 LemonSMS LemonSMS 这个Java库可以让开发者在应用程序中集成使用GSM调制解调器或兼容电话来发送SMS消息。 远程桌面 Java Remote Desktop.tar Java Remote Desktop 是一个Java 的远程桌面软件,支持...