什么是Android进程(app)保活、进程保活的方案

想了解什么是Android 进程、Android 进程的生命周期、Android 进程回收策略

可参照地址https://blog.csdn.net/lmm0513/article/details/103073475

一、app保活

       在Android中是一种流氓行为,一方面无端浪费用户手机电量,另一方面给用户一种很困惑的感觉,影响用户体验还有可能导致整个Android系统流畅性变差,所以Google官方一种不推荐该功能,也一直在阻止这方面功能在Android系统上运行,作为一个Android开发人员,应该极力地址这种无耻的行为!!! 

以上内容原文:https://blog.csdn.net/qq_18350329/article/details/70738327

 二、Android 进程保活的两个方案:

  • 运行中保活:提高进程优先级,降低被系统 kill 的概率

  • 被 kill 后拉活:被系统 kill 后,将进程拉活(重启)

1.运行中保活

通过前面章节的论述,我们知道,假设 APP 进程能够一直被认为是前台进程,那么系统就有可能永远不会杀死该进程。当然,这是不可能的,当我们将 APP 退回到后台,改 APP 所属进程就不属于 前台进程了。但是上述假设也让我们有了灵感不是,只要我们尽可能的提高进程的优先级,不就可以最大概率的降低被系统 kill 的可能性了。

那么,提高进程优先级的方法有哪些呢?

(1)利用 Activity 提高权限

监听手机锁屏解锁事件,锁屏时启动一个1像素的 Activity ,解锁时将该 Activity 销毁。此方法能将进程在锁屏状态下提高到最高前台进程( oom_adj 为 0 )的级别。避免出现一些让用户困扰(体验不好)的情况,该 Activity 需设计成用户无感知。

此方案主要解决为了达到省电目的,一些第三方应用或者系统管理工具在检测到锁屏之后一段时间(一般是 5 分钟)内会杀死后台进程。

下面是实例代码:

1像素 Activity:

class KeepLiveActivity : AppCompatActivity() {


   override fun onCreate(savedInstanceState: Bundle?) {

       super.onCreate(savedInstanceState)


       KeepLiveManager.keepLiveActivity = this


       // 设置Activity在左上角

       window.setGravity(Gravity.START)


       // 设置window的像素为1

       window.attributes.run {

           x = 0

           y = 0

           width = 1

           height = 1

       }

   }

}

注意,这里一定要设置启动模式为 singleInstance,使该 Activity 单独一个 Activity 回退栈,否则在锁屏且 APP 在后台运行时,启动该 Activity 后,会进程带入前台,解锁后显示该APP界面,体验不好

<activity

   android:name=".KeepLiveActivity"

   android:launchMode="singleInstance"/>

广播接收者:

class KeepLiveReceiver : BroadcastReceiver() {


   override fun onReceive(context: Context, intent: Intent) {

       Log.d("KeepLiveReceiver", "action = ${intent.action}")


       when(intent.action) {

           // 锁屏

           Intent.ACTION_SCREEN_OFF -> {

               KeepLiveManager.startKeepLiveActivity(context)

           }


           // 解锁

           Intent.ACTION_USER_PRESENT -> {

               KeepLiveManager.finishKeepLiveActivity()

           }

       }

   }

}

管理单例:

object KeepLiveManager {

   var keepLiveActivity: KeepLiveActivity? = null


   fun startKeepLiveActivity(context: Context) {

       val intent = Intent(context, KeepLiveActivity::class.java)

       intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK

       context.startActivity(intent)

   }


   fun finishKeepLiveActivity() {

       keepLiveActivity?.finish()

   }

}

注:由于锁屏、解锁的动作频率极高,该类广播在清单文件中注册无效,需要启动服务来注册广播,此部分代码和本章主题关系不大,就不贴代码了。思路就是:启动 APP 时,启动一个注册服务,在服务的 onCreate() 方法中注册广播,在 onDestory() 方法中注销广播。

以下是使用该方案保活前和保活后查看 oom_adj 的对比截图:

7a88c1bf9df4c60fda2129a21b6a62ed5b46db01

保活前

051d4f75b75e7e671373cd77276296f55040a295

保活后

可见,保活后在锁屏状态,将进程的 oom_adj 由原来的7提高到了 0 。

附:查看进程 oom_adj 的方法  


在命令行中使用以下两个命令


adb shell ps | grep  packageName

adb shell cat /proc/PID/oom_adj


如:

G:AndroidGithubKeepLive>adb shell

shell@armani:/ $ ps | grep com.cy.keeplive

u0_a3     5991  213   541548 29976 ffffffff 00000000 S com.cy.keeplive

shell@armani:/ $ cat /proc/5991/oom_adj
0

(2)利用 Notification 提升权限

通过 setForeground() 方法可以将后台 Service 设置为前台 Service,可以将服务进程优先级提升为与可见进程一致,这将有效提高进程的优先级,从而大大降低进程被kill的概率。

通过 setForeground() 将后台 Service 设置为前台 Service 时,必须在系统的通知栏发送一条通知,也就是说前台 Service 必须绑定一条可见的通知。

在通知栏发送一条通知,是用户可以感知到的,这可能会对用户造成一定的困扰。可以通过实现一个内部 Service,在外部和内部 Service 中同时发送具有相同 ID 的 Notifacation ,然后将内部 Service 结束。随着内部 Service 的结束,Notification 也会消失掉,但系统的优先级仍然提高了。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

   try {

       Notification notification = new Notification();

       if (Build.VERSION.SDK_INT < 18) {

           startForeground(NOTIFICATION_ID, notification);

       } else {

           startForeground(NOTIFICATION_ID, notification);

           // start InnerService

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

       }

   } catch (Throwable e) {

       e.printStackTrace();

   }


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

}

然后在内部 Service 中也启动一个相同 ID 的 Notifacation ,并调用 stopSelf() 方法,结束内部 Service:

@Override
public void onCreate() {

   super.onCreate();

   try {

       startForeground(NOTIFICATION_ID, new Notification());

   } catch (Throwable throwable) {

       throwable.printStackTrace();

   }

   stopSelf();

}

2、被 kill 后拉活

此类方法暂未实践,后续补充。暂时简单提一下前人研究的可行性方案,不过这类方案都多多少少存在限制条件或者版本兼容性问题。

(1)通过系统广播拉活

简单讲就是监听一些特定的系统广播,当系统发出这些广播时,即可相应事件拉活。

(2)利用第三方应用广播拉活

此方案和第1中方案类似,不同的时该方案接收第三方 TOP 应用广播。通过反编译第三方 TOP 应用(如 QQ、微信、支付宝等,以及个推、极光推送等推送 SDK ),找出它们外放的广播进行监听,响应相应广播事件拉活。

(3)利用系统Service机制拉活

将 Service 设置为 START_STICKY,利用系统机制在 Service 挂掉后拉活。

(4)双进程守护

通过双进程的 Service 相互绑定,在一个进程被 kill 时,另一个进程将其拉活。

(5)利用 JobScheduler 机制拉活

JobScheduler 允许在特定状态与特定时间间隔周期执行任务。可以利用它的这个特点完成保活的功能,效果类似开启一个定时器,与普通定时器不同的是其调度由系统完成。它是在 Android5.0 之后推出的,在 5.0 之前无法使用。

(6)利用 Native 进程拉活

利用 Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native 进程中立即对主进程进行拉活。

以上内容来自原文:https://yq.aliyun.com/articles/666425

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值