Android4.4短信接收拦截,黑白名单(framework修改)

来源:互联网 发布:哪种抢票软件好 编辑:程序博客网 时间:2024/05/18 19:45

Android4.4,关于短信部分的结构做了比较大的变化,之前的版本可以直接编写一个apk通过拦截有序广播的方法来拦截短信,但到了4.4后改成另外一个广播SMS_DELIVER_ACTION,而且只有默认短信应用能接受到该广播,原来的广播也能接受到但不能实现拦截。如果普通的应用想拦截短信就必须设置为默认短信应用。

但如果你想拦截一些短信,而且不想限制用户选择自己喜欢的短信应用。我们只能在framework层的广播发送前拦截住。如果你还想实现动态的黑白名单,那就涉及进程间的通信。拦截某段代码还要涉及到如何保存恢复数据。

进程间的通信有2种,aidl和broadcast。选用改动少的broadcast。如果用aidl的还要加server,非常麻烦。

数据我们要随bradcast发送出去,所以要序列化。这样子白名单就可以正常。


目前网络上关于新结构的分析很少,所有我们要自己分析找到地方,直接在源码里搜索SMS_DELIVER_ACTION找到frameworks/opt/telephony/src/java/com/android/internal/telephony/InboundSmsHandler.java,广播就是从这段代码开始发出。

boolean processMessagePart(InboundSmsTracker tracker) {        //(省略前面一段代码)        Intent intent;        if (destPort == -1) {            intent = new Intent(Intents.SMS_DELIVER_ACTION);            // Direct the intent to only the default SMS app. If we can't find a default SMS app            // then sent it to all broadcast receivers.            ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true);            if (componentName != null) {                // Deliver SMS message only to this receiver                intent.setComponent(componentName);                log("Delivering SMS to: " + componentName.getPackageName() +                        " " + componentName.getClassName());            }        } else {            Uri uri = Uri.parse("sms://localhost:" + destPort);            intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);        }        intent.putExtra("pdus", pdus);        intent.putExtra("format", tracker.getFormat());        dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,                AppOpsManager.OP_RECEIVE_SMS, resultReceiver);}


分析调用这个方法的代码,以及从方法名和传入参数可以知道,InboundSmsTracker这个类是专门用于封装短信的所有相关信息包含短信内容,发送人号码。而且processMessagePart方法除了发送短信广播,还将原来过长的短信在发送时被分开,在这里将合并一起。

接下来就很简单了,注释以上代码,将InboundSmsTracker序列化(因为进程间通信的数据必须序列化),使用广播发送出去。

Intent smsIntent = new Intent("com.sms.SMS_RECEIVED_ACTION");        SmsMessage mSmsMessage = SmsMessage.createFromPdu(tracker.getPdu());        String sender=mSmsMessage.getOriginatingAddress();        smsIntent.putExtra("sender", sender);        smsIntent.putExtra("InboundSmsTracker", tracker);        smsIntent.putExtra("pdus", pdus);        if("CdmaInboundSmsHandler".equals(InboundSmsHandler.this.getName())){            smsIntent.putExtra("action", "com.flyaudio.sms.SMS_CDMA_INTERCEPTER");        }else if("GsmInboundSmsHandler".equals(InboundSmsHandler.this.getName())){            smsIntent.putExtra("action", "com.flyaudio.sms.SMS_GSM_INTERCEPTER");        }        mContext.sendBroadcast(smsIntent);


为了使白名单能正常接收,另外创建一个广播继续执行发送广播的代码

        mBroadcast = new SmsIntercepterBroadcastReceiver();        IntentFilter filter = new IntentFilter();        if("CdmaInboundSmsHandler".equals(name)){            filter.addAction("com.sms.SMS_CDMA_INTERCEPTER");        }else if("GsmInboundSmsHandler".equals(name)){            filter.addAction("com.sms.SMS_GSM_INTERCEPTER");        }        mContext.registerReceiver(mBroadcast, filter);

在构造器里注册广播就可以了,这里有个地方要稍微注意一下。

这个InboundSmsHandler.java本身是个抽象类,从它的子类GsmInboundSmsHandler,CdmaInboundSmsHandler

以及打logcat测试时发现,不同的网络GSM和CDMA会使用不同的类处理。将其区分开,在黑白名单的应用里面判断一下网络类型再发送到适当的处理类。


广播里就是执行发送广播的代码,这里不再重复给出了。

0 0
原创粉丝点击