问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Android 如何进行进程保活

发布网友 发布时间:2022-10-10 10:30

我来回答

1个回答

热心网友 时间:2023-10-08 14:48

每一个 Android 应用启动后至少对应一个进程,有的是多个进程,而且主流应用中多个

进程的应用比例较大

对于任何一个进程,我们都可以通过 adb shell ps|grep <package_name>的方式来查看

它的基本信息

Android 中的进程跟封建社会一样,分了三流九等,Android 系统把进程的划为了如下

几种(重要性从高到低),网上多位大神都详细总结过(备注:严格来说是划分了 6 种)。

场景:

1.某个进程持有一个正在与用户交互的 Activity 并且该 Activity 正处于 resume 的

状态。

2.某个进程持有一个 Service,并且该 Service 与用户正在交互的 Activity 绑定。

3.某个进程持有一个 Service,并且该 Service 调用 startForeground()方法使之位于前台运行。

4.某个进程持有一个 Service,并且该 Service 正在执行它的某个生命周期回调方法,比如 onCreate()、 onStart()或 onDestroy()。

5.某个进程持有一个 BroadcastReceiver,并且该 BroadcastReceiver 正在执行其onReceive()方法。用户正在使用的程序,一般系统是不会杀死前台进程的,除非用户强制停止应用或者系统内存不足等极端情况会杀死。

场景:

1.拥有不在前台、但仍对用户可见的 Activity(已调用 onPause())。

2.拥有绑定到可见(或前台)Activity 的 Service

用户正在使用,看得到,但是摸不着,没有覆盖到整个屏幕,只有屏幕的一部分可见进程

不包含任何前台组件,一般系统也是不会杀死可见进程的,除非要在资源吃紧的情况下,

要保持某个或多个前台进程存活

场景

1.某个进程中运行着一个 Service 且该 Service 是通过 startService()启动的,与用户看见的界面没有直接关联。

在内存不足以维持所有前台进程和可见进程同时运行的情况下,服务进程会被杀死

场景:

在用户按了"back"或者"home"后,程序本身看不到了,但是其实还在运行的程序,

比如 Activity 调用了 onPause 方法系统可能随时终止它们,回收内存

场景:

某个进程不包含任何活跃的组件时该进程就会被置为空进程,完全没用,杀了它只有好处没坏处,第一个干它!

上面是进程的分类,进程是怎么被杀的呢?系统出于体验和性能上的考虑,app 在退到

后台时系统并不会真正的 kill 掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在系统内存不足的情况下,系统开始依据自身的一套进程回收机制

来判断要 kill 掉哪些进程,以腾出内存来供给需要的 app, 这套杀进程回收内存的机制

就叫 Low Memory Killer。那这个不足怎么来规定呢,那就是内存阈值,我们可以使用

cat /sys/mole/lowmemorykiller/parameters/minfree 来查看某个手机的内存阈值。

其实系统在进程回收跟内存回收类似也是有一套严格的策略,可以

自己去了解,大概是这个样子的,oom_adj 越大,占用物理内存越多会被最先 kill 掉,OK,那么现在对于进程如何保活这个问题就转化成,如何降低 oom_adj 的值,以及如

何使得我们应用占的内存最少。

据说这个是手 Q 的进程保活方案,基本思想,系统一般是不会杀死前台进程的。所以要

使得进程常驻,我们只需要在锁屏的时候在本进程开启一个 Activity,为了欺骗用户,

让这个 Activity 的大小是 1 像素,并且透明无切换动画,在开屏幕的时候,把这个 Activity

关闭掉,所以这个就需要监听系统锁屏广播,我试过了,的确好使,如下。

如果直接启动一个 Activity,当我们按下 back 键返回桌面的时候,oom_adj 的值是 8,

上面已经提到过,这个进程在资源不够的情况下是容易被回收的。现在造一个一个像素

的 Activity。

为了做的更隐藏,最好设置一下这个 Activity 的主题,当然也无所谓了

在屏幕关闭的时候把 LiveActivity 启动起来,在开屏的时候把 LiveActivity 关闭掉,所以

要监听系统锁屏广播,以接口的形式通知 MainActivity 启动或者关闭 LiveActivity。

现在 MainActivity 改成如下

按下 back 之后,进行锁屏,现在测试一下 oom_adj 的值

果然将进程的优先级提高了。

但是还有一个问题,内存也是一个考虑的因素,内存越多会被最先 kill 掉,所以把上面

的业务逻辑放到 Service 中,而 Service 是在另外一个 进程中,在 MainActivity 开启这

