前一篇文章 —— Android 进程保活系列:(一)利用 Activity 提升权限 讲到了利用前台的 Activity 保证系统管家不会杀死我们的应用。这只是一种讨巧的技术手段,并没有利用系统的漏洞。今天要说的方法适用性非常广,应用间互不干扰,不存在像是我开启一像素 Activity 把你盖住,然后你我争夺焦点的问题。
在实践之前还是先看看别人家的应用,比如腾讯新闻。adb shell 下输入
dumpsys activity services com.tencent.news
看一下控制台的输出,顾名思义 PushService 应该是推送服务,ServiceRecord 指明了它是前台服务。我们看一下它的 oom_adj 的值:
ps | grep com.tencent.news
cat /proc/25890/oom_adj
没错,PuseService 的优先级是 2,属于可感知进程,一般不会被杀死。下面有个关于 oom_adj 的说明。
其中红色部分代表比较容易被杀死的 Android 进程(OOM_ADJ >= 4),绿色部分表示不容易被杀死的 Android 进程,其他表示非 Android 进程(纯 Linux 进程)。在 Lowmemorykiller 回收内存时会根据进程的级别优先杀死 OOM_ADJ 比较大的进程,对于优先级相同的进程,则进一步受到进程所占内存和进程存活时间的影响。
下面就来亲身实践一下。利用系统的漏洞开启前台服务,提升进程的优先级。这里有两个思路:
- 思路一:API < 18,启动前台 Service 时直接传入new Notification();
- 思路二:API >= 18,同时启动两个id相同的前台 Service,然后再将后启动的 Service 做 stop 处理;
// 要开启前台的 service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
startForeground(SERVICE_ID, new Notification());
} else {
startForeground(SERVICE_ID, new Notification());
Intent sendIntend = new Intent(this, ChannelService.class);
startService(sendIntend);
}
return super.onStartCommand(intent, flags, startId);
}
// 为开启前台 service 服务的傀儡 service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(DaemonService.SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
这样就完成了,我们再次用 shell 命令验证一下。
没错,它已经是前台服务了,用户看不见摸不着的前台服务,系统是不会轻易杀死该服务的,可以放心大胆地搞事情啦~~
项目地址:AndroidKeepPractive