Android_SMS


1 Android_SMS 源代码接受短信流程
2 短息发送流程
3 PDU 编解码详解
1  Android_SMS 源代码接受短信流程
短信来了之后 framework 会发送广播 “android.provider.Telephony.SMS_RECEIVED”
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­PrivilegedSmsReceiver­­­­­­­­­­­­­­­­­­­­­
此时,PrivilegedSmsReceiver 会接受到该广播,调用父类 SmsReceiver 的 onReceiveWithPrivilege()方法
此方法内获取一个 wake lock 然后启动 SmsReceiverService 服务
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­SmsReceiverService­­­­­­­­­­­­­­­­­­­­­­­­
启动该服务后,会调用 onStartCommand 方法,该方法以之前传来的 Intent 为 Message 的 Obj 发送一条
Message
在 handleMessage 方法里面通过 Intent 判断后执行相应的操作,如
handleSmsSent,handleSmsReceived,
handleBootCompleted,handleServiceStateChanged
接受到短信时当然执行 handleSmsReceived 方法
该方法内通过 Intents.getMessagesFromIntent(intent)方法从 Intent 里面取出 Message[]
然后通过 insertMessage(this, msgs)方法插入短信 insertMessage 里通过调用 storeMessage 方法
storeMessage 方法执行 values.put(Inbox.BODY, sms.getDisplayMessageBody())方法就可以将
短信以 ContentValues 的形式插入数据库。
insertMessage 方法如果插入成功将会返回插入短信的 Uri,如果此 Uri 不为 Null,说明已经插入数据库,
于是
执行 MessagingNotification.updateNewMessageIndicator(this, true);
该方法则会根据短信的状态,发出提示音或震动,也可以根据设置 notification
自此,一条新信息就成功接受了。
 
短信的所有提示都是通过 Notification 来提示的,所以当从设置里面把 Notification 的震动关闭,设为静音
的话,
无所短信设置里面怎么设置提示方式都没用。因为短信提示就是一个普通的 Notification
2 短息发送流程
1、上层开发调用的接口函数:SmsManager.getDefault().sendTextMessage()
函数实现:
 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 = ISms.Stub.asInterface(ServiceManager.getService("isms"));// 在 Binder 注册服
务,通过 iccISms 调用底层接口
            if (iccISms != null) {
                iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);// 调用底层
函数
            }
        } catch (RemoteException ex) {
            // ignore it
        }
    }
 
2、Isms 中处理 sendText
       到 ISms.java 中查找此函数发现有两个,尴尬,为什么会有两个?
有一个是:iccISms.sendText
另一个是:Proxy:sendText
明白了,一看就知道我们要的是第一个。但是当我们查看第一个函数的时候发现没有实现。。。为什么呢?
这时候就要说到一个机制:Binder,这里就是它在捣鬼。这里给我们提供的接口就是 Binder 客户端的接口,
具体实现是在 Binder 的服务。
 
3、寻找 Binder 服务中哪里实现的 sendText
sendText 是在 SMSDispatcher.java 文件中,但是他的实现是在 GsmSMSDispatcher.java 或者
CdmaSMSDispatcher.java 文件中。
protected void sendText(String destAddr, String scAddr, String text,
            PendingIntent sentIntent, PendingIntent deliveryIntent)
{
        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                scAddr, destAddr, text, (deliveryIntent != null));
        sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
    }
 
4、sendRawPdu 这个函数又返回到 SMSDispatcher.java 文件中,
protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
            PendingIntent deliveryIntent)
{
        if (pdu == null)
{
            if (sentIntent != null)
{
                try
{
                    sentIntent.send(RESULT_ERROR_NULL_PDU);
                } catch (CanceledException ex) {}
            }
        return;
}
HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("smsc", smsc);
        map.put("pdu", pdu);
 
        SmsTracker tracker = new SmsTracker(map, sentIntent,
                deliveryIntent);
        int ss = mPhone.getServiceState().getState();
 
        if (ss != ServiceState.STATE_IN_SERVICE) {
            handleNotInService(ss, tracker);
        } else {
            String appName = getAppNameByIntent(sentIntent);
            if (mCounter.check(appName, SINGLE_PART_SMS)) {
                sendSms(tracker);
            } else {
                sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
            }
        }
    }
 
5、sendSms 看到这个函数感觉离真正干活的地方不远了。此函数又跑到 GsmSMSDispatcher.java 或者
CdmaSMSDispatcher.java 文件中了,说明两个网的实现方式还有有一定差异的。
protected void sendSms(SmsTracker tracker) {
        HashMap map = tracker.mData;
 
        byte smsc[] = (byte[]) map.get("smsc");
        byte pdu[] = (byte[]) map.get("pdu");
 
        Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
        mCm.sendSMS(IccUtils.bytesToHexString(smsc),
                IccUtils.bytesToHexString(pdu), reply);
    }
 
有必要说一下 mCm 这个成员变量,比变量声明为:CommandsInterface,(怎么跑出来这么个东西?)这
个是 Ril 层的接口层,里边提供了 Ril 实现的功能。
看到这里我们就可以跨过 Ril 机制了,直接找我们想要的功能实现。CommandsInterface.java 只是提供接口,
具体实现在 Ril.java 中。
 
