web-dev-qa-db-de.com

Vordergrunddienst wird von Oreo getötet

Ich habe einen Vordergrund-Service geschrieben, der für alle Betriebssystemversionen, die niedriger als Oreo sind, ordnungsgemäß funktioniert. Der Oreo-Anwendungsprozess wird nach 5 Minuten des Schließens beendet und die Anwendung wird aus den letzten Jahren entfernt.

Laut Android-Entwicklerdokumentation für Hintergrundausführungsbeschränkungen OS sollte keine Anwendung beenden, für die ein Vordergrunddienst ausgeführt wird, und eine Benachrichtigung wird im Benachrichtigungsfenster angezeigt.

Gemäß den Richtlinien zur Entwicklerdokumentation. Ich habe die folgenden Schritte befolgt, um den Vordergrunddienst zu starten.

  1. Der Vordergrunddienst wird mit der startForegroundService()-Methode gestartet
  2. Innerhalb von 5 Sekunden nach dem Start des Dienstes wird eine Benachrichtigung für den Dienst mit startForeground() angezeigt.
  3. Rückgabe START_STICKY von onStartCommand() der service

Dieses Problem tritt an folgenden Telefonen auf:

  1. OnePlus 5T
  2. Vivo
  3. Oppo
  4. Mi

Was ich versucht habe zu verhindern, dass der Vordergrunddienst zerstört wird?

  1. Deaktivieren Sie die Batterieoptimierung für die Anwendung, indem Sie den Systemdialogfeld __ anzeigen, in dem der Benutzer den Doze-Modus deaktiviert.

Was habe ich versucht, den Vordergrund-Dienst neu zu starten?

  1. Verwendet AlarmManager, um den Dienst von onTaskRemoved () ..__ neu zu starten. Bitte überprüfen Sie diesen Link für Details.

Nach meinem Verständnis haben diese Hersteller den AOSP angepasst und halten sich nicht an die OS-Richtlinien für die Ausführung des Vordergrunddienstes. Möglicherweise haben diese Hersteller dies getan, weil sie den Benutzern eine lange Akkulaufzeit gewähren. 

Vordergrund-Serviceklasse

    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)
        }

    }

Bitte teilen Sie Ihren Vorschlag, wenn Sie mit ähnlichen Problemen konfrontiert sind und eine Lösung dafür gefunden haben.

6
Sagar Trehan

Ich habe das Problem bei OnePlus analysiert, da ich mich in derselben Situation befinde wie Sie. Wie ich momentan sehe, gibt es keine Lösung. OnePlus folgt eindeutig einer schlechten Praxis.

Da sie den Quellcode, der Prozesse auf diese Weise abbricht, nicht veröffentlicht haben, habe ich OnePlus ROM heruntergeladen (ich wähle OnePlus 5T 5.1.5), extrahiere es, finde die .class, die dies tut (OnePlusHighPowerDetector.class in services.vdex), dekompilieren und versuchen herauszufinden, was los ist.

Eine Version dieser Klasse finden Sie hier (nicht von mir, und vielleicht ist es nicht dieselbe Version, die ich verwendet habe): https://github.com/joshuous/oneplus_blobs_decompiled/blob/master/com /Android/server/am/OnePlusHighPowerDetector.Java

Leider werden die wichtigsten Funktionen nicht erfolgreich dekompiliert. Wir können den Bytecode aber trotzdem analysieren. Folgendes habe ich gefunden:

  • OnePlus beendet Hintergrundprozesse (es scheint, dass es egal ist, ob es einen Vordergrunddienst hat oder nicht), ohne Gnade. Fast alle. Es spielt keine Rolle, wie wenig CPU-Ressourcen verbraucht werden. Meine App verwendet weniger als 1% und wird getötet.
  • Wenn sich die App in der Liste der letzten Apps befindet (bestimmt durch eine Liste von com_oneplus_systemui_recent_task_lockd_list), wird sie nicht beendet. So kann der Benutzer die App speichern, indem er sie anheftet. Aber es ist für sie unbequem.
  • Oneplus bietet eine Liste von Prozessen, die sie nicht beenden. Diese Liste befindet sich in oneplus-framework-res.apk/res/values/array.xml mit dem Schlüssel string-array name="backgroundprocess_detection_app_whitelist". Diese Liste enthält hauptsächlich Karten- und Fitnessanwendungen1.
  • Vielleicht gibt es noch andere Faktoren, die das Absterben eines Prozesses verhindern können. Ich habe das Problem nicht weiter analysiert. Wenn Sie Zeit haben, besuchen Sie OnePlusHighPowerDetector.Java.

Hier sind die Schritte zum Dekompilieren einer .vdex-Datei:

  • verwenden Sie Vdex Extractor , um eine .dex aus .vdex zu erstellen (möglicherweise müssen Sie die --ignore-crc-error-Option verwenden).
  • verwenden Sie JADX , um eine .dex zu dekompilieren (dies ist derzeit der beste Dekompiler meiner Meinung nach), oder verwenden Sie dex2jar , um eine .jar aus .dex zu erstellen, und verwenden Sie einen beliebigen Dekompilierer, um die .jar zu dekompilieren

