背景
前几天vip学员群里讨论到Activity相关拦截启动实现方案时候,有一些学员朋友提出了一个我们比较陌生的一种aosp原生方案ifw,这个都不要修改任何的系统代码就可以实现对系统的四大组件进行纷纷的拦截,这个“ifw”其实应该大部分同学都是对它很陌生,它的全名是IntentFirewall,也叫“Intent防火墙”。对它陌生其实也正常,毕竟google官方和网络基本上也找不到多少资料,而且非公开接口,还需要高权限等限制,也侧面反应了确实在实际工作中用的也比较少。
但是这个IntentFirewall其实在一些开源系统论坛还比较活跃,用IntentFirewall主要目的是来限制一些国内互联网应用组件启动,因为它们过渡耗费性能,一打开cpu电量,内存呼呼没了,也就是人家说的aosp原生待机10几天,结果国内app一安装最多一天待机。所以就是使用IntentFirewall方式来限制很多组件的启动,当然限制也不是随随便便限制任意组件,也需要根据场景,测试功能不会有问题才可以。
IntentFirewall原理源码相关介绍
源码位置:
frameworks/base/services/core/java/com/android/server/firewall/IntentFirewall.java
组件IntentFirewall的作用
IntentFirewall是Android框架中的一个组件,它可以根据XML文件中定义的规则来控制Intent的发送和接收。Intent是Android中用于组件间通信和启动的一种消息对象,它可以携带动作、数据、类别等信息。IntentFirewall可以根据Intent的属性和调用者的信息,决定是否允许或拒绝Intent的传递,从而增强系统的安全性和灵活性。
主要功能主要有以下几条:
(1)过滤任何类型的Intent,包括Activity,Service,Broadcast和ContentProvider。
(2)动态更新过滤规则,无需重启系统。
(3)支持多种过滤条件,包括动作、数据、类别、组件、权限、用户、进程等。
(4)支持多种过滤动作,包括阻止、记录、修改和转发Intent。
初略看了一下代码核心几个方法如下:
核心检测Activity是分可以启动方法checkStartActivity
/**
* This is called from ActivityManager to check if a start activity intent should be allowed.
* It is assumed the caller is already holding the global ActivityManagerService lock.
*/
public boolean checkStartActivity(Intent intent, int callerUid, int callerPid,
String resolvedType, ApplicationInfo resolvedApp) {
return checkIntent(mActivityResolver, intent.getComponent(), TYPE_ACTIVITY, intent,
callerUid, callerPid, resolvedType, resolvedApp.uid);
}
public boolean checkIntent(FirewallIntentResolver resolver, ComponentName resolvedComponent,
int intentType, Intent intent, int callerUid, int callerPid, String resolvedType,
int receivingUid) {
boolean log = false;
boolean block = false;
// For the first pass, find all the rules that have at least one intent-filter or
// component-filter that matches this intent
List<Rule> candidateRules;
candidateRules = resolver.queryIntent(getPackageManager().snapshot(), intent, resolvedType,
false /*defaultOnly*/, 0);
if (candidateRules == null) {
candidateRules = new ArrayList<Rule>();
}
resolver.queryByComponent(resolvedComponent, candidateRules);
// For the second pass, try to match the potentially more specific conditions in each
// rule against the intent
for (int i=0; i<candidateRules.size(); i++) {
Rule rule = candidateRules.get(i);
if (rule.matches(this, resolvedComponent, intent, callerUid, callerPid, resolvedType,
receivingUid)) {
block |= rule.getBlock();
log |= rule.getLog();
// if we've already determined that we should both block and log, there's no need
// to continue trying rules
if (block && log) {
break;
}
}
}
if (log) {
logIntent(intentType, intent, callerUid, resolvedType);
}
return !block;
}
相关规则的xml文件部分
读取规则文件方法readRulesDir,可以看出这里会扫描data/system/ifw/下面所有的xml文件,这里只需要是xml后缀就会加入规则
/**
* Reads rules from all xml files (*.xml) in the given directory, and replaces our set of rules
* with the newly read rules.
*
* We only check for files ending in ".xml", to allow for temporary files that are atomically
* renamed to .xml
*
* All calls to this method from the file observer come through a handler and are inherently
* serialized
*/
private void readRulesDir(File rulesDir) {
FirewallIntentResolver[] resolvers = new FirewallIntentResolver[3];
for (int i=0; i<resolvers.length; i++) {
resolvers[i] = new FirewallIntentResolver();
}
File[] files = rulesDir.listFiles();
if (files != null) {
for (int i=0; i<files.length; i++) {
File file = files[i];
if (file.getName().endsWith(".xml")) {
readRules(file, resolvers);
}
}
}
Slog.i(TAG, "Read new rules (A:" + resolvers[TYPE_ACTIVITY].filterSet().size() +
" B:" + resolvers[TYPE_BROADCAST].filterSet().size() +
" S:" + resolvers[TYPE_SERVICE].filterSet().size() + ")");
synchronized (mAms.getAMSLock()) {
mActivityResolver = resolvers[TYPE_ACTIVITY];
mBroadcastResolver = resolvers[TYPE_BROADCAST];
mServiceResolver = resolvers[TYPE_SERVICE];
}
}
具体这个xml长什么样呢?这里就需要看接下来的实战部分
实战使用方式
准备一个xml文件,主要push到data/system/ifw
com.android.messaging.xml
<rules>
<activity block="true" log="false">
<component-filter name="com.android.messaging/.ui.conversation.ConversationActivity" />
</activity>
</rules>
<activity标签代表就是要拦截activity类型组件,也可以其它标签service,broadcast等
<component-filter 标签就是代表组件具体名字
这里 block="true"代表是ifw会拦截ConversationActivity的启动
log=“false”时候打印不会有ifw_intent_matched相关的日志
05-02 00:19:01.127 3307 3751 I ActivityTaskManager: START u0 {flg=0x4000000 cmp=com.android.messaging/.ui.conversation.ConversationActivity} with LAUNCH_MULTIPLE from uid 10106 result code=102
log=“true”时候打印会有ifw_intent_matched相关的日志
05-02 00:21:35.355 5090 6117 I ifw_intent_matched: [0,com.android.messaging/.ui.conversation.ConversationActivity,10106,1,NULL,NULL,NULL,NULL,67108864]
05-02 00:21:35.356 5090 6117 I ActivityTaskManager: START u0 {flg=0x4000000 cmp=com.android.messaging/.ui.conversation.ConversationActivity} with LAUNCH_MULTIPLE from uid 10106 result code=102
当然上面xml只是列出一个简单的activity进行拦截,也可以其它3个组件
比如这里给一个qq音乐的案例,供大家参考
<rules>
<service block="true" log="false">
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.business.lockscreen.LockScreenService" />
<component-filter name="com.tencent.qqmusic/com.xiaomi.mipush.sdk.MessageHandleService" />
<component-filter name="com.tencent.qqmusic/com.xiaomi.mipush.sdk.PushMessageHandler" />
<component-filter name="com.tencent.qqmusic/com.huawei.android.pushagent.PushService" />
<component-filter name="com.tencent.qqmusic/com.xiaomi.push.service.XMPushService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusicplayerprocess.daemon.DaemonService" />
<component-filter name="com.tencent.qqmusic/com.tencent.tinker.lib.service.DefaultTinkerResultService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.tinker.service.MusicTinkerResultService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusicplayerprocess.wns.PullService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusicplayerprocess.qplayauto.QPlayAutoService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusicplayerprocess.qqmusicdlna.QPlayService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.third.QQMusicServiceForThird" />
<component-filter name="com.tencent.qqmusic/com.q.m.QS" />
<component-filter name="com.tencent.qqmusic/com.tencent.qalsdk.service.QalAssistService" />
<component-filter name="com.tencent.qqmusic/com.tencent.qalsdk.service.QalService" />
<component-filter name="com.tencent.qqmusic/com.tencent.tmassistantsdk.downloadservice.TMAssistantDownloadSDKService" />
<component-filter name="com.tencent.qqmusic/com.tencent.tmdownloader.TMAssistantDownloadService" />
<component-filter name="com.tencent.qqmusic/jackpal.androidterm.TermService" />
<component-filter name="com.tencent.qqmusic/com.tencent.tinker.lib.service.TinkerPatchService" />
<component-filter name="com.tencent.qqmusic/com.tencent.tinker.lib.service.TinkerPatchService$InnerService" />
</service>
<broadcast block="true" log="false">
<component-filter name="com.tencent.qqmusic/com.tencent.base.os.clock.AlarmClockReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.business.musicalarm.AlarmDemoReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.business.ford.AppLinkReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.BootBroadcastReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.third.BroadcastReceiverCenterForThird" />
<component-filter name="com.tencent.qqmusic/com.tencent.component.thirdpartypush.huaweipush.HWPushReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.business.local.MediaScannReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.component.thirdpartypush.mipush.MiPushReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qalsdk.core.NetConnInfoCenter" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.OverInstallDexInjectReceiver" />
<component-filter name="com.tencent.qqmusic/com.xiaomi.push.service.receivers.PingReceiver" />
<component-filter name="com.tencent.qqmusic/com.huawei.android.pushagent.PushBootReceiver" />
<component-filter name="com.tencent.qqmusic/com.huawei.android.pushagent.PushEventReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qalsdk.QALBroadcastReceiver" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.ShutdownBroadcastReceiver" />
</broadcast>
<activity block="true" log="false">
<component-filter name="com.tencent.qqmusic/com.tencent.tads.splash.AdLandingPageActivity" />
<component-filter name="com.tencent.qqmusic/com.tencent.qqmusic.activity.PushInfoActivity" />
<component-filter name="com.tencent.qqmusic/jackpal.androidterm.Term" />
</activity>
</rules>
更多framework实战干货,请关注下面“千里马学框架”