好贷网好贷款

Android短信编解码

发布时间:2016-12-4 7:50:36 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Android短信编解码",主要涉及到Android短信编解码方面的内容,对于Android短信编解码感兴趣的同学可以参考一下。

Android短信编码在Framework层实现。 对于普通短信,其SmsHeader部分为空。 Gsm: Gsm中,对于长短信,使用了SmsHeader类进行描述。SmsHeader.ConcatRef描述了长短信的refNumber(对于同一个短信,相同,使用SmsDispatcher.getNextConcatenatedRef方法获取一个索引值,将其或上0x00FF),seqNumber(分段序列号,从1开始),msgCount(分段数量)。然后设置isEightBits为假(为了支持不同长度REFERENCE的短信,8位则REFERENCE为8位,否则为16位)。 短信头的编码位于SmsHeader.toByteArray中。 1           写入concatRef 1.1          若为8位REFERENCE,写入ELT_ID_CONCATENATED_8_BIT_REFERENCE(00000000),写入剩下concatRef的字节数(此处设为00000011,表示3个字节),写入refNumber(低8位) 1.2          若为16位,写入ELT_ID_CONCATENATED_16_BIT_REFERENCE(00001000),写入剩下concatRef的字节数(此处设为00000100,表示4个字节),写入refNumber(先写入高8位,再写入低8位) 1.3          写入msgCount(低8位)与seqNumber(低8位) 2           写入PortAddrs 3           写入specialSmsMsgList 4           写入miscEltList 短信内容编码从Gsm的SmsMessage.getSubmitPdu方法开始(com.android.internal.telephony.gsm.SmsMessage) 1           设置MTIBYTE(TP-Message-Type-Indicator,初始为00000001)与UDHI。若SmsHeader不为空,MTIBYTE为01000001,否则为00000001 2           调用Gsm的SmsMessage.getSubmitPduHeader写入基本信息,返回一个ByteArrayOutputStream 1           2           2.1          设置SubmitPdu的服务中心地址 2.2          若需要接收报告,MTIBYTE|=00100000。(TP-Status-Report-Request) 2.3          将MTIBYTE写入输出流(低8位) 2.4          写入一个字节00000000(TP-Message-Reference) 2.5          写入目标号码长度(有效数字个数,如号码12345为5)(低8位) 2.6          写入目标号码(第一个字节为TOA,号码中有加号则为10010001,表示国际号码,否则为10000001未知,TS 24.008 10.5.4.7。后面为BCD码字节数组,每个字节存两个数,不存加号,顺序是反的。如13 24 58表示号码31 42 85。如果号码长度是奇数,最后一个字节的高4位为1111,如13 22 F5表示号码31 22 5) 2.7          写入一个字节00000000(TP-Protocol-Identifier) 3           若编码方式未指定,默认使用7BIT 4           如果使用7BIT编码,调用GsmAlphabet.stringToGsm7BitPacketedWithHeader进行编码,获取编码后的字节数组 4.1          如果没有Header,直接调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=0) 4.1.1     调用GsmAlphabet.countGsmSeptets计算7BIT编码所需的字节数(计算结果要加上头部的7BIT编码所需的字节数) 4.1.2     若超过255个字节,抛出异常 4.1.3     计算使用字节数组保存编码后的7BIT数据所需的字节数(包括Header) 4.1.4     将数据以7BIT编码的方式写入字节数组 4.1.5     在数组的0号位写入7BIT编码所需的字节数(包括Header),返回 4.2          否则,先计算Header的7BIT编码后的长度(包括表示头长度的字节),调用GsmAlphabet.stringToGsm7BitPacket获取编码后的数据字节数组(startingSeptetOffset=Header的长度),在编码后的数据字节数组前面预留出该长度的部分(同4.1.1-4.1.5)。在1号位写入头的长度,其后为Header的内容(Header未进行7BIT编码,但为什么后面的空间是按7BIT空出来?) 4.3          若所需字节数未超过MAX_USER_DATA_SEPTETS,往输出流中写入一个字节00000000(TP-Data-Coding-Scheme,默认编码,未压缩) 5           否则使用UCS-2方式,调用Gsm的SmsMessage.encodeUCS2进行编码,获取编码后的字节数组 5.1          将消息正文转成utf-16be格式 5.2          若包含Header,则创建一个新字节数组用于存放待输出数据,0号位存放Header长度,后面接着Header和转换后的正文。否则,仅输出转换后的消息正文 5.3          创建一个新的字节数组,长度比待输出数据多一。0号位存放待输出数据长度,后面跟着待输出数据 5.4          若所需字节数未超过MAX_USER_DATA_BYTES,往输出流中写入一个字节00001011(TP-Data-Coding-Scheme,Class 3,UCS-2,未压缩) 6           往输出流中写入编码后的字节数组 Gsm短信发送(SMS-SUBMIT)编码格式(不全,具体参见GSM短信标准中9.2.2.2 SMS SUBMIT type)如下图所示:   用户数据区域如下图所示,UDL-用户数据长度,UDHL-用户数据头长度,UDH-用户数据头。若没有Header,则只包括TP-UDL和编码后的短信内容(由TP-UDHI标识)。   对于Gsm,还要在RIL中,将smscPdu与内容pdu进行整合。smscPdu的格式与内容pdu类似,先是一个长度字节(后面号码内容的长度),后面是号码的BCD编码(格式与目标号码相同,也包括TOA)。 Gsm其它类型的PDU可参考标准中的说明,大致结构都差不多。总共包括以下六种。其中,SMS-DELIVER的解码在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_NEW_SMS中调用。 1.         SMS-DELIVER,包含从SC到MS的消息(手机收到的短信)。 2.         SMS-DELIVER-REPORT,包含 a)       失败原因(如果需要的话) b)      对于SMS-DELIVER或SMS-STATUSREPORT的确认 3.         SMS-SUBMIT,包含从MS到SC的消息(从手机发出的短信)。 4.         SMS-SUBMIT-REPORT,包含 a)       失败原因(如果需要的话) b)      对于SMS-SUBMIT或SMS-COMMAND的确认 5.         SMS-STATUS-REPORT,包含从SC到MS的状态报告。 6.         SMS-COMMAND,包含从MS到SC的命令。   Cdma: Cdma的SmsHeader的内容与Gsm几乎没有区别,只是isEightBits为真。 Cdma使用了UserData来辅助构造SubmitPdu,其中的payloadStr存储了不同分段的短信字符串,userDataHeader存储了SmsHeader,msgEncoding存储了编码类型,msgEncodingSet用于指明是否指明编码类型(此处设为真)。 对于普通短信,其userDataHeader为空,msgEncoding与msgEncodingSet均未设置。剩下的编码过程与长短信相同。 Cdma的长短信内容编码也是从Cdma的SmsMessage.getSubmitPdu方法开始,最后转到Cdma的SmsMessage.privateGetSubmitPdu方法进行编码。(com.android.internal.telephony.cdma.SmsMessage) 1           利用目标地址构造一个CdmaSmsAddress 2           构造BearerData对象用于辅助编码,其中消息类型messageType设为BearerData.MESSAGE_TYPE_SUBMIT(0x02),获取了一个MessageId(自增,C.S0015-B,v2.0,4.3.1.5),deliveryAckReq为是否需要接收报告,userAckReq、readAckReq、reportReq均为假,userData为UserData对象。 3           使用BearerData.encode方法对BearerData对象进行编码,获得一个字节数组(3GPP2,C.R1001-F,v1.0,4.5)。其格式为SUBPARAMETER_ID后面带上相应的数据。 3.1          构造一个BitwiseOutputStream进行数据的编码,该输出流能够往其中写入任意位数的数据,而不限于字节的边界 3.2          往输出流中写入SUBPARAM_MESSAGE_IDENTIFIER(0x00)(3GPP2 C.S0015-B,v2.0表4.5-1),8位 3.3          往输出流中写入MessageId(3GPP2 C.S0015-B,4.5.1 Message Identifier) 3.3.1     写入00000011,8位 3.3.2     写入消息类型,4位 3.3.3     写入MessageId的高8位 3.3.4     写入MessageId的低8位 3.3.5     写入是否有用户数据头,1有,0无,1位 3.3.6     跳过3位(留作备用) 3.4          若userData不空,输出(3GPP2 C.S0015-B,4.5.2 User Data) 3.4.1     写入SUBPARAM_USER_DATA(0x01),8位 3.4.2     对UserData的payload使用Bearer.encodeUserDataPayload进行编码 3.4.2.1    若payloadStr为空且msgEncoding不是ENCODING_OCTET(3GPP2 C.R1001-F,v1.0,表9.1-1),设payloadStr为空串 3.4.2.2    若userDataHeader不空,编码并返回 3.4.2.2.1   使用SmsHeader的toByteArray方法将SmsHeader编码为字节数组(具体过程前面介绍了) 3.4.2.2.2   根据编码类型msgEncoding的不同,分别调用不同方法,将SmsHeader数组编码成不同的字节数组。若没指定字符集,默认使用7BIT_ALPHABET。若出现异常,再使用UNICODE16。 3.4.2.2.2.1       如果是ENCODING_GSM_7BIT_ALPHABET,调用BearerData.encode7bitEms,同Gsm的4.2,将编码后的字节数组存入UserData的payload,格式同Gsm的用户数据区域(去掉了第一个字节,即UDL)。将整个用户数据区域的长度存入UserData的numFields。 3.4.2.2.2.2       如果是ENCODING_UNICODE_16,调用BearerData.encode16bitEms,将payloadStr编码为Utf-16be字节数组。将头的长度存入payload的0号字节,后面加上头的字节数组。如果前面的字节数为奇数,还要补上一个字节作为udhPadding以保证字节边界对齐。然后接上编码后的payloadStr。此处的numFields存的是16位单元的长度,即payload字节数除2。 3.4.2.2.2.3       如果是ENCODING_7BIT_ASCII,调用BearerData.encode7bitEmsAscii,过程与ENCODING_GSM_7BIT_ALPHABET相同,只是字符集不同。 3.4.2.3    否则,说明为普通短信,没有Header。 3.4.2.3.1   如果设置了编码字符集,根据编码类型msgEncoding的不同设置相应的payload值。 3.4.2.3.1.1       如果是ENCODING_OCTET。若 UserData.payload为空,payload设为一个空字节(00000000),numFields为0。若UserData.payload不空,numFields为payload的字节数。 3.4.2.3.1.2       如果不是ENCODING_OCTET。若payloadStr为空,设其为空串。否则,根据编码字符集的不同,调用相应方法将payloadStr编码,具体方法同3.4.2.2.2,只是没有UDHL和UDH部分,只含编码后的短信内容。 3.4.2.3.2   若没有设置编码字符集,尝试使用7BIT_ASCII进行编码,若出现异常,再采用UNICODE_16。然后,将numFields设为payloadStr的长度(即字符个数)。 3.4.3     计算后面数据与参数的总字节数paramBytes(如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,多加1字节),以及为了保证数据对齐所需的位数paddingBits 3.4.4     写入paramBytes,8位(SUBPARAM_LEN) 3.4.5     写入UserData的编码方式msgEncoding,5位 3.4.6     如果编码方式为ENCODING_IS91_EXTENDED_PROTOCOL或ENCODING_GSM_DCS,输出UserData的消息类型msgType,8位 3.4.7     写入UserData的numFields,8位 3.4.8     写入UserData的payload 3.4.9     如果需要补全,写入所需的空位paddingBits 3.5          若callbackNumber不空,输出(目前未设置,3GPP2 C.S0015-B,v2,4.5.15) 3.6          若userAckReq,deliveryAckReq,readAckReq,reportReq有一个为真,写入SUBPARAM_REPLY_OPTION(00001010),8位 3.6.1     写入00000001,8位 3.6.2     写入userAckReq,1位 3.6.3     写入deliveryAckReq,1位 3.6.4     写入readAckReq,1位 3.6.5     写入reportReq,1位 3.6.6     写入0000,4位 3.7          若numberOfMessage不为0,输出(Voice Mail中的) 3.7.1     写入SUBPARAM_NUMBER_OF_MESSAGE(3GPP2 C.S0015-B,v2.0,4.5.12),8位 3.7.2     写入00000001,8位 3.7.3     写入BearerData的numberOfMessage,8位 3.8          若validityPeriodRelativeSet为真,输出(目前未设置)——SUBPARAM_VALIDITY_PERIOD_RELATIVE 3.9          若privacyIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIVACY_INDICATOR 3.10       若languageIndicatorSet为真,输出(目前未设置)——SUBPARAM_LANGUAGE_INDICATOR 3.11       若displayModeSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_DISPLAY_MODE 3.12       若priorityIndicatorSet为真,输出(目前未设置)——SUBPARAM_PRIORITY_INDICATOR 3.13       若alertIndicator为真,输出(目前未设置)——SUBPARAM_ALERT_ON_MESSAGE_DELIVERY 3.14       若messageStatusSet为真,输出(目前未设置)——SUBPARAM_MESSAGE_STATUS 4           若有SmsHeader,teleservice为SmsEnvelope.TELESERVICE_WEMT,否则为SmsEnvelope.TELESERVICE_WMT 5           构造一个ByteArrayOutputStream,使用DataOutputStream进行封装 6           往输出流中写入teleservice,Int 7           往输出流中写入0(Service Present),Int 8           往输出流中写入0(Service Category),Int 9           往输出流中写入digitMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte 10        往输出流中写入numberMode(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte 11        往输出流中写入ton,即numberType(TS 23.040 9.1.2.5,TS 24.008表10.5.118,C.S0005-D表2.7.1.3.2.4-2),byte 12        往输出流中写入numberPlan(3GPP2,C.S0015-B,v2.0,3.4.3.3,C.S005-D表2.7.1.3.2.4-3),byte 13        往输出流中写入地址长度numberOfDigits(3GPP2,C.S0015-B,v2.0,3.4.3.3),byte 14        往输出流中写入CdmaSmsAddress中编码后的目标地址,byte[] 15        SubAddress不支持,故输出三个字节00000000 15.1       往输出流中写入0(subaddressType),byte 15.2       往输出流中写入0(subaddress_odd),byte 15.3       往输出流中写入0(subaddress_nbr_of_digits),byte 16        往输出流中写入编码后的BearerData字节数组的长度,byte 17        往输出流中写入编码后的BearerData字节数组,byte[] 对于CDMA短信的解码,在RIL的processUnsolicited的RIL_UNSOL_RESPONSE_CDMA_NEW_SMS中调用,实际代码在com.android.internal.telephony.cdma.SmsMessage.newFromParcel中,解码格式与编码格式相同,只是存的地址变成了发出消息的手机的地址。

上一篇:Jquery UI学习笔记(9)
下一篇:有限自动机

相关文章

相关评论