前台服务被奥利奥杀死 [英] Foreground service getting killed from Oreo

查看:40
本文介绍了前台服务被奥利奥杀死的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个前台服务,该服务适用于低于 Oreo 的所有操作系统版本.从 Oreo 应用程序关闭并从最近的应用程序中删除 5 分钟后被终止.

I have written a foreground service which is working properly for all OS version lower than Oreo. From Oreo application process is getting killed after 5 minutes of closing and removing the application from recents.

根据 后台执行限制的 android 开发者文档,操作系统不应终止正在运行前台服务且通知显示在通知窗口中的应用程序.

As per android developer documentation for background execution limitations OS should not kill application for which a foreground service is running and notification is shown in notification window.

根据开发者文档指南.我按照以下步骤启动前台服务.

As per guidelines on developer documentation. I followed below steps to start foreground-service.

  1. 前台服务通过startForegroundService()方法启动
  2. 在启动服务后 5 秒内,使用 startForeground()
  3. 显示该服务的通知
  4. service
  5. onStartCommand()返回START_STICKY

我在以下手机上遇到了这个问题:

I am facing this issue on following phones:

  1. 一加 5T
  2. 体内
  3. OPPO

我试图防止前台服务被破坏的方法是什么?

What I tried to prevent foreground-service from being destroyed?

  1. 禁用电池优化通过展示申请系统对话框给用户以禁用打盹模式.
  1. Disable the battery optimization for the application by showing system dialog to user to disable doze mode.

我试图重新启动前台服务?

What I tried to restart the foreground-service?

  1. 使用 AlarmManager 从 onTaskRemoved() 重新启动服务.请查看此链接了解详情.
  1. Used AlarmManager to restart the service from onTaskRemoved(). Please check this link for details.

据我了解,这些制造商定制了 AOSP,并且不遵守允许前台服务运行的操作系统准则.可能这些制造商这样做是因为为用户提供了较长的电池寿命.

As per my understanding these manufacturers have customized the AOSP and are not respecting the OS guidelines for allowing foreground service to run. May be these manufacturers have done this because of giving long battery life time to users.

前台服务类

    class DataCaptureService : Service() {

        private var isServiceStarted = false

        override fun onBind(intent: Intent?): IBinder? {
            return null
        }

override fun onCreate() {
        super.onCreate()
        wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run {
                    newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakelockTag123").apply {
                        acquire()
                    }
                }
    }


        override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            val serviceAction = intent?.action
            LogUtils.logD("OnStartCommand(). Action=$serviceAction")
            if (Constants.INTENT.ACTION_STOP_SERVICE == serviceAction) {
                LogUtils.logD("Stopping data capture service")
                stopForeground(true)
                stopSelf()
            } else if (Constants.INTENT.ACTION_START_SERVICE == serviceAction && !isServiceStarted) {
                LogUtils.logD("Starting data capture service")
                isServiceStarted = true
                // Here showing notification using a utility method (startForeground(id, notification))
                createNotification(this)
                // Doing some stuff here
                ----------------------
                //
            }
            return START_STICKY
        }

        override fun onDestroy() {
            super.onDestroy()
            if (isServiceStarted) {
                LogUtils.logD("onDestroy of DataCaptureService method is invoked")
                // Doing some stuff here
                ----------------------
                //
                isServiceStarted = false
                if (wakeLock.isHeld) {
                    wakeLock.release()
                }
            }
        }

        override fun onTaskRemoved(rootIntent: Intent?) {
            LogUtils.logD("onTaskRemoved of DataCaptureService method is invoked")
            ensureServiceStaysRunning()
            super.onTaskRemoved(rootIntent)
        }

        private fun ensureServiceStaysRunning() {
            val restartAlarmInterval = 60 * 1000
            val resetAlarmTimer = 30 * 1000L
            // From this broadcast I am restarting the service
            val restartIntent = Intent(this, ServiceRestartBroadcast::class.java)
            restartIntent.action = "RestartedViaAlarm"
            restartIntent.flags = Intent.FLAG_RECEIVER_FOREGROUND
            val alarmMgr = getSystemService(Context.ALARM_SERVICE) as AlarmManager
            val restartServiceHandler = @SuppressLint("HandlerLeak")
            object : Handler() {
                override fun handleMessage(msg: Message) {
                    val pendingIntent = PendingIntent.getBroadcast(applicationContext, 87, restartIntent, PendingIntent.FLAG_CANCEL_CURRENT)
                    val timer = System.currentTimeMillis() + restartAlarmInterval
                    val sdkInt = Build.VERSION.SDK_INT
                    if (sdkInt < Build.VERSION_CODES.KITKAT)
                        alarmMgr.set(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
                    else if (Build.VERSION_CODES.KITKAT <= sdkInt && sdkInt < Build.VERSION_CODES.M)
                        alarmMgr.setExact(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
                    else if (sdkInt >= Build.VERSION_CODES.M) {
                        alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timer, pendingIntent)
                    }
                    sendEmptyMessageDelayed(0, resetAlarmTimer)
                    stopSelf()
                }
            }
            restartServiceHandler.sendEmptyMessageDelayed(0, 0)
        }

    }

