linux 如何实现java守护进程编程开发

linux 如何实现java守护进程编程开发,第1张

可以通过GuardServer实现,具体代码如下

 1 public class GuardServer {

 2     private String servername

 3 

 4     public GuardServer(String servername) {

 5         this.servername = servername

 6     }

 7 

 8     public void startServer(String cmd) throws Exception {

 9         System.out.println("Start Server : " + cmd)

10         //将命令分开

11 //        String[] cmds = cmd.split(" ")

12 //        ProcessBuilder builder = new ProcessBuilder(cmds)

13     

14         //

15         ProcessBuilder builder=new ProcessBuilder(new String[]{"/bin/sh","-c",cmd})

16         //将服务器程序的输出定位到/dev/tty

17         builder.redirectOutput(new File("/dev/tty"))

18         builder.redirectError(new File("/dev/tty"))

19         builder.start() // throws IOException

20         Thread.sleep(10000)

21     }

22 

23     /**

24      * 检测服务是否存在

25      * 

26      * @return 返回配置的java程序的pid

27      * @return pid >0 返回的是 pid <=0 代表指定java程序未运行

28      * **/

29     public int checkServer() throws Exception {

30         int pid = -1

31         Process process = null

32         BufferedReader reader = null

33         process = Runtime.getRuntime().exec("jps -l")

34         reader = new BufferedReader(new InputStreamReader(process.getInputStream()))

35         String line

36         while ((line = reader.readLine()) != null) {

37             String[] strings = line.split("\\s{1,}")

38             if (strings.length < 2)

39                 continue

40             if (strings[1].contains(servername)) {

41                 pid = Integer.parseInt(strings[0])

42                 break

43             }

44         }

45         reader.close()

46         process.destroy()

47         return pid

48     }

49 }

在我们进行应用开发时,会遇到上级的各种需求,其中有一条 刚需: 后台保活 ,更有甚者:

我要我们的应用永远活在用户的手机后台不被杀死 —— 这都 TM 的扯淡

除了系统级别的应用能持续运行,所有三方程序都有被杀死的那一天!当然 QQ/微信/陌陌 等会好一些,因为他们已经深入设备的 心 ;

我们能做的只是通过各种手段尽量让我们的程序在后台运行的时间长一些,或者在被干掉的时候,能够重新站起来,而且这个也不是每次都有效的,也是不能在所有的设备的上都有效的;要做到后台进程保活,我们需要做到两方便:

要实现实现上边所说,通过下边几点来实现,首先我们需要了解下进程的优先级划分:

Process Importance 记录在 ActivityManager.java 类中:

了解进程优先级之后,我们还需要知道一个进程回收机制的东西;这里参考 AngelDevil 在博客园上的一篇文章:

Android 的 Low Memory Killer 基于 Linux 的 OOM 机制,在 Linux 中,内存是以页面为单位分配的,当申请页面分配时如果内存不足会通过以下流程选择bad进程来杀掉从而释放内存:

在 Low Memory Killer 中通过进程的 oom_adj 与占用内存的大小决定要杀死的进程, oom_adj 越小越不容易被杀死;

Low Memory Killer Driver 在用户空间指定了一组内存临界值及与之一一对应的一组 oom_adj 值,当系统剩余内存位于内存临界值中的一个范围内时,如果一个进程的 oom_adj 值大于或等于这个临界值对应的 oom_adj 值就会被杀掉。

下边是表示 Process State (即老版本里的 OOM_ADJ )数值对照表,数值越大,重要性越低,在新版SDK中已经在 android 层去除了小于0的进程状态

Process State (即老版本的 OOM_ADJ )与 Process Importance 对应关系,这个方法也是在 ActivityManager.java 类中,有了这个关系,就知道可以知道我们的应用处于哪个级别,对于我们后边优化有个很好地参考

一般情况下,设备端进程被干掉有一下几种情况

由以上分析,我们可以可以总结出,如果想提高我们应用后台运行时间,就需要提高当前应用进程优先级,来减少被杀死的概率

