Android中短信接收拦截比较好实现,如果要实现短信发送拦截就要修改framework的代码。
实现也不难,同时也介绍framework开发的一般步骤。
准备阶段
关于短信发送流程的详细分析网上有很多,这里简单提一下
应用层SmsManger这个类的sendTextMessage( )或sendMultipartText( )发送
通过aidl调用系统服务ISms发送短信。发送的拦截主要在系统服务里实现。
源码的工具可以参考下面博客
http://blog.csdn.net/thinkandchange/article/details/7677366
源码修改
找到framework/base/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
这个类就是ISms的aidl的实现,找到发送的两个方法然后将其最后一行替换为自己的方法:
public void sendText(String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority) {
mPhone.getContext().enforceCallingPermission(
"android.permission.SEND_SMS",
"Sending SMS message");
if (Log.isLoggable("SMS", Log.VERBOSE)) {
log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
" text='"+ text + "' sentIntent=" +
sentIntent + " deliveryIntent=" + deliveryIntent);
}
sendTextBoardcast(mContext, destAddr, scAddr, text, sentIntent, deliveryIntent,priority);
//mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,priority);
}
public void sendMultipartText(String destAddr, String scAddr, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
mContext.enforceCallingPermission(
"android.permission.SEND_SMS",
"Sending SMS message");
if (Log.isLoggable("SMS", Log.VERBOSE)) {
int i = 0;
for (String part : parts) {
log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr +
", part[" + (i++) + "]=" + part);
}
}
sendMultipartTextBoardcast(mContext, destAddr, scAddr,(ArrayList<String>) parts,
(ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents);
/* mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,
(ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents);*/
}
将其发送广播出去,由其他应用决定是否拦截,为了后面还能正常发送,将所有参数发出去
/**
* 发送广播,通知有进程发送短信
* @param context
*/
private void sendTextBoardcast(Context context,String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority) {
Intent intent = new Intent("com.android.sms.REPORT_SMS");
intent.putExtra("method", "sendText");
intent.putExtra("destAddr", destAddr);
intent.putExtra("scAddr",scAddr);
intent.putExtra("text",text);
intent.putExtra("sentIntent",sentIntent);
intent.putExtra("deliveryIntent",deliveryIntent);
intent.putExtra("priority",priority);
int pid = Binder.getCallingPid();
if ( pid != android.os.Process.myPid() ){
String processName = getProcessName(context,pid);
String packageName = getPackageName(context,processName);
if(processName != null){
intent.putExtra("packageName", packageName);
} else {
intent.putExtra("packageName", "");
}
} else {
intent.putExtra("packageName", "");
}
context.sendBroadcast(intent);
}
/**
* 发送广播,通知有进程发送多段短信
* @param context
*/
private void sendMultipartTextBoardcast(Context context,String destAddr, String scAddr, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
Intent intent = new Intent("com.android.sms.REPORT_SMS");
intent.putExtra("method", "sendMultipartText");
intent.putExtra("destAddr", destAddr);
intent.putExtra("scAddr",scAddr);
intent.putStringArrayListExtra("parts",parts);
intent.putParcelableArrayListExtra("sentIntents",sentIntents);
intent.putParcelableArrayListExtra("deliveryIntents",deliveryIntents);
int pid = Binder.getCallingPid();
if ( pid != android.os.Process.myPid() ){
String processName = getProcessName(context,pid);
String packageName = getPackageName(context,processName);
if(processName != null){
intent.putExtra("packageName", packageName);
} else {
intent.putExtra("packageName", "");
}
} else {
intent.putExtra("packageName", "");
}
context.sendBroadcast(intent);
}
如果要知道是有哪个应用发送的,可以根据pid进程号来查找
/**
* 获取进程名
* @param context
* @param id Process ID
* @return
*/
public String getProcessName(Context context,int id) {
int pid = id;
ActivityManager mActivityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return null;
}
/**
* 获取包名
* @param context
* @param processName 进程名
* @return
*/
public String getPackageName(Context context,String processName){
if(processName == null || context == null) {
return null;
}
PackageManager packageManager = context.getPackageManager();
List<ApplicationInfo> infos = packageManager.getInstalledApplications(0);
for (ApplicationInfo info : infos) {
if ( processName.equals(info.processName) ) {
return info.packageName;
} else if( processName.equals(info.packageName) ) {
return info.packageName;
}
}
return null;
}
既然已经拦截了发送,我们要提供另外的正常发送方法,就是之前注释的方法
public void mySendText(String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority){
mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,priority);
}
public void mySendMultipartText(String destAddr, String scAddr, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents){
mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts,
(ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents);
}
要使能被调用到,要在对应的aidl里添加接口
找到framework/base/telephony/java/com/android/internal/telephony/ISms.aidl
void mySendText(in String destAddr, in String scAddr, in String text,
in PendingIntent sentIntent, in PendingIntent deliveryIntent, in int priority);
void mySendMultipartText(in String destinationAddress, in String scAddress,
in List<String> parts, in List<PendingIntent> sentIntents,
in List<PendingIntent> deliveryIntents);
最后在SmsManger里增加自己的方法
framework/base/telephony/java/android/telephony/SmsManager.java
public void mySendText(String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent, int priority){
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
if (iccISms != null) {
iccISms.flySendText(destAddr, scAddr, text, sentIntent, deliveryIntent,priority);
}
} catch (RemoteException ex) {
// ignore it
}
}
public void mySendMultipartText(String destAddr, String scAddr, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents){
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
if (iccISms != null) {
iccISms.flySendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents);
}
} catch (RemoteException ex) {
// ignore it
}
}
编译测试
之前先编译一遍源码
进入framework/base执行命令mm
根据打印出来的信息找到out/target/product/(芯片平台)/system/framework/framework.jar
将其adb push framework.jar system/framework
重启adb reboot
编写应用程序
广播接收器
<span style="color:#330000;"><receiver android:name="com.interceptor.SmsReport" >
<intent-filter>
<action android:name="com.android.sms.REPORT_SMS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver></span>
public class SmsReport extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String packageName = intent.getStringExtra("packageName");
if(MApplication.mApp.checkSendMessages(packageName) == false){
Toast.makeText(MApplication.mApp, packageName+"不允许发送短信", Toast.LENGTH_LONG).show();
return;
}
String methodName = intent.getStringExtra("method");
SmsManager smsManager = SmsManager.getDefault();
if(methodName == null || "".equals(methodName)){
return;
}else if(methodName.equals("sendText")){
String destAddr = intent.getStringExtra("destAddr");
String scAddr = intent.getStringExtra("scAddr");
String text = intent.getStringExtra("text");
PendingIntent sentIntent = intent.getParcelableExtra("sentIntent");
PendingIntent deliveryIntent = intent.getParcelableExtra("deliveryIntent");
int priority = intent.getIntExtra("priority", -1);
smsManager.mySendText(destAddr, scAddr, text, sentIntent, deliveryIntent,priority);
}else if(methodName.equals("sendMultipartText")){
String destAddr = intent.getStringExtra("destAddr");
String scAddr = intent.getStringExtra("scAddr");
ArrayList<String> parts = intent.getStringArrayListExtra("parts");
ArrayList<PendingIntent> sentIntents = intent.getParcelableArrayListExtra("sentIntents");
ArrayList<PendingIntent> deliveryIntents = intent.getParcelableArrayListExtra("deliveryIntents");
smsManager.mySendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents);
}
}
}
要使应用程序编译通过,必须导入out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar包并且必须编译顺序比Android的jar包靠前