Android服务保活(灰色保活)

  • 内容
  • 评论
  • 相关

灰色保活,这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。

1、方案的设计思想:

Android 中 Service 的优先级为4,通过 setForeground 接口可以将后台 Service 设置为前台 Service,使进程的优先级由4提升为2,从而使进程的优先级仅仅低于用户当前正在交互的进程,与可见进程优先级一致,使进程被杀死的概率大大降低。

2、方案实现的挑战

从 Android2.3 开始调用 setForeground 将后台 Service 设置为前台 Service 时,必须在系统的通知栏发送一条通知,也就是前台 Service 与一条可见的通知时绑定在一起的。

对于不需要常驻通知栏的应用来说,该方案虽好,但却是用户感知的,无法直接使用。

3、方案挑战应对措施

通过实现一个内部 Service,在 LiveService 和其内部 Service 中同时发送具有相同 ID 的 Notification,然后将内部 Service 结束掉。随着内部 Service 的结束,Notification 将会消失,但系统优先级依然保持为2。

4、方案的使用范围

Android7.1以下,API < 25,因为在此版本之后这个漏洞给修复了。

5、具体实施方案

public class GrayService extends Service {

    private final static int GRAY_SERVICE_ID = 1001;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
            startForeground(GRAY_SERVICE_ID, new Notification());//API < 18
        } else if (Build.VERSION.SDK_INT < 25){
            Intent innerIntent = new Intent(this, GrayInnerService.class);
            startService(innerIntent);
            startForeground(GRAY_SERVICE_ID, new Notification());
        }

        return super.onStartCommand(intent, flags, startId);
    }

    ...
    ...

    /**
     * 给 25 > API >= 18 的平台上用的灰色保活手段
     */
    public static class GrayInnerService extends Service {

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(GRAY_SERVICE_ID, new Notification());
            stopForeground(true);
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }

    }
}

就是这么简单,能神不知鬼不觉的启动着一个前台Service。其实市面上很多app都用着这种灰色保活的手段,什么?你不信?好吧,我们来验证一下。流程很简单,打开一个app,看下系统通知栏有没有一个 Notification,如果没有,我们就进入手机的adb shell模式,然后输入下面的shell命令

dumpsys activity services PackageName

下面分别是我手机上QQ的测试结果,像微信、支付宝、陌陌等都是,大家有兴趣也可以自己验证一下。

验证方法:

打印出指定包名的所有进程中的Service信息,看下有没有 isForeground=true 的关键信息。如果通知栏没有看到属于app的 Notification 且又看到 isForeground=true 则说明了,此app利用了这种灰色保活的手段。

   androidkeepalive1
其实Google察觉到了此漏洞的存在,并在Android7.1版本进行了封堵。这就是为什么这种保活方式分 25 > API >= 18 和
 API < 18 两种情况,从Android5.0的ServiceRecord类的postNotification函数源代码中可以看到这样的一行注释:

androidkeepalive11
需要注意的是,使用灰色保活并不代表着你的Service就永生不死了,只能说是提高了进程的优先级。如果你的app进程占用了
大量的内存,按照回收进程的策略,同样会干掉你的app。
感兴趣于灰色保活是如何利用系统漏洞不显示 Notification 的童鞋,可以研究一下系统的 ServiceRecord、NotificationManagerService 等
相关源代码,因为不是本文的重点,所以不做详述。

其他方法可以参考Android服务保活(一),我还会逐一写其他保活的办法,敬请期待哦。

评论

2条评论
  1. Gravatar 头像

    Fantine

    So let me get this straight Mr. Yeomans. Your scientific conclusion is that it is a meteor because no man made object was predicted in that area??? So it must be natural?Thats it? So no analysis of its flight path, speed, any meteor like chrcictraaistars explained? just the fact that nothing was predicted to enter the atmosphere. Oh and lets not forget. THE SAME OBJECT SEEN SECOND TIME THIS WEEK!!! If it is a meteor, we should catch it and use it to fly. I hate NASA!

发表评论