分析了那么多,现在对Android自身后台进程管理,以及进程的回收也有了一个大致的了解,后边我们要做的就是想尽一切办法去提高应用进程优先级,降低进程被杀的概率;或者是在被杀死后能够重新启动后台守护进程

第一种方式就是利用系统漏洞,使用 startForeground() 将当前进程伪装成前台进程,将进程优先级提高到最高(这里所说的最高是服务所能达到的最高,即1)

这种方式在 7.x 之前都是很好用的,QQ、微信、IReader、Keep 等好多应用都是用的这种方式实现;因为在7.x 以后的设备上,这种伪装前台进程的方式也会显示出来通知栏提醒,这个是取消不掉的,虽然 Google 现在还没有对这种方式加以限制,不过这个已经能够被用户感知到了,这种方式估计也用不了多久了

下边看下实现方式,这边这个 VMDaemonService 就是一个守护进程服务,其中在服务的 onStartCommand() 方法中调用 startForeground() 将服务进程设置为前台进程,当运行在 API18 以下的设备是可以直接设置,API18 以上需要实现一个内部的 Service ,这个内部类实现和外部类同样的 *** 作,然后结束自己;当这个服务启动后就会创建一个定时器去发送广播,当我们的核心服务被干掉后,就由另外的广播接收器去接收我们守护进程发出的广播,然后唤醒我们的核心服务;

当我们启动这个守护进程的时候,就可以使用以下 adb 命令查看当前程序的进程情况(需要 adb shell 进去设备),

为了等下区分进程优先级,我启动了一个普通的后台进程,两外两个一个是我们启动的守护进程,一个是当前程序的核心进程,可以看到除了后台进程外,另外两个进程都带有 isForeground=true 的属性:

然后我们可以用下边的命令查看 ProcessID

有了 ProcessID 之后,我们可以根据这个 ProcessID 获取到当前进程的优先级状态 Process State ,对应 Linux 层的 oom_adj

可以看到当前核心进程的级别为 0 ,因为这个表示当前程序运行在前台 UI 界面,守护进程级别为 1 ,因为我们利用漏洞设置成了前台进程,虽然不可见,但是他的级别也是比较高的,仅次于前台 UI 进程,然后普通后台进程级别为 4 ;当我们退到后台时,可以看到核心进程的级别变为 1 了,这就是因为我们利用 startForeground() 将进程设置成前台进程的原因,这样就降低了进程被系统回收的概率了;

可以看到这种方式确实能够提高进程优先级,但是在一些国产的设备上还是会被杀死的,比我我测试的时候小米点击清空最近运行的应用进程就别干掉了;当把应用加入到设备白名单里就不会被杀死了,微信就是这样,人家直接装上之后就已经在白名单里了,我们要做的就是在用户使用中引导他们将我们的程序设置进白名单,将守护进程和白名单结合起来,这样才能保证我们的应用持续或者

Android系统在5.x以上版本提供了一个 JobSchedule 接口,系统会根据自己实现定时去调用改接口传递的进程去实现一些 *** 作,而且这个接口在被强制停止后依然能够正常的启动;不过在一些国产设备上可能无效,比如小米;

下边是 JobServcie 的实现:

我们要做的就是在需要的时候调用 JobSchedule 的 schedule 来启动任务;剩下的就不需要关心了, JobSchedule 会帮我们做好,下边就是我这边实现的启动任务的方法:

在实现 Service 类时,将 onStartCommand() 返回值设置为 START_STICKY ,利用系统机制在 Service 挂掉后自动拉活;不过这种方式只适合比较原生一些的系统,像小米,华为等这些定制化比较高的第三方厂商,他们都已经把这些给限制掉了;

这种方式在以下两种情况无效:

事事没有绝对,万物总有一些漏洞,就算上边的那些方式不可用了,后边肯定还会出现其他的方式;我们不能保证我们的应用不死,但我们可以提高存活率;

其实最好的方式还是把程序做好,让程序本身深入人心,别人喜欢你了,就算你被干掉了,他们也会主动的把你拉起来,然后把你加入他们的白名单,然后我们的目的就实现了不是

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/12072049.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-20
下一篇 2023-05-20

发表评论

登录后才能评论

评论列表(0条)

保存