个服务就行了,这样这个进程就更加的轻量,

OK,通过上面的操作,我们的应用就始终和前台进程是一样的优先级了,为了省电,

系统检测到锁屏事件后一段时间内会杀死后台进程,如果采取这种方案,就可以避免了

这个问题。但是还是有被杀掉的可能,所以我们还需要做双进程守护,关于双进程守护,

比较适合的就是 aidl 的那种方式,但是这个不是完全的靠谱,原理是 A 进程死的时候,

B 还在活着,B 可以将 A 进程拉起来,反之,B 进程死的时候,A 还活着,A 可以将 B

拉起来。所以双进程守护的前提是,系统杀进程只能一个个的去杀,如果一次性杀两个,

这种方法也是不 OK 的。

事实上

那么我们先来看看 Android5.0 以下的源码,ActivityManagerService 是如何关闭在应用

退出后清理内存的

在应用退出后,ActivityManagerService 不仅把主进程给杀死,另外把主进程所属的进

程组一并杀死,这样一来,由于子进程和主进程在同一进程组,子进程在做的事情,也

就停止了。所以在 Android5.0 以后的手机应用在进程被杀死后,要采用其他方案。

这种大部分人都了解,据说这个微信也用过的进程保活方案,移步微信 Android 客户端

后台保活经验分享,这方案实际利用了 Android 前台 service 的漏洞。

原理如下

对于 API level < 18 :调用 startForeground(ID, new Notification()),发送空的

Notification ,图标则不会显示。

对于 API level >= 18:在需要提优先级的 service A 启动一个 InnerService,两个服务

同时 startForeground,且绑定同样的 ID。Stop 掉 InnerService ,这样通知栏图标即

被移除。

public class KeepLiveService extends Service{

public static final int NOTIFICATION_ID=0x11; 

public KeepLiveService() {

}

@Override

public IBinder onBind(Intent intent){

throw new UnsupportedOperationException("Not yet implemented");

 }

 @Override 

public void onCreate() {

 super.onCreate(); //API 18 以下,直 接发 送 Notification 并 将 其 置 为 前 台

if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN_MR2){

startForeground(NOTIFICATION_ID,new Notification()); 

} else { //API 18 以上,发送 Notification 并将其置为前台后,启动 InnerService

Notification.Builder builder=new Notification.Builder(this);

builder.setSmallIcon(R.mipmap.ic_launcher);

startForeground(NOTIFICATION_ID, builder.build());

 startService(new Intent(this, InnerService.class));

 }

 }

 public class InnerService extends Service{

 @Override public IBinder onBind(Intent intent) {

 return null;

 } 

@Override public void onCreate() {

 super.onCreate(); //发送与 KeepLiveService中 ID 相同的 Notification,然后将其取消并取消自己的前台显示

 Notification.Builder builder = new Notification.Builder(this);

builder.setSmallIcon(R.mipmap.ic_launcher);startForeground(NOTIFICATION_ID,

builder.build());

new Handler().postDelayed(new Runnable() { 

@Override public void run() { 

stopForeground(true);

 NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

manager.cancel(NOTIFICATION_ID); 

stopSelf();

 }

 },

100);

 }

 }

 }

在没有采取前台服务之前,启动应用,oom_adj 值是 0,按下返回键之后,变成 9(不

同 ROM 可能不一样)

相互唤醒的意思就是,假如你手机里装了支付宝、淘宝、天猫、UC 等阿里系的 app,

那么你打开任意一个阿里系的 app 后,有可能就顺便把其他阿里系的 app 给唤醒了。

这个完全有可能的。此外,开机,网络切换、拍照、拍视频时候,利用系统产生的广播

也能唤醒 app,不过 Android N 已经将这三种广播取消了。

如果应用想保活,要是 QQ,微信愿意救你也行,有多少手机上没有 QQ,微信呢?或

者像友盟,信鸽这种推送 SDK,也存在唤醒 app 的功能。

拉活方法

JobSheler是作为进程死后复活的一种手段,

native进程方式最大缺点是费电,Native

进程费电的原因是感知主进程是否存活有两种实现方式,在 Native 进程中通过死循环

或定时器,轮训判断主进程是否存活,当主进程不存活时进行拉活。其次 5.0 以上系统

不支持。 但是 JobSheler 可以替代在 Android5.0 以上 native 进程方式,这种方式即

使用户强制关闭,也能被拉起来,亲测可行。

JobSheler@TargetApi(Build.VERSION_CODES.LOLLIPOP) 

public class MyJobService extends JobService {

 @Override

