zoukankan      html  css  js  c++  java
  • 保证Service不被Kill的解决方案

    1、Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样

    2、通过 startForeground将进程设置为前台进程,做前台服务,优先级和前台应用一个级别​,除非在系统内存非常缺,否则此进程不会被 kill.具体实现方式为在service中创建一个notification,再调用void android.app.Service.startForeground(int id,Notificationnotification)方法运行在前台即可。

    3、双进程Service:让2个进程互相保护,其中一个Service被清理后,另外没被清理的进程可以立即重启进程

      双进程守护:

      首先是一个AIDL接口,两边的Service都要通过继承ServiceAidl.Stub来实现AIDL接口中的方法。接口声明如下:

    interface ServiceAidl {
        String getName();
    }

      然后是两个Service,为了保持连接,内部写一个内部类实现ServiceConnection的接口,当外部杀了其中一个进程的时候,会进入onDisConnection中,那么此时要做的就是start和bind另一个进程,因为Service的启动是可以多次的,所以这样是没问题的,代码如下:

    public class LocalService extends Service {
        private ServiceConnection conn;
        private MyService myService;
    
        @Override
        public IBinder onBind(Intent intent) {
            return myService;
        }
    
    
        @Override
        public void onCreate() {
            super.onCreate();
            init();
    
        }
    
        private void init() {
            if (conn == null) {
                conn = new MyServiceConnection();
            }
            myService = new MyService();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Toast.makeText(getApplicationContext(), "本地进程启动", Toast.LENGTH_LONG).show();
            Intent intents = new Intent();
            intents.setClass(this, RemoteService.class);
            bindService(intents, conn, Context.BIND_IMPORTANT);
            return START_STICKY;
        }
    
        class MyService extends ServiceAidl.Stub {
    
    
            @Override
            public String getName() throws RemoteException {
                return null;
            }
        }
    
        class MyServiceConnection implements ServiceConnection {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                System.out.println("获取连接");
    
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Toast.makeText(LocalService.this, "远程连接被干掉了", Toast.LENGTH_SHORT).show();
                LocalService.this.startService(new Intent(LocalService.this,
                        RemoteService.class));
                LocalService.this.bindService(new Intent(LocalService.this,
                        RemoteService.class), conn, Context.BIND_IMPORTANT);
    
            }
    
        }
    
    }

    远程服务类如下:

    public class RemoteService extends Service {
        private MyBinder binder;
        private ServiceConnection conn;
    
        @Override
        public void onCreate() {
            super.onCreate();
            // System.out.println("远程进程开启");
            init();
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Toast.makeText(getApplicationContext(), "远程进程启动", Toast.LENGTH_LONG).show();
            Intent intents = new Intent();
            intents.setClass(this, LocalService.class);
            bindService(intents, conn, Context.BIND_IMPORTANT);
            return START_STICKY;
        }
    
        private void init() {
            if (conn == null) {
                conn = new MyConnection();
            }
            binder = new MyBinder();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
    
        static class MyBinder extends ServiceAidl.Stub {
    
    
            @Override
            public String getName() throws RemoteException {
                return "远程连接";
            }
        }
    
        class MyConnection implements ServiceConnection {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                System.out.println("获取远程连接");
            }
    
            @Override
            public void onServiceDisconnected(ComponentName nme) {
                Toast.makeText(RemoteService.this, "本地连接被干掉了", Toast.LENGTH_SHORT).show();
                RemoteService.this.startService(new Intent(RemoteService.this,
                        LocalService.class));
                RemoteService.this.bindService(new Intent(RemoteService.this,
                        LocalService.class), conn, Context.BIND_IMPORTANT);
            }
        }
    
    }

      布局文件里要加上声明

    <service android:name=".LocalService" />
            <service
                android:name=".RemoteService"
                android:process=":remote" />

      实际情况我个人测试,在5.0以下的模拟器上是没问题的,不管多次从系统的进程里kill掉,也还是会重新启动tos,但是5.0以上这种方法是无效的,5.0以上Android应该是意识到了这种双进程守护的方式,因此修改了一下源码,让这种双进程保活应用的方式无效。因此,针对5.0以上,我们采用另一种方案。

      JobScheduler执行任务调度保活

      JobScheduler这个类是21版本google新出来的api。

      这个任务其实是在设备空闲期执行的,而且系统设计的这个api不会很耗电,本意是用来执行一些任务调度的,但是我们设想一下,如果用这个类来执行我们的开启双进程,那么也是一定会在设备空闲期执行的,因此我们写一个类继承JobService,在onstart里声明创建JobScheduler对象,并设置多久执行一次和开机自启动,这样就能确保及时在息屏状态,也能够执行重启进程,所以我们在JobService的onStopJob方法里判断我们的进程是否被回收了,如果被回收了就重启进程,这样子就可以实现5.0以上的进程保活了。具体代码如下:

    public class JobHandlerService extends JobService {
        private JobScheduler mJobScheduler;
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            System.out.println("服务被创建");
    
    //        startService(new Intent(this, LocalService.class));
    //        startService(new Intent(this, RemoteService.class));
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
                JobInfo.Builder builder = new JobInfo.Builder(startId++,
                        new ComponentName(getPackageName(), JobHandlerService.class.getName()));
    
                builder.setPeriodic(5000); //每隔5秒运行一次
                builder.setRequiresCharging(true);
                builder.setPersisted(true);  //设置设备重启后,是否重新执行任务
                builder.setRequiresDeviceIdle(true);
    
                if (mJobScheduler.schedule(builder.build()) <= 0) {
                    //If something goes wrong
                    System.out.println("工作失败");
                } else {
                    System.out.println("工作成功");
                }
            }
            return START_STICKY;
        }
    
    
        @Override
        public boolean onStartJob(JobParameters params) {
    
            Toast.makeText(this, "服务启动", Toast.LENGTH_SHORT).show();
    //        || isServiceRunning(this, "com.ph.myservice.RemoteService") == false
            System.out.println("开始工作");
    //        if (!isServiceRunning(getApplicationContext(), "com.ph.myservice") || !isServiceRunning(getApplicationContext(), "com.ph.myservice:remote")) {
    //            startService(new Intent(this, LocalService.class));
    //            startService(new Intent(this, RemoteService.class));
    //        }
    
           /* boolean serviceRunning = isServiceRunning(getApplicationContext(), "com.ph.myservice");
            System.out.println("进程一" + serviceRunning);
    
            boolean serviceRunning2 = isServiceRunning(getApplicationContext(), "com.ph.myservice:remote");
            System.out.println("进程二" + serviceRunning2);*/
            return false;
        }
    
        @Override
        public boolean onStopJob(JobParameters params) {
            if (!isServiceRunning(this, "com.ph.myservice.LocalService") || !isServiceRunning(this, "com.ph.myservice.RemoteService")) {
                startService(new Intent(this, LocalService.class));
                startService(new Intent(this, RemoteService.class));
            }
            return false;
        }
    
        // 服务是否运行
        public boolean isServiceRunning(Context context, String serviceName) {
            boolean isRunning = false;
            ActivityManager am = (ActivityManager) this
                    .getSystemService(Context.ACTIVITY_SERVICE);
            List<ActivityManager.RunningAppProcessInfo> lists = am.getRunningAppProcesses();
    
    
            for (ActivityManager.RunningAppProcessInfo info : lists) {// 获取运行服务再启动
                System.out.println(info.processName);
                if (info.processName.equals(serviceName)) {
                    isRunning = true;
                }
            }
            return isRunning;
    
        }
    
    
    }
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                openJobService();
            } else {
                openTwoService();
            }
    
        }
    
        private void openTwoService() {
            startService(new Intent(this, LocalService.class));
            startService(new Intent(this, RemoteService.class));
        }
    
        private void openJobService() {
    
            Intent intent = new Intent();
            intent.setClass(MainActivity.this, JobHandlerService.class);
            startService(intent);
    
        }
    }

      经过我6.0系统的华为真机测试是没有问题的,就算处于息屏状态进程也还是活着的,不管过多久打开屏幕还是会tos,并且关机了开机也会吐司。

    4、AlarmManager不断启动service。该方式原理是通过定时警报来不断启动service,这样就算service被杀死,也能再启动

    参考实现方式如下:

    Intent intent =new Intent(mContext, MyService.class);

    PendingIntent sender=PendingIntent

    .getService(mContext, 0, intent, 0);

    AlarmManager alarm=(AlarmManager)getSystemService(ALARM_SERVICE);

    alarm.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis,5*1000,sender);

    该方式基本可以保证在正常运行情况下,以及任务栏移除历史任务后(小米、魅族手机除外),service不被杀死。但是360等软件管家依然可以杀死。另外还有不断启动的逻辑处理麻烦。

    5、监听系统广播判断Service状态(比如:手机重启、网络切换、开锁屏)

    6、QQ黑科技:在应用退到后台后,另起一个只有 1 像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死

    7、在已经root的设备下,修改相应的权限文件,将App伪装成系统级的应用(Android4.0系列的一个漏洞,已经确认可行)

    • Android系统中当前进程(Process)fork出来的子进程,被系统认为是两个不同的进程。当父进程被杀死的时候,子进程仍然可以存活,并不受影响。鉴于目前提到的在Android-Service层做双守护都会失败,我们可以fork出c进程,多进程守护。死循环在那检查是否还存在,具体的思路如下(Android5.0以下可行)
    1. 用C编写守护进程(即子进程),守护进程做的事情就是循环检查目标进程是否存在,不存在则启动它。
    2. 在NDK环境中将1中编写的C代码编译打包成可执行文件(BUILD_EXECUTABLE)。
    3. 主进程启动时将守护进程放入私有目录下,赋予可执行权限,启动它即可。

    8、联系厂商,加入白名单

    转载连接

    http://www.cnblogs.com/shen-hua/p/5836386.html

    http://blog.csdn.net/pan861190079/article/details/72773549

  • 相关阅读:
    Django之ModelForm组件
    Hibernate的继承映射
    hibernate的检索策略
    Hibernate的多对多映射关系
    Hibernate中的一对一映射关系
    Hibernate中双向的一对多关系
    Hibernate中的映射关系(一对多)
    Hibernate的映射组成关系
    Hibernate的大对象映射
    hibernate的日期映射
  • 原文地址:https://www.cnblogs.com/kelina2mark/p/7665438.html
Copyright © 2011-2022 走看看