service进程——保活和拉起

落日映苍穹つ 2024-05-24 01:04 188阅读 0赞

存在问题

最近在做一个项目A,该项目A是已经是system app,但该App在内存不足、用户清理后台后,进程会死亡。为了保证A能一直处于运行状态,开发一个守护进程用于保活和拉起A。
需求:

  1. 在开机后,A不能自启动,保证设备快速开机运行
  2. 用户清理后台后,A能继续存活,以便接听实时通话
  3. 在应用关闭后,A能够保活
  4. 内存占用过大,系统释放内存后,A和service能存活
  5. 重启后,service能够自启动

理论知识准备

service讲解

service基础知识

判断APP处于前台还是后台

6种判断方法

进程优先级

Android系统尽量长时间保留应用进程,为了新建进程或运行更加重要的进程,系统会移除旧的进程,回收内存。系统根据重要层级结构中的优先级,优先清除重要性低的进程。

前台进程(Foreground process)

前台进程数量不多,只有在内存不足的情况下,系统才会终止他们。

  • 托管用户正在交互的Activity,已调用Activity的onResume()方法
  • 托管某个Service,后者绑定到用户正在交互的 Activity
  • 托管正在前台运行的Service服务,已调用startForeground()
  • 托管正执行一个生命周期回调的Service (onCreate() 、onStart()或onDestroy())
  • 托管正执行其onReceive()方法的BroadcastReceiver

可见进程(Visible process)

除非为了保证前台进程的运行,而不得已终止,系统不会终止可见进程。

  • 托管不在前台、但仍对用户可见的Activity已调用其onPause()方法。
  • 托管绑定到可见(或前台)Activity 的Service。

服务进程(Service process)

  • 正在运行 startService() 方法启动的服务,且不属于上述两个更高类别进程的进程。

系统尽量维持服务进程的运行,除非系统内存不足维护前台进程和可见进程的运行。

后台进程(Background process)

  • 进程持有一个用户不可见的activity,onStop()别调用,onDestory()没被调用,该进程为一个后台进程。

后台进程不影响用户的体验,系统为了前台进程、可见进程和服务进程,可任意杀死后台进程。

空进程(Empty process)

  • 不包含任何活动应用组件的进程

保留这类进程的目的用于缓存,以便缩短下一次在其中运行组件运行所需的启动时间。

常见的保活方案

  • 开启一个像素的Activity
  • 前台服务
    白色保活:启动前台服务使得进程的优先级提高为前台进程,但前台服务和通知绑定,在通知栏会显示,用户可能会删除通知。
    灰色保活:利用系统漏洞开启前台服务,去掉通知,用户感应不到。
  • 相互唤醒
    黑色保活:相互拉起,腾讯系列。
  • JobSheduler
  • 粘性服务
  • 双进程
    让两个进程互相保护,其中一个service被清理后,未被清理的进程重启该进程,甚至有多进程,
  • service设置成START_STICKY,被杀死5秒后会重启,startForegroundService将该进程设置为前台进程。
  • 加入白名单

解决方案

获得系统级权限

由于项目A已是system app,在AndroidManifest中添加android:sharedUserId=“android.uid.system”
通过设置同一个User id的使得多个应用可以运行在同一个进程中。而将sharedUserId设置成android.uid.system则可以将该应用和系统应用运行在同一进程中,于是乎便有了系统权限。

判断APP是否存活

  1. 获取系统所有的app信息,首先遍历所有的app
  2. 通过进程id去判断该进程是否存活,如果不存活,发送广播,如果存活,不处理。在BroadcastReceiver中,判断action,启动activity。

    //根据进程名判断进程是否运行,并返回pid

    1. public static int getPidByProcessName(Context context, String procName) {
    2. ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    3. List<ActivityManager.RunningAppProcessInfo> processInfoList = manager.getRunningAppProcesses();
    4. if(processInfoList!=null){
    5. for (ActivityManager.RunningAppProcessInfo processInfo : processInfoList) {
    6. LogUtils.d("Utils processName = " + processInfo.processName);
    7. if (procName.equals(processInfo.processName)) {
    8. LogUtils.d("Uitls pid = " + processInfo.pid);
    9. return processInfo.pid;
    10. }
    11. }
    12. }
    13. return -1;
    14. }

去除activiy界面

无界面的app(对于非系统的应用没有activity无法启动service),但可以使用主题@android:style/Theme.NoDisplay 来隐藏Activity达到无界面的app效果。

  1. <application
  2. android:icon="@mipmap/ic_launcher"
  3. android:label="@string/app_name"
  4. android:theme="@android:style/Theme.NoDisplay">

注意点:

  1. MyActivity extends 只能是activity,不能为其他的,比如AppCompatActivity(support_v4/v7,带actionbar或者toolbar)等主题与activity不搭导致app运行错误。
  2. 既然是隐藏的app,那么桌面图标和后台任务也不能让用户看到。经过测试验证,若不隐藏桌面图标和后台任务,点击后会出现无响应的问题,像是死机的样子。





    //桌面启动图标去除

在activity中重写onResume()方法,杀死Activity。

  1. @Override
  2. protected void onResume() {
  3. super.onResume();
  4. this.finish();
  5. }

守护进程

静态配置接收器

守护进程开机自启动

  1. <receiver
  2. android:name=".service.TestReceiver"
  3. android:enabled="true"
  4. android:exported="true">
  5. <intent-filter>
  6. <action android:name="android.intent.action.BOOT_COMPLETED"/>
  7. </intent-filter>
  8. </receiver>

广播接收器类的实现

Receiver中接受,并判断action

  1. public class TestReceiver extends BroadcastReceiver {
  2. public final static String TEST_ACTION_BOOT_COMPLETED="android.intent.action.BOOT_COMPLETED";
  3. @Override
  4. public void onReceive(Context context, Intent intent) {
  5. String action = intent.getAction();
  6. if(TEST_ACTION_BOOT_COMPLETED.equals(action)){
  7. Intent intentStart = new Intent(context, MainActivity.class);
  8. intentStart.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  9. context.startActivity(intentStart);
  10. }
  11. }
  12. }

Service

采用getPidByProcessName方法定期判断进程是否存活,如果存活不做处理;如果不存活,向进程A发送一个广播。
在进程A配置action,在收到广播后,拉起对应的Activity。

由于作者水平有限,文中若有不正确的地方,欢迎大家指出,若有任何问题,请在下方讨论。

发表评论

表情:
评论列表 (有 0 条评论,188人围观)

还没有评论,来说两句吧...

相关阅读

    相关 进程

    一、前言   说到进程保活,大家往往联想到hacking和“流氓”软件。这是一些不负责任的开发者滥用进程保活,导致了用户的反感和抵触情绪。实际上大部分软件是不需要常驻进程

    相关 Android后台进程

    1、为什么需要对进程进行保活 系统出于体验和性能上的考虑,app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来。打开的应用越多,后台缓存的进程也越多。在

    相关 Android实现进程方案解析

    众所周知,日活率是一款App的核心绩效指标,日活量不仅反应了应用的受欢迎程度,同时反应了产品的变现能力,进而直接影响盈利能力和企业估值。为了抢占市场,谁都不会放过任何一个可以提

    相关 TCP-机制

    保活机制:是一种在不影响数据流内容的情况下探测对方的方式。它是由一个保活计时器实现的。当计时器被激发, 连接端将发送一个保活探测(简称保活)报文 , 另一端接收报文的同时会发送