6、sendSMS 此函数在 Ril.java 中,看看怎么实现的。(这是什么东西,没看明白)
public void
    sendSMS (String smscPDU, String pdu, Message result) {
        RILRequest rr
                = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);
 
        rr.mp.writeInt(2);
        rr.mp.writeString(smscPDU);
        rr.mp.writeString(pdu);
 
        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
 
        send(rr);
    }
 
Ril.java 中的实现方式基本都是一个样子,就是 send(rr),这其实是 Ril 的机制,Ril.java 其实是 Rild 的一
个代理,他负责给 Rild 发消息,通知他去做具体的操作。
 
7、看看谁处理了 RIL_REQUEST_SEND_SMS 这个消息就知道谁在干活了。
onRequest
此函数就是处理消息的函数。对应 case RIL_REQUEST_SEND_SMS 会调用相应的函数
requestSendSMS(data, datalen, t);
 
8、再往下看就是如何将请求编辑成 AT 命令发送给 cp 层了,这样就是 Ril 的真正意义。没必要再写了。
参考下列标准:
TS 23.040  着重介绍短信发送中对字符集的控制部分
TS 23.038  SMS 编码解码相关
TS 24.011   SMS 同 SMSC 交互
3
 PDU 编解码详解
简单介绍
SMS 是由 Etsi 所制定的一个规范(GSM 03.40 和 GSM 03.38)。当使用 7­bits 编码的时候 ,它可以发送最多 160 个
字符,8­bit 编码(最多 140 个字符)通常无法直接通过手机显示;通常被用来作为数据消息。16­bit 信息(最多 70
个字符)被用来显示 Unicode(UCS2)文本信息,可以被大多数的手机所显示。一个以 class 0 开头的 16­bit 的文本信
息将在某些手机上作为 Flash SMS 显示(闪烁的 SMS 和警告 SMS)。
有两种方式来发送和接收 SMS 信息:使用文本模式或者使用 PDU(protocol description unit) 模式。文本模式(可能
某些手机不支持)实际上也是一种 PDU 编码的一种表现形式。在显示 SMS 信息,可能使用不同的字符集和不同的
编码方式。
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
接收
PDU 串不仅仅包含了消息,而且还有很多发送者的元信息,他的 SMS 服务中心,时间标志等等。这些都是以 8 位
字节的 16 进制数,或者半 8 位字节的十进制数。以下的字符书我从 Nokia 6110 收到的信息,当从 www.mtn.co.za 发
送的串是"hellohello"的时候。
07 917238010010F5 040BC87238880900F100009930925161958003C16010
这个八位串包含了三个部分:第一个 8 位表示 SMSC 信息的长度("07"),SMSC 的信息 ("917238010010F5"),和
SMS_DELIVER 部分(GSM 03.40 中指定)。
8 位描述
07 SMSC 信息的长度。(在这个例子里是 7 个八位)
91 SMSC 的地址类型 (91 意味着国际格式的电话号码)
72 38 01 00 10 F5 服务中心号码(半八位的十进制数)电话号码是一个奇数(11),因此加入 F 来保证 8 位。这个服
务中心的号码是"+27381000015"
04 SMS_DELIVER 的第一个 8 位。
0B 地址长度。发送号码的长度(0B hex = 11 dec)
C8 发送号码的地址类型
72 38 88 09 00 F1 发送号码(半八位的十进制数),有一个 F 结尾。
00 TP­PID.协议标识
00 TP­DCS 编码方式
99 30 92 51 61 95 80 TP­SCTS.时间邮戳(半 8 位)
0A TP­UDL.用户数据长度,信息的长度。TP­DCS 域表明是 7­bit 格式的数据。因此长度在这里是一个 10 个 7­
bits。如果 TP­DCS 被设置成 8­bit 或者 Unicode,那么长度就应该是 9 个八位长度。
E8329BFD4697D9EC37 TP­UD. 7­bit 编码的信息。
所有的 8 位都是 16 进制编码,除了服务中心号码,发送号码和时间邮戳;他们都是十进制的半 8 位编码。在 PDU
串的结尾部分包含了一些 16 进制的 8­bits 数据,但他们实际 7­bits 数据。
十进制的半 8 位只需要将高位和地位交换就可以得到实际的数值。例如:"72 38 88 09 00 F1" 到 "27 83 88 90 00
1F"。因为电话号码是一个奇数,没有办法组成 8 位编码,所以使用 F 来补齐。在解析时间邮戳的时候("99 03 29
15 16 59 08"),前 6 位代表日期,后 6 位代表时间,最后 2 位是时区。
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
7Bit 编码
"hellohello"包含了 10 个字符,他们必须一个个将用 7­bits 来代表。
h e l l o h e l l o
104 101 108 108 111 104 101 108 108 111
1101000 1100101 1101100 1101100 1101111 1101000 1100101 1101100 1101100 1101111
1101000
110010 1
11011 00
1101 100
110 1111
11 01000
1 100101
1101100
1101100
110111 1
首先将字符转换为 7 位的二进制,然后,将后面字符的位调用到前面,补齐前面的差别。例如:h 翻译成
1101000,e 翻译成 1100101,显然 h 的二进制编码不足八位,那么就将 e 的最后一位补足到 h 的前面。那么就成了
11101000(E8)。剩余地编码看下表:
1 1101000
00 110010
100 11011
1111 1101
01000 110
100101 11
1101100 1
1 1101100
110111
E8 32 9B FD 46 97 D9
EC 37
那么就变成了 9 个八进制数 E8 32 9B FD 46 97 D9 EC 37。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值