 public void onCreate() {

 super.onCreate();

 startJobSheler();

 }

public void startJobSheler() { 

try {

 JobInfo.Builder builder = new JobInfo.Builder(1,new ComponentName(getPackageName(), MyJobService.class.getName()));

builder.setPeriodic(5); builder.setPersisted(true); JobScheler jobScheler =(JobScheler)

this.getSystemService(Context.JOB_SCHEDULER_SERVICE);

jobScheler.schele(builder.build());

}

catch

(Exception ex)

{ ex.printStackTrace(); } }

 @Override 

public boolean onStartJob(JobParameters jobParameters) {

 return false; 

} @Override public boolean onStopJob(JobParameters jobParameters) { 

return false; 

}

 }

这个是系统自带的,onStartCommand 方法必须具有一个整形的返回值,这个整形的返

回值用来告诉系统在服务启动完毕后,如果被 Kill,系统将如何操作,这种方案虽然可

以,但是在某些情况 or 某些定制 ROM 上可能失效,我认为可以多做一种保保守方案。

1.START_STICKY

如果系统在 onStartCommand 返回后被销毁,系统将会重新创建服务并依次调用

onCreate 和 onStartCommand(注意:根据测试 Android2.3.3 以下版本只会调用

onCreate 根本不会调用 onStartCommand,Android4.0 可以办到),这种相当于服务

又重新启动恢复到之前的状态了)。

2.START_NOT_STICKY

如果系统在 onStartCommand 返回后被销毁,如果返回该值,则在执行完

onStartCommand 方法后如果 Service 被杀掉系统将不会重启该服务

3.START_REDELIVER_INTENT

START_STICKY 的兼容版本,不同的是其不保证服务被杀后一定能重启。

4.相比与粘性服务与系统服务*更厉害一点,这个来自爱哥的研究,这里说的系统服务

很好理解,比如 NotificationListenerService,NotificationListenerService 就是一个监听

通知的服务,只要手机收到了通知,NotificationListenerService 都能监听到,即时用户

把进程杀死,也能重启,所以说要是把这个服务放到我们的进程之中,那么就可以呵呵



所以你的应用要是有消息推送的话,那么可以用这种方式去欺骗用户。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
教材电子版去哪里找 九阳豆浆机打不放网罩能打干豆吗 深圳和记中转场干什么用 腹部增强CT查什么 腹部ct增强检查是什么 腹部加强ct检查出什么 设置好的电脑壁纸老爱自己变我的电脑为什么在老是自动换桌面壁纸 蛇能极速爬行靠什么 武昌理工学院宿舍条件怎么样 河北省人港澳通行证怎样续签? 女人带貔貅的正确方法 php中的hook fdd上下行数据怎么传输 面试结束如何礼貌的离开 面试后如何礼貌的离开。 面试结束,怎么礼貌告别? 怎样手链才叫开了光的? 弥留之国的爱丽丝日剧第二季什么时候出 日剧 我们都无法成为大人 是一部值得看的吗? 弥留之国第二季上线时间 房产证已分配老人和子女各有房产证,但是老人的那一份房产证丢失怎么办理补领手续 砼搅拌站的基本组成 砼添加剂。一般一个普通大小,四至六个罐子的搅拌站,一年要用多少混泥土添加剂? 职场唯美感言句子 中国的中秋节是从哪一年开始的 中秋节是从哪一年开始的? 中秋节是从哪年开始的? 粘和黏的不同 Vivo手机文件管理回收站在哪里,vivo手机文件管理回收站里的文件怎么恢复 适合快五十岁的人的眼霜有哪些?五十岁眼霜排行榜你真的了解吗? Android后台进程保活方案 Android中的保活机制 Service的保活机制 Android保活方案 初学钓鱼如何选择鱼竿长度,如何选择鱼竿调性 新手钓鱼用几米的鱼竿最好 dunlop是什么牌子的轮胎 dunlop牌子的轮胎介绍 罗汉鱼如何养注意事项 罗汉鱼养殖教程和注意事项 感冒鼻塞老不好是鼻炎吗 我想把头发整蓬松、凌乱点,请问那种“烫”叫什么?(不是卷哦) 爱思助手在电脑上为什么窗口这么小 爱思助手内存很少那该咋办没法下载其他软件了 c#在窗体中直接显示excel图表的问题 如何在窗体内集成Excel 二胡为什么不按玄有声音 按玄后没声音了 二胡玄和吉他玄可以共用吗? 1=c二胡是什么玄? 二胡玄的装法 二胡玄上的猫儿螺丝是做什么用的叫什么名字你 七律长征描绘了怎样一副图画