ROM定制:APP防自启原理

国内APP各种保活、拉活,这也是导致安卓手机卡慢的主因,为此各大厂商都有自己防自启机制,规避APP的流氓行为,提升手机流畅性。

防自启基本原理:
拦截四大组件(activity、service、receiver、provider)启动流程,并对其它可能主动拉起APP的AccountManagerService、JobService、SyncManager进行拦截,切断一切可能启动APP的线索。

下面针对各组件的拦截点进行汇总(activity不拦截,用户可感知):

service

启动service有两个接口startService、bindService,二者最终都会调用retrieveServiceLocked()检索service信息,我们选择在此统一拦截service的启动。
startService()-->AMS.startServiceLocked()-->retrieveServiceLocked()
bindService()-->AMS.bindServiceLocked()-->retrieveServiceLocked()

retrieveServiceLocked()先在ServiceMap缓存中查询service,查不到再调用PMS.resolveService()进一步查询。我们在查询到ServiceRecord之后拦截。

ActiveServices.java:retrieveServiceLocked():
在blockService()中我们可以根据callname和ServiceRecord信息进行进一步处理,例如黑名单、isSystemAPP()等,根据实际需求定制。

receiver

根据调用流程,我们选择在processNextBroadcast()进行广播拦截,有序队列中的动态广播无需拦截,只拦截静态注册,startProcess之前拦截。
sendBroadcast()-->AMS.broadcastIntent()-->broadcastIntentLocked()-->queue.scheduleBroadcastsLocked()-->mHandler.sendMessage(BROADCAST_INTENT_MSG)-->processNextBroadcast()

BroadcastQueue.java:processNextBroadcast():
这里是粗粒度的skip整个广播,后面会介绍针对receivers中某个接收者进行skip,对无源码的单个耗时广播有效。

provider

根据调用流程,我们选择在AMS的getContentProviderImpl()进行拦截。
ContentResolver.query()-->acquireUnstableProvider()-->mMainThread.acquireProvider()-->ActivityManagerNative.getDefault().getContentProvider()-->getContentProviderImpl()

ActivityManagerService.java:getContentProviderImpl():

AccountManagerService、JobService、SyncManager

这几个service不再细述流程,直接贴拦截代码。

  • AccountManagerService.java:addAccount()、addAccountAsUser()

  • JobServiceContext.java:executeRunnableJob()

  • SyncManager.java:bindToSyncAdapter()

>

补充:receiver耗时与skip

广播超时场景下,我们需要分析出receivers中具体哪个receiver耗时较长,进行优化处理。
对于无源码的APK,广播耗时又比较久,我们也可以针对性的skip该receiver。

动态广播:deliverToRegisteredReceiverLocked()处理;
静态广播:进程已创建,processCurBroadcastLocked()处理;
静态广播:进程未创建,startProcessLocked()创建进程。

耗时分析

原生代码对广播耗时分析不太友好,需要手动比较日志中"BroadcastQueue:Delivering to xxx"前后的时间间隔来判断耗时,繁琐而且不精确。我们采用自行添加log的方式协助日常分析。

无序广播:binder异步分发,需要自行添加log确认耗时时长。
有序广播:每个BroadcastRecord全部处理完毕,会有finish日志,单个receiver的耗时需要自行添加log。

无序广播:
deliverToRegisteredReceiverLocked()-->performReceiveLocked()-->AT.scheduleRegisteredReceiver()-->InnerReceiver.performReceive()-->ReceiverDispatcher.performReceive()-->ReceiverDispatcher.Args.getRunnable()-->onReceive()

LoadedApk.java:ReceiverDispatcher.Args.getRunnable():

有序广播:
每个BroadcastRecord中所有receivers处理完,总时长。
BroadcastQueue.java:processNextBroadcast():
BroadcastQueue: Finished with ordered broadcast BroadcastRecord{9bec22c u13 android.intent.action.USER_INITIALIZE} receivers:(5) take 5783ms in [foreground], remains 5

BroadcastRecord中单个receiver耗时。
processCurBroadcastLocked()-->AT.scheduleReceiver()-->handleReceiver()-->onReceive()
ActivityThread.java:handleReceiver():

耗时广播skip

例如发现GMS某个receiver耗时较长,对实际功能又无影响,可skip此receiver。
在deliverToRegisteredReceiverLocked()、processCurBroadcastLocked()、startProcessLocked()三处进行skip处理。


deliverToRegisteredReceiverLocked():

processCurBroadcastLocked():

startProcessLocked()之前:

作者: RESSRC

个人资源站

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据