如果您遇到过类似的问题并设法找到解决方案,请分享您的建议.

Please share your suggestion if you have faced similar type of issue and managed to find a solution for this.

推荐答案

我已经在 OnePlus 上分析过这个问题,因为我和你的情况一样.正如我目前所见,没有解决方案.OnePlus 显然遵循了不好的做法.

I've analyzed the issue on OnePlus, as I'm in the same situation as you. As I see currently, there is no solution. OnePlus clearly follows a bad practice.

由于他们没有发布以这种方式杀死进程的源代码,我下载了一个OnePlus ROM(我选择了OnePlus 5T 5.1.5),解压缩它,找到执行此操作的.class(服务中的OnePlusHighPowerDetector.class.vdex),反编译它,并试图找出发生了什么.

As they haven't released the source code which kills processes in this manner, I downloaded a OnePlus ROM (I choose OnePlus 5T 5.1.5), extract it, find the .class which does this (OnePlusHighPowerDetector.class in services.vdex), decompile it, and tried to find out what's going on.

你可以在这里找到这个类的一个版本(不是我写的,可能和我用的版本不一样):https://github.com/joshuous/oneplus_blobs_decompiled/blob/master/com/android/server/am/OnePlusHighPowerDetector.java

You can find a version of this class here (it is not by me, and maybe it is not the same version that I've used): https://github.com/joshuous/oneplus_blobs_decompiled/blob/master/com/android/server/am/OnePlusHighPowerDetector.java

不幸的是,最重要的函数没有成功反编译.但无论如何我们都可以分析字节码.这是我发现的:

Unfortunately, the most important functions aren't decompiled successfully. But we can analyze the bytecode anyway. Here's what I've found:

  • OnePlus 会毫不留情地杀死后台进程(似乎它是否有前台服务并不重要).几乎所有的人.使用多少 CPU 资源并不重要.我的应用使用了不到 1% 的资源,然后就被杀死了.
  • 如果应用被固定在最近的应用列表中(由com_oneplus_systemui_recent_task_lockd_list 列表确定),它不会被杀死.因此,用户可以通过固定来保存应用程序.但这对他们来说很不方便.
  • Oneplus 提供了一个进程列表,它们不会杀死这些进程.此列表位于 oneplus-framework-res.apk/res/values/array.xml 中,键为 string-array name="backgroundprocess_detection_app_whitelist".此列表主要包含地图和健身应用1.
  • 也许还有其他因素可以挽救一个进程被杀死,我没有进一步分析这个问题.如果您有时间,请查看 OnePlusHighPowerDetector.java.
  • OnePlus kills background processes (it seems that it doesn't matter whether it has a foreground service or not) without mercy. Almost all of them. It doesn't really matter, how little CPU resources are used. My app uses less than 1%, and it gets killed.
  • If the app is pinned in the recent app list (determined by a list of com_oneplus_systemui_recent_task_lockd_list), it doesn't get killed. So, the user can save the app by pinning it. But it is inconvenient for them.
  • Oneplus provides a list of processes, which they don't kill. This list is in oneplus-framework-res.apk/res/values/array.xml, with the key string-array name="backgroundprocess_detection_app_whitelist". This list mostly contains map and fitness applications1.
  • Maybe there are other factors which can save a process being killed, I haven't analyzed the issue further. If you have the time, check out OnePlusHighPowerDetector.java.

以下是反编译 .vdex 文件所需的步骤:

Here are the steps needed to decompile a .vdex file:

  • 使用 Vdex Extractor 从 .vdex 创建 .dex(也许您需要使用--ignore-crc-error 选项)
  • 使用 JADX 反编译 .dex(我认为这是目前最好的反编译器),或者使用 dex2jar 从 .dex 创建一个 .jar,并使用任何反编译器反编译 .jar
  • use Vdex Extractor to create a .dex from .vdex (maybe you'll need to use the --ignore-crc-error option)
  • use JADX to decompile a .dex (this is currently the best decompiler in my opinion), or use dex2jar to create a .jar from .dex, and use any decompiler to decompile the .jar

1Rant:这表明当前情况有多糟糕.OnePlus,这真的是解决方案吗?您选择了 10-15 个可以在后台运行的应用程序,而您不关心所有其他应用程序吗?如何创建一个新的健身/地图/音乐播放器应用程序,在您的设备上安全运行?

1Rant: this shows how bad the current situation is. OnePlus, is this really the solution? You've chosen 10-15 applications, which can run in the background, and you don't care about all the other ones? How can one create a new fitness/map/music player application, which works safely on your device?

这篇关于前台服务被奥利奥杀死的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