1Rant: Dies zeigt, wie schlecht die aktuelle Situation ist. OnePlus, ist das wirklich die Lösung? Sie haben 10-15 Anwendungen ausgewählt, die im Hintergrund ausgeführt werden können, und Sie interessieren sich nicht für alle anderen? Wie kann man eine neue Fitness-/Karten-/Musikplayer-Anwendung erstellen, die auf Ihrem Gerät sicher funktioniert?

9
geza

verwenden Sie die startForeground(id, notification)-Methode in Ihrem Service.

Der Benutzer sollte wissen, dass etwas, das vom System nicht getötet werden kann, im Hintergrund arbeitet. Daher sollte das Android-System den Benutzer mit einer Benachrichtigung informieren, sodass der Benutzer genau weiß, was seine Batterie tötet.

Übrigens können Sie WakeLock verwenden.

 PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
 PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK, 
 TAG_FOR_DEBUG);
 wakeLock.acquire()

Aber lesen Sie vor der Verwendung von WakeLock .. Und vergessen Sie nicht, es zu deaktivieren, wenn Ihre Arbeit abgeschlossen ist.

Sie können die aktivierten Wecksperren mit dem Befehl adb Shell dumpsys power im Terminal überprüfen.

1
Viktor Vasyliev

Ich habe mehrere Stunden damit verbracht, dieses Problem zu lösen. Xiaomi-Telefon, Oreo. Ich habe Lösung, 2 Schritte:

  1. Xiaomi benötigt zusätzliche Berechtigungen: Einstellungen-> Berechtigungen-> Automatischer Start. Es gibt eine Liste von Anwendungen, die automatisch gestartet werden dürfen. BOOT_COMPLETED und START_STICKY reicht NICHT aus. Facebook, Outlook, Skype + Meine App ist hier aufgelistet. Ich weiß nicht, wie der Benutzer programmgesteuert um Erlaubnis gebeten wird. 

  2. Der Dienst wird neu erstellt, aber NICHT neu gestartet, auch wenn Sie START_STICKY zurückgeben. Nachdem Sie die App beendet haben (aus aktiven Apps streichen), wird onCreate erneut aufgerufen, jedoch NICHT beiStartCommand. Versuchen Sie es mit Log.d (). Ich habe die gesamte Logik nach onCreate EXCEPT verschoben, um die Benachrichtigung zu erstellen, startForeground () aufzurufen und START_STICKY zurückzugeben. Dies muss in onStartCommand () bleiben.

Die Batery-Optimierung muss auch für die Anwendung deaktiviert sein, war aber bereits in der Vorgängerversion von Android erforderlich.

Jetzt läuft mein Dienst weiter oder wird innerhalb weniger Sekunden mit 100% Erfolg wiederhergestellt.

1
Milan Švec

Ich hatte in meinem OnePlus3 das gleiche Problem für meine App. Dann bemerkte ich diese Zeilen in logcat, jedes Mal, wenn meine App und der Vordergrunddienst beendet wurden:

10-12 18:30:40.644  1439  1519 I OHPD    : [BgDetect]force stop com.mycompany.MyAndroidApp (uid 10905) level 0
10-12 18:30:40.645  1439  1519 I ActivityManager: Force stopping com.mycompany.MyAndroidApp appid=10905 user=0: from pid 1439
10-12 18:30:40.645  1439  1519 I ActivityManager: Killing 23139:com.mycompany.MyAndroidApp/u0a905 (adj 200): stop com.mycompany.MyAndroidApp
10-12 18:30:40.647  1439  1519 W ActivityManager: Scheduling restart of crashed service com.mycompany.MyAndroidApp/md55852635cfc9dced970aa39ae09e74ead.MyForegroundService in 1000ms
10-12 18:30:40.651  1439  1519 I ActivityManager:   Force finishing activity ActivityRecord{a5c8d39 u0 com.mycompany.MyAndroidApp/md55852635cfc9dced970aa39ae09e74ead.MainActivity t3108}
10-12 18:30:40.655  1439  1519 I ActivityManager:   Force stopping service ServiceRecord{6052f94 u0 com.mycompany.MyAndroidApp/md55852635cfc9dced970aa39ae09e74ead.MyForegroundService}
10-12 18:30:40.660  1439  1519 I OHPD    : [BgDetect]chkExcessCpu level: 1 doKills: true critical false uptime: 300328
10-12 18:30:40.710  1439  8213 I WindowManager: WIN DEATH: Window{c381342 u0 com.mycompany.MyAndroidApp/md55852635cfc9dced970aa39ae09e74ead.MainActivity}

Dann durchsuche ich das Internet nach den Schlüsselwörtern 'OHPD: [BgDetect] chkExcessCpu: 1 doKills: true' brachte mich dazu SO Antwort:

Verhindern Sie, dass der Hintergrunddienst aufgrund von "Erkennung übermäßiger CPU-Leistung bei gegabeltem Prozess" abbricht.

Wie in dieser Antwort und im GitHub-Problem vorgeschlagen, verhinderte das Sperren/Anheften meiner App, dass Oxygen OS meine App (MainActivity und Forground Service) beendet.

0
Jagan

führen Sie in oneplus 6t diesen Befehl adb aus

einstellung put system com_oneplus_systemui_recent_task_lockd_list {com.topjohnwu.magisk/a.c # 0} {com.mycompany.MyAndroidApp/com.mycompany.MyAndroidApp.MainActivity # 0}

verhindern, dass com.topjohnwu.magisk und com.mycompany.MyAndroidApp getötet werden

0
LiSong Xue