安卓开发:使用双进程守护和进程提权来实现服务进程保活

4,454 阅读3分钟

如何让我们的Android应用进程保活? 文章里总结了一些进程保活方法,本文以双进程守护和进程提权来保活我们的服务进程。

  1. 双进程守护:
    主要设计AB两个不同服务进程,A进程的服务轮询检查B进程的服务是否存活,没存活的话将其拉起,同样B进程服务轮询检查A进程服务是否存活,没存活的话也将其拉起

  2. 进程提权
    主要设计中调用 startForeground方法将service置为“前台进程”,不过这样会显示我们发送的Notification。为了取消这个Notification通知栏,我们需要第三个服务C来进行取消通知栏的工作。

二、具体设计

一、设计三个服务

在AndroidMainfest中对三个服务进行注册,其中FirstService和SecondService运行在新开的两个进程中,以进行我们的双进程守护。ThirdService主要用来取消我们的通知栏,将其放在应用的原进程就好。

   
    
    

二、双进程守护

对FirstService与SecondService进行设计,使其相互守护,为了提醒对方自己已挂,在这里使用相互绑定对方服务的方法,当一方出现异常断开绑定时,则另一方在回调方法中拉起对方,并再进行相互绑定

以下为FirstService的设计:

public class FirstService extends Service {

    private MyBinder binder; //绑定服务需要Binder进行交互
    private MyConn conn;

    @Override
    public IBinder onBind(Intent intent) {

        return binder;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onCreate() {
        super.onCreate();
        binder = new MyBinder();
        if(conn==null)
            conn = new MyConn();

    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        // 与SecondSevice绑定
        FirstService.this.bindService(new Intent(this,SecondService.class),conn, Context.BIND_IMPORTANT);
    }


    //使用aidl实现进程通信

    class MyBinder extends ProcessService.Stub{

        @Override
        public String getServiceName() throws RemoteException {
            return "I am FirstService";
        }
    }

    //建立相互绑定时的连接
    class  MyConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

            Log.i("Info","与SecondService连接成功");

        }

        //在异常断开的回调方法进行拉起对方服务并绑定
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Toast.makeText(FirstService.this,"SecondService被杀死",Toast.LENGTH_SHORT).show();
            // 启动FirstService
            FirstService.this.startService(new Intent(FirstService.this,SecondService.class));
            //绑定FirstService
            FirstService.this.bindService(new Intent(FirstService.this,SecondService.class),conn, Context.BIND_IMPORTANT);
        }
    }



}

服务进程提权

SecondService的设计和FirstService的设计差不多,都是在onStart中与对方相互绑定,在异常断开时重启对方并绑定。

SecondService多了一层服务进程提权设计(FirstService也可以加上这层设计):

public class SecondService extends Service {

    private MyBinder binder;
    private MyConn conn;

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return binder;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onCreate() {
        super.onCreate();
        binder = new MyBinder();
        if(conn==null)
            conn = new MyConn();

    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        //创建通知栏
        Notification.Builder builder = new Notification.Builder(this);
        builder.setSmallIcon(R.mipmap.ic_launcher);

        //显示通知栏,服务进程提权为前台服务。
        startForeground(250, builder.build());//使用id:250标记该通知栏

        // 启动第三个服务ThirdService来消除通知栏
        startService(new Intent(this,ThirdService.class));

        SecondService.this.bindService(new Intent(this,FirstService.class),conn, Context.BIND_IMPORTANT);
    }

    class MyBinder extends ProcessService.Stub{

        @Override
        public String getServiceName() throws RemoteException {
            return "I am SecondService";
        }
    }

    class  MyConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i("Info","与FirtService连接成功"+SecondService.this.getApplicationInfo().processName);
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Toast.makeText(SecondService.this,"FirstService被杀死",Toast.LENGTH_SHORT).show();
            // 启动FirstService
            SecondService.this.startService(new Intent(SecondService.this,FirstService.class));
            //绑定FirstService
            SecondService.this.bindService(new Intent(SecondService.this,FirstService.class),conn, Context.BIND_IMPORTANT);
        }
    }

}

在ThirdService消除通知栏 :

public class ThirdService extends Service {


    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        // 被启动后创建相互id的通知栏,并提权服务
        Notification.Builder builder = new Notification.Builder(this);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        startForeground(250, builder.build());

        //开启新的线程消除通知栏
        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(1000);
                stopForeground(true);//停止前台
                NotificationManager manager =
                        (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                manager.cancel(250); // 消除通知栏
                stopSelf(); // 停止服务
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
}

最后在MainActivity或其他适当的地方启动FirstService和SecondService这两个服务:

    this.startService(new Intent(this,FirstService.class));
    this.startService(new Intent(this,SecondService.class));

服务进程保活效果

  1. 当应用处于后台时,双进程守护起很好的效果,但一方服务进程被杀掉时,另一方服务可即时地重启了被杀掉的服务进程。(也可以在设置->应用->正在运行中进行手动地杀死进程查看效果)

  2. 当FirstService和SecondService进行服务提权为前台服务时,可以躲过360卫士的手机加速的查杀。

  3. (上述仅在vivo max5中测试过。下方为项目代码地址,可自行测试)

Github