这个周末又没有吊事,在家研究了如何经过进程的注入技术修改广播接收器的优先级,关于这个应用场景是不少的,并且也很重要,因此就很急的去fixed了。html
Android中的四大组件中有一个广播:Broadcastjava
关于它的相关知识能够转战:http://blog.csdn.net/jiangwei0910410003/article/details/19150705android
咱们这里就不作太多解释了,如今来看一下问题:shell
这篇文章和我以前介绍一篇文章: Andrdoid中对应用程序的行为拦截实现方式之----从Java层进行拦截api
内容和知识点很是类似,若是想看明白这篇文章的话,那么必须先看懂上面的一篇文章,不然很难理解的。安全
一、进程注入技术app
二、获取系统中全部应用的IntentFilteride
如今不少安全应用都会注册这个广播(360手机卫士、清理大师等),广播中能够设置优先级的。同时动态注册的广播的优先级比静态注册的广播的优先级高。测试
经过上面的知识咱们能够这么作:spa
一、将本身的广播接收器注册的优先级设置最高,通常是用最大值:Integer.MAX_VALUE
二、进行动态注册广播(那么咱们可能须要开启一个后台服务了,否则应用退出以后,这个接收器就没有了,是接收不到广播的)
经过上面的两步咱们能够发现,咱们本身的广播接收器的优先级应该比较高了。可以最早接收到广播了。
问题来了,你的应用这么作,那么其余应用也会这么作的,并且这种作法的成本和代价不是很高。很容易实现的。
好吧。那么咱们如今该怎么办呢?
这时候咱们就须要经过Android中的进程注入技术来进行拦截操做,而后去修改其余应用的广播接收器的优先级了
下面来看一下具体实现:
首先关于进程的注入技术这里就不作介绍了,若是有疑问的同窗能够转战:
http://blog.csdn.net/jiangwei0910410003/article/details/40949475
注:还有一个问题,我今天介绍的内容其实和这篇文章很是类似,功能差很少。因此强烈建议你们最好认真的把这篇文章从头至尾仔细的读一遍,同时最后动手去实现如下,那么在来看这篇文章就简单多了。否则是很费劲的。
这里咱们须要注入到系统进程:system_server
而后在Java层自定义一个Binder对象,在经过底层去替换系统的Binder。而后咱们须要作的工做就是在Java中的自定义的这个Binder对象的onTransact方法中进行操做
很少说了,先来看代码:
DemoInject3项目:
EntryClass.java
package com.demo.inject3; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; /** * * @author boyliang * */ public final class EntryClass { private static final class ProxyActivityManagerServcie extends Binder { private static final String CLASS_NAME = "android.app.IActivityManager"; private static final int s_broadcastIntent_code; private SmsReceiverResorter mResorter; static { if (ReflecterHelper.setClass(CLASS_NAME)) { s_broadcastIntent_code = ReflecterHelper.getStaticIntValue("BROADCAST_INTENT_TRANSACTION", -1); } else { s_broadcastIntent_code = -1; } } private IBinder mBinder; public ProxyActivityManagerServcie(IBinder binder) { Logger.init(); mBinder = binder; mResorter = new SmsReceiverResorter(binder); } @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == s_broadcastIntent_code) { Log.i("TTT", "broadcastintent:"+s_broadcastIntent_code); mResorter.updatePriority("com.demo.sms"); } return mBinder.transact(code, data, reply, flags); } } public static Object[] invoke(int i) { IBinder activity_proxy = null; try { activity_proxy = new ProxyActivityManagerServcie(ServiceManager.getService("activity")); Log.i("TTT", ">>>>>>>>>>>>>I am in, I am a bad boy 3!!!!<<<<<<<<<<<<<<"); } catch (Exception e) { e.printStackTrace(); } return new Object[] { "activity", activity_proxy }; } }
核心的方法是onTransact:
这里须要判断一下code值,咱们只对广播的code作操做。关于这个code的值,在上面的提到的那篇文章中有详细介绍。
看到调用了mResorter.updatePriority方法。那么咱们在来看一下mResorter变量的类型
SmsReceiverResorter.java
package com.demo.inject3; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; import android.util.Log; final class SmsReceiverResorter { private static final String key = Intent.ACTION_PACKAGE_ADDED; private final String TAG = "TTT"; private HashMap<String, IntentFilter[]> mActionToFilter; private Field mPackageNameField; @SuppressWarnings("unchecked") public SmsReceiverResorter(IBinder am) { Class<?> claxx = am.getClass(); try { Field field = claxx.getDeclaredField("mReceiverResolver"); field.setAccessible(true); Object mReceiverResolver = field.get(am); Log.i("TTT", "Binder:"+mReceiverResolver.getClass().getName()); claxx = mReceiverResolver.getClass(); field = claxx.getSuperclass().getDeclaredField("mActionToFilter"); field.setAccessible(true); mActionToFilter = (HashMap<String, IntentFilter[]>) field.get(mReceiverResolver); Log.i("TTT", "mActionToFilter:"+mActionToFilter); if(mActionToFilter == null){ return; } Log.i("TTT", "size:"+mActionToFilter.size()); Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key)); IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key); Log.i("TTT", "filters:"+filters_tmp); if (filters_tmp != null) { Log.i("TTT", "length:"+filters_tmp.length); for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg); } } Set<Entry<String, IntentFilter[]>> sets = mActionToFilter.entrySet(); Iterator<Entry<String, IntentFilter[]>> iterators = sets.iterator(); while(iterators.hasNext()){ Log.i("TTT", "key:"+iterators.next().getKey()); } } catch (Exception e) { Log.e(TAG, e.toString()); } } public void updatePriority(String target_pkg) { if (mActionToFilter != null) { IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key); Log.i("TTT", "filters:"+filters_tmp); if (filters_tmp != null) { Log.i("TTT", "add package..."); IntentFilter[] newFilters = new IntentFilter[1]; for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority()); //现将全部的应用的广播接收器的优先级设置最低 filters_tmp[i].setPriority(Integer.MIN_VALUE); if(pkg == null){ continue; } if (target_pkg.equals(pkg)) { Log.i("TTT", "find pkg:"+pkg); //把咱们本身的广播接收器的优先级设置最高 filters_tmp[i].setPriority(Integer.MAX_VALUE); //newFilters[0] = filters_tmp[i]; break; } } /*mActionToFilter.put(key, newFilters); IntentFilter[] filterss = mActionToFilter.get(key); for(int i=0;i<filterss.length;i++){ Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i])); }*/ } } } private String getPackageName(IntentFilter filter) { if (mPackageNameField == null && filter != null) { Class<?> claxx = filter.getClass(); try { mPackageNameField = claxx.getDeclaredField("packageName"); mPackageNameField.setAccessible(true); } catch (Exception e) { Log.e(TAG, e.toString()); } } String result = null; if (filter != null) { try { result = (String) mPackageNameField.get(filter); } catch (Exception e) { Log.e(TAG, e.toString()); } } return result; } }
这里面有两个重要的方法:
一、构造方法
public SmsReceiverResorter(IBinder am) { Class<?> claxx = am.getClass(); try { Field field = claxx.getDeclaredField("mReceiverResolver"); field.setAccessible(true); Object mReceiverResolver = field.get(am); Log.i("TTT", "Binder:"+mReceiverResolver.getClass().getName()); claxx = mReceiverResolver.getClass(); field = claxx.getSuperclass().getDeclaredField("mActionToFilter"); field.setAccessible(true); mActionToFilter = (HashMap<String, IntentFilter[]>) field.get(mReceiverResolver); Log.i("TTT", "mActionToFilter:"+mActionToFilter); if(mActionToFilter == null){ return; } Log.i("TTT", "size:"+mActionToFilter.size()); Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key)); IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key); Log.i("TTT", "filters:"+filters_tmp); if (filters_tmp != null) { Log.i("TTT", "length:"+filters_tmp.length); for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg); } } Set<Entry<String, IntentFilter[]>> sets = mActionToFilter.entrySet(); Iterator<Entry<String, IntentFilter[]>> iterators = sets.iterator(); while(iterators.hasNext()){ Log.i("TTT", "key:"+iterators.next().getKey()); } } catch (Exception e) { Log.e(TAG, e.toString()); } }
在构造方法中咱们主要作的工做是获取mActionToFilter的值,它的定义:
private HashMap<String, IntentFilter[]> mActionToFilter;这个值是干什么的呢?它是全部应用的IntentFilter的值,关于IntentFilter的做用能够自行百度,这里就不解释了。
这里的key是action的名称。由于咱们在动态注册广播的时候,须要传递IntentFilter的。
因此,咱们拿到这个值以后,就能够获取全部应用注册广播的信息了
这个变量是非公开的,咱们没法经过api去获取。那么不用说用反射去搞定它:
这个变量的定义是在 Android源码目录\services\java\com\android\server\IntentResolver.java
/** * All filters that have been registered. */ private final HashSet<F> mFilters = new HashSet<F>(); /** * All of the MIME types that have been registered, such as "image/jpeg", * "image/*", or "{@literal *}/*". */ private final ArrayMap<String, F[]> mTypeToFilter = new ArrayMap<String, F[]>(); /** * The base names of all of all fully qualified MIME types that have been * registered, such as "image" or "*". Wild card MIME types such as * "image/*" will not be here. */ private final ArrayMap<String, F[]> mBaseTypeToFilter = new ArrayMap<String, F[]>(); /** * The base names of all of the MIME types with a sub-type wildcard that * have been registered. For example, a filter with "image/*" will be * included here as "image" but one with "image/jpeg" will not be * included here. This also includes the "*" for the "{@literal *}/*" * MIME type. */ private final ArrayMap<String, F[]> mWildTypeToFilter = new ArrayMap<String, F[]>(); /** * All of the URI schemes (such as http) that have been registered. */ private final ArrayMap<String, F[]> mSchemeToFilter = new ArrayMap<String, F[]>(); /** * All of the actions that have been registered, but only those that did * not specify data. */ private final ArrayMap<String, F[]> mActionToFilter = new ArrayMap<String, F[]>(); /** * All of the actions that have been registered and specified a MIME type. */ private final ArrayMap<String, F[]> mTypedActionToFilter = new ArrayMap<String, F[]>();那么 IntentResolver这个类的对象咱们能够从哪里获取呢?
在 Android源码目录\services\java\com\android\server\am\ActivityManagerService.java 中定义:
/** * Resolver for broadcast intents to registered receivers. * Holds BroadcastFilter (subclass of IntentFilter). */ final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver = new IntentResolver<BroadcastFilter, BroadcastFilter>() { @Override protected boolean allowFilterResult( BroadcastFilter filter, List<BroadcastFilter> dest) { IBinder target = filter.receiverList.receiver.asBinder(); for (int i=dest.size()-1; i>=0; i--) { if (dest.get(i).receiverList.receiver.asBinder() == target) { return false; } } return true; } @Override protected BroadcastFilter newResult(BroadcastFilter filter, int match, int userId) { if (userId == UserHandle.USER_ALL || filter.owningUserId == UserHandle.USER_ALL || userId == filter.owningUserId) { return super.newResult(filter, match, userId); } return null; } @Override protected BroadcastFilter[] newArray(int size) { return new BroadcastFilter[size]; } @Override protected boolean isPackageForFilter(String packageName, BroadcastFilter filter) { return packageName.equals(filter.packageName); } };
关于这个ActivityManagerService的对象,咱们该怎么获取呢?咱们知道它是一个系统的Service,还有系统的Service都是一个IBinder对象的。
ServiceManager.getService("activity")这种方式就能够获取到ActivityManagerService对象了。
具体代码在回去看一下EntryClass.java中初始化SmsReceiverResorter的部份内容。
还有一个重要的方法
二、修改优先级的方法:updatePriority
public void updatePriority(String target_pkg) { if (mActionToFilter != null) { IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key); Log.i("TTT", "filters:"+filters_tmp); if (filters_tmp != null) { Log.i("TTT", "add package..."); IntentFilter[] newFilters = new IntentFilter[1]; for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority()); //现将全部的应用的广播接收器的优先级设置最低 filters_tmp[i].setPriority(Integer.MIN_VALUE); if(pkg == null){ continue; } if (target_pkg.equals(pkg)) { Log.i("TTT", "find pkg:"+pkg); //把咱们本身的广播接收器的优先级设置最高 filters_tmp[i].setPriority(Integer.MAX_VALUE); //newFilters[0] = filters_tmp[i]; break; } } /*mActionToFilter.put(key, newFilters); IntentFilter[] filterss = mActionToFilter.get(key); for(int i=0;i<filterss.length;i++){ Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i])); }*/ } } }在这个方法中,传递进来一个包名(com.demo.sms),这个包名其实就是咱们想将其优先级设置最高的一个应用。
咱们首先经过key去获取对应的IntentFilter[]对象
IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key);这里的key是:
private static final String key = Intent.ACTION_PACKAGE_ADDED;就是安装应用的对应的系统action名
那么咱们就获取到了系统中全部注册了安装应用的广播的应用了。
这里咱们再次使用反射从IntentFilter对象中拿到包名,这样咱们就能够进行过滤了。
for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority()); //现将全部的应用的广播接收器的优先级设置最低 filters_tmp[i].setPriority(Integer.MIN_VALUE); if(pkg == null){ continue; } if (target_pkg.equals(pkg)) { Log.i("TTT", "find pkg:"+pkg); //把咱们本身的广播接收器的优先级设置最高 filters_tmp[i].setPriority(Integer.MAX_VALUE); //newFilters[0] = filters_tmp[i]; break; } }而后就开始遍历IntentFilter[]对象,首先将其说有的应用的广播接收器的优先级设置最低,直接调用IntentFilter的setPriority方法
而后发现若是当前的包名和咱们须要设置优先级的包名同样,就将其优先级设置最高。
好了,上面的代码看完了。
下面来看一下咱们自定义的两个广播来进行测试:
第一个测试项目:com.demo.sms
咱们看了上面的代码以后,会发现,这个项目就是咱们须要修改最高优先级的应用
一、广播接收器:
package com.demo.sms; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public final class SmsReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { Log.i("TTT", "com.demo.sms:"+intent.getAction()); } }打印一下action的值
二、后台用于动态注册广播的service
package com.demo.sms; import android.app.Service; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; public final class MyService extends Service { @Override public void onCreate() { super.onCreate(); IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); filter.setPriority(Integer.MIN_VALUE); registerReceiver(new SmsReceiver(), filter); filter = null; } @Override public IBinder onBind(Intent paramIntent) { return null; } }而后就开启这个service就能够了。这里咱们将它的优先级设置最低
第二个测试项目:com.demo.smstrojan
这个项目的代码和上面的一个测试项目代码如出一辙,就是对应的包名不同以及注册广播的优先级不同。这里就不作解释了。
package com.demo.smstrojan; import android.app.Service; import android.content.Intent; import android.content.IntentFilter; import android.os.IBinder; public final class MyService extends Service { @Override public void onCreate() { super.onCreate(); IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); filter.setPriority(Integer.MAX_VALUE); registerReceiver(new SmsReceiver(), filter); } @Override public IBinder onBind(Intent paramIntent) { return null; } }这里咱们将它的优先级设置最高
好了,咱们如今首先运行这两个测试项目。后台的Service也起来了
在来运行一下上面的DemoInject3,
这个应用是不会运行有界面的,他只是一个插件apk.
咱们运行以后,获取DemoInject3.apk文件。
下面就开始进行注入了。
这里我不作演示了,操做步骤和:http://blog.csdn.net/jiangwei0910410003/article/details/40949475 这篇文章如出一辙。
下面来看一下运行结果:
这里其实还须要两个文件:libproxybinder.so和poison
这两个文件从上面提到的那篇文章中能够找到的
开启一个终端来查看一下系统进程的pid:
=>adb shell
=>ps |grep system_server
在开启一个终端进行注入:
=>adb shell
=>su
=> cd /data/data/
=>./poison /data/data/libproxybinder.so 579
在开启一个终端来打印log值,由于这个log值有点多:因此咱们将log输出到一个文件中:
=>adb logcat -s TTT >log.txt
这里须要等待一会,而后咱们退出这个命令(Ctrl+C),查看log.txt文件
=>start log.txt
这里的log.txt文件有点大,这里直截取一部份内容:
咱们看到了打印的key值了。可是这里发现一个问题
isHave:false
这个值是在SmsReceiverResorter.java的构造方法中打印的:
Log.i("TTT", "isHave:"+mActionToFilter.containsKey(key));这里的key是: android.intent.action.PACKAGE_ADDED,安装应用的系统action名
那么问题就来了,咱们在两个测试项目中都进行注册了这个action,为何这里获取到的mActionToFilter中的key没有这个action呢?
这个纠结了我一天,最后才发现问题所在的。
咱们在测试项目中注册广播是:
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); filter.setPriority(Integer.MIN_VALUE); registerReceiver(new SmsReceiver(), filter);发现有一个地方:就是IntentFilter中不只添加了action值,还有一个 scheme的值,好吧,问题还得去看源代码:
仍是在IntentResolver.java中
咱们看到还有一个变量:mSchemeToFilter,用来存储scheme的IntentFilter的值。
那么继续来看一下IntentResolver类中的addFilter方法
发现到问题了:
这里有两个判断:
首先将IntentFilter添加到mSchemeToFilter变量中
而后判断IntentFilter中有没有scheme和mime,没有的话就将IntentFilter添加到mActionToFilter变量中
好吧,到这里咱们就找到问题了,由于咱们如今有scheme字段的,值是:package
那么咱们注册的IntentFilter就不会再mActionToFilter中,而是在mSchemeToFilter中。
问题找到了,下面我就开始修改DemoInject项目中的SmsReceiverResorter.java代码:
1)首先修改一下反射的字段
将下面代码:
field = claxx.getSuperclass().getDeclaredField("mActionToFilter");改为:
field = claxx.getSuperclass().getDeclaredField("mSchemeToFilter");
将下面代码:
private static final String key = Intent.ACTION_PACKAGE_ADDED;改为:
private static final String key = "package";由于咱们注册的时候都是用的是这个值: package
咱们再次运行DemoInject项目,获得DemoInject3.apk
而后再次进行操做(和上面的操做同样):
不过这里有一个问题,就是system_server进程只能注入一次,因此若是在次进行注入操做的话,须要从新启动设备了
等到设备重启以后,还要记得分别运行上面两个测试项目,而后咱们随便安装一个应用,用于测试广播接收的
这时候咱们在来看一下log.txt
这时候看到了isHave是true了
这时候,咱们发现,com.demo.sms项目的优先级最高,其余的应用的优先级都是最低的。咱们还发现
com.demo.sms比com.demo.smstrojan先获取广播
咱们看到上面的两个测试项目的代码:
com.demo.sms项目中的广播优先级设置最低
com.demo.smstrojan项目的广播优先级设置最高
因此正常状况下,应该是com.demo.smstrojan项目最早接收到广播的。
可是如今咱们修改了优先级以后,com.demo.sms项目最早接收到广播
到这里咱们的问题解决了,能够将咱们本身特定的应用的广播接收的优先级设置最高,让其最早接收到广播。
可是问题尚未结束,如今还有这种需求,若是咱们如今想让一个应用最早接收到广播,以后就不让后续的应用接收到这个广播了,有人说能够在这个特定的应用中终止这个广播,那个只是对于有序广播来讲的,如今若是是无序广播呢?咱们该怎么操做呢?
其实看懂了SmsReceiverResorter.java中的updatePriority方法,咱们这里就容易修改了。
原理:咱们能够将其余应用的IntentFilter删除,只保留须要修改优先级的应用的IntentFilter便可
实现:那么能够重新定义一个IntentFilter[]对象,而后将咱们须要设置最早接收到广播的那个应用的IntentFilter添加进去,而后在put进map中
具体修改以下:
updatePriority方法:
public void updatePriority(String target_pkg) { if (mActionToFilter != null) { IntentFilter[] filters_tmp = (IntentFilter[]) mActionToFilter.get(key); Log.i("TTT", "filters:"+filters_tmp); if (filters_tmp != null) { Log.i("TTT", "add package..."); IntentFilter[] newFilters = new IntentFilter[1]; for (int i=0;i<filters_tmp.length;i++) { String pkg = getPackageName(filters_tmp[i]); Log.i("TTT", "pkg:"+pkg+",priority:"+filters_tmp[i].getPriority()); if(pkg == null){ continue; } if (target_pkg.equals(pkg)) { Log.i("TTT", "find pkg:"+pkg); newFilters[0] = filters_tmp[i]; break; } } //重新覆盖IntentFilter[] mActionToFilter.put(key, newFilters); IntentFilter[] filterss = mActionToFilter.get(key); for(int i=0;i<filterss.length;i++){ Log.i("TTT", "new_pkg:"+getPackageName(filters_tmp[i])); } } } }
核心代码:
mActionToFilter.put(key, newFilters);将咱们新的IntentFilter[]对象去覆盖mActionToFilter中的指定key的对象。
其余地方不须要修改,再次运行
查看log.txt
这里看到了,咱们上面代码打印新的IntentFilter[]
如今只有一个
new_pkg:com.demo.sms
并且,咱们在安装一个apk包,发现只有com.demo.sms可以接收到广播了
而com.demo.smstrojan已经接收不到广播了同时咱们会发现之前很牛逼的360卫士如今也接收不到广播了,哈哈~~
咱们没有操做前360卫士能够接收到这个安装广播:
咱们操做以后,哈哈~~,没有拦截到,由于这个广播被咱们手动的给干掉了
通知栏中没有通知了。
好吧,到这里咱们算是完全的作到了广播接收的独裁专政了,如今是能够设置特定的应用能接收到广播,并且无论这个广播是有序的仍是无序的,咱们均可以将其静止,不让其余应用接收到。
说实话,这个问题解决了,真的好开心好开心,特别是发现360如今也接收不到这个广播了。内心特别爽。哈哈~~
DemoSms1项目(com.demo.smstrojan)下载
关于这篇文章的研究意义在于咱们能够控制特定的应用的广播接收器的优先级了,如今市面上有不少应用都会接收系统发送的一些广播,那么每一个应用可能都会将本身的广播接收器的优先级设置最高,让自家的接收器最早接收到广播。那么主动权就可控了,可是那些常规的方法貌似如今每一个应用都在用,因此若是想作到最牛逼的,那么只能用很是规的方法了,那么这些很是规的方法也是须要必定代价的:设备必须root了。同时这么作从理论上来讲就有点流氓了。
并且如今有一些恶意的apk,它须要接收到系统发送的短信广播,那么这时候他确定但愿本身最早收到这个短信了,而后把这个广播给终止了。这时候就能够这么作了。
PS:
有的同窗可能会有疑问,说咱们这么作,那么其余家的应用应该也想到这么作了,是的,因此这里就须要强调一点:
这种作法是很流氓的,不合常规的,并且设备必须root,因此咱们之后在作相似的功能的时候,最好仍是按照常规的方式去实
现。不要用很是规的方法,那些方法只能骗骗小白用户,长期这样对于应用自己发展也是不利的。以上只是我我的观点。