`

Android平台 短信发送流程剖析(含编码)

 
阅读更多

Android平台 短信发送流程剖析(含编码)

本文对Android平台短信发送流程进行了走读和剖析,特别是编码部分,今天将流程整理出来,以便平时参考,也希望对大家有用!!!

先上图,下面2个图是用PPT画的,这里截图附上来:

                                           流程图1:


 

 

 

 

                                                            流程图2:

  

发送流程编码解析:

从上图中的GsmSMSDispatchersendText开始分析

 

//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);
        }
    }

 

 

  • 大小: 38.4 KB
  • 大小: 106.5 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    短信发送sdk包

    对于开发者来说,通过集成这样的SDK,可以大大简化短信发送的流程,无需关心底层通信协议和短信网关的细节,只需按照SDK提供的API进行调用即可。 【标签】“短信发送”进一步明确了这个SDK的核心功能,即它的主要...

    Framework层短信收发流程介绍

    以下以QRD平台为例,详细介绍短信发送的过程: 1. **UI接口调用**:首先,上层UI会调用`innerfacelay.java`中的发送接口,即`SendMultipartTextMessageExtra()`。该接口为扩展接口,用于支持双卡项目中的短信发送...

    详解Android4.4 RIL短信接收流程分析

    本篇文章将详细解析Android 4.4版本中RIL如何处理短信接收的流程。 1. **RIL接收到短信的初步处理**: 当手机接收到短信时,RIL会通过无线电控制器(Radio Controller,ATC)接收到AT命令`+CMT:`,这表明有新的...

    Android 节日短信回复助手源码.zip

    通过分析这个项目源码,开发者可以学习到Android应用的完整生命周期,从设计、编码、调试到发布,以及如何处理特定场景下的用户交互。这对于提升个人Android开发技能和了解实际项目开发流程具有极大的价值。

    MTK 电信 短信 自注册

    5. **验证与激活**:设备会发送一个测试短信给网络,以验证短信服务是否已经正确配置和激活。如果一切正常,用户就可以开始使用短信功能了。 在实际应用中,开发者或工程师可能需要对这些过程进行调试和优化,以...

    Android恶意代码——木马APK分析.pdf

    通过对恶意代码的分析,可以掌握恶意代码的恶意操作,例如读取短信、监控短信收发、读取联系人、后台发送邮件等操作。同时,也可以掌握犯罪嫌疑人的手机号码及电子邮箱等个人信息。这些信息对于公安机关打击移动...

    Android RIL GSM底层驱动 实现打电话发短信功能详解

    4. 短信发送成功后,GSM驱动返回确认信息,RILD向上层反馈发送状态。 五、调试与优化 在开发或维护过程中,调试RIL和GSM驱动至关重要。可以使用adb logcat查看RIL的日志,分析通信过程中的错误。同时,利用模拟器...

    MTK之短信

    2. **短信发送**:用户通过界面输入短信内容,应用程序将内容传至短信协议栈,经过编码后通过无线网络发送到目标手机或SMSC。 3. **短信存储**:在MTK平台上,短信存储采用特定的文件格式,一般为SQLite数据库文件...

    短信猫测试工具

    短信猫测试工具是一种专门用于测试和管理短信猫设备的软件应用。短信猫,又称为GSM调制解调器,是一种能够通过手机网络发送和...在实际应用中,还需要关注法规要求,避免违反相关的短信发送政策,如垃圾短信的限制。

    Android 源码 RIL层

    5. **短信服务**: 发送和接收短信的流程也通过RIL进行,包括短信编码、解码以及通过AT命令进行传输。 6. **位置信息**: RIL获取并上报基站信息,用于手机定位服务。 **4. RIL的扩展与定制** 由于不同的基带处理器...

    手机短信收发程序

    在iOS平台上,可以利用MFMessageComposeViewController进行短信发送,而MessageUI框架则提供了接收短信的接口。 在“手机短信收发程序”中,关键的类可能是SmsTest,这个类可能包含了发送短信、接收短信、管理短信...

    Android 倒计时(用于短信验证).zip

    在Android开发中,倒计时(CountDownTimer)是一个常用的功能,尤其在用户验证环节,如短信验证码的发送与接收。这个"Android 倒计时(用于短信验证)"项目是一个实现此类功能的示例代码,允许在实体机或虚拟机上...

    安卓课程设计-手机通讯录系统全解.doc

    通讯功能涵盖电话拨打和短信发送,满足基本通信需求。个人中心则是用户的个性化设置区域,包括显示所有联系人、还原联系人和备份功能。此外,系统界面设计注重用户体验,通过直观的布局和易用的交互方式,使得用户...

    大话企业级Android 开发

    "05大话企业级Android开发_MVC讲解及简单短信和拨号器实现.pdf"可能讲解了Model-View-Controller(MVC)架构模式,通过短信发送和拨号器功能的实现来阐述这一设计模式在Android应用中的应用。 通过这些章节的学习,...

    基于Android的学校智能办公OA设计.pdf

    智能办公OA系统的开发不是孤立的,需要遵循软件开发的通用流程,包括需求分析、系统设计、编码实现、测试验证、部署上线等。此外,系统设计还需考虑易用性、安全性、可维护性等因素,确保系统的稳定性和用户的良好...

    PduParser.rar_android

    `PduParser`作为Android系统中处理PDU的关键组件,它的源码解析对于理解Android短信服务的底层机制至关重要。通过深入学习`PduParser`,开发者不仅可以掌握短信数据的解析,还能更好地理解和应对与短信相关的各种...

    基于android手机电话薄的设计与实现毕业论文设计说明.doc

    在设计过程中,作者遵循了标准的软件开发流程,包括需求分析、功能确定、编码、调试、程序运行以及优化。论文详细描述了每个阶段的具体步骤和实施方法,体现了作者对Android平台的理解和应用能力。 此外,论文还...

    Android应用源码之电话、短信黑白名单拦截、电话录音-IT计算机-毕业设计.zip

    通过这个毕业设计项目,开发者不仅可以掌握Android应用的基本开发流程,还能深入理解电话和短信管理的相关API,以及如何在实际应用中处理隐私和安全问题。同时,这也为撰写相关领域的学术论文提供了实践基础。

Global site tag (gtag.js) - Google Analytics