J'ai écrit un service de premier plan qui fonctionne correctement pour toutes les versions de système d'exploitation inférieures à Oreo. Le processus de demande de Oreo est éliminé après 5 minutes de fermeture et de suppression de la demande.
Selon la documentation pour les développeurs Android concernant les limitations d'exécution background , le système d'exploitation ne doit pas tuer les applications pour lesquelles un service de premier plan est en cours d'exécution et la notification s'affiche dans la fenêtre de notification.
Selon les directives de la documentation du développeur. J'ai suivi les étapes ci-dessous pour démarrer le service de premier plan.
startForegroundService()
startForeground()
START_STICKY
depuis onStartCommand()
sur service
Je suis confronté à ce problème sur les téléphones suivants:
Qu'est-ce que j'ai essayé d'empêcher la destruction du service de premier plan?
Qu'est-ce que j'ai essayé de redémarrer le service de premier plan?
AlarmManager
pour redémarrer le service à partir de onTaskRemoved () . Veuillez vérifier ce lien pour plus de détails.D'après ce que j'ai compris, ces fabricants ont personnalisé l'AOSP et ne respectent pas les directives du système d'exploitation permettant le fonctionnement du service de premier plan. Peut-être que ces fabricants ont agi de la sorte en donnant aux utilisateurs une longue durée de vie de la batterie.
Classe de service de premier plan
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)
}
}
Veuillez partager votre suggestion si vous avez rencontré le même type de problème et avez réussi à trouver une solution à ce problème.
J'ai analysé le problème sur OnePlus, car je suis dans la même situation que vous. Comme je le vois actuellement, il n'y a pas de solution. OnePlus suit clairement une mauvaise pratique.
Comme ils n’ont pas publié le code source qui tue les processus de cette manière, j’ai téléchargé un OnePlus ROM (j’ai choisi OnePlus 5T 5.1.5), l’extrais, je trouve le .class qui le fait (OnePlusHighPowerDetector.class services.vdex), décompilez-le et essayez de savoir ce qui se passe.
Vous pouvez trouver une version de cette classe ici (ce n'est pas de moi, et peut-être que ce n'est pas la même version que celle que j'ai utilisée): https://github.com/joshuous/oneplus_blobs_decompiled/blob/master/com /Android/server/am/OnePlusHighPowerDetector.Java
Malheureusement, les fonctions les plus importantes ne sont pas décompilées correctement. Mais on peut quand même analyser le bytecode. Voici ce que j'ai trouvé:
com_oneplus_systemui_recent_task_lockd_list
), elle n'est pas supprimée. Ainsi, l'utilisateur peut enregistrer l'application en l'épinglant. Mais c'est gênant pour eux.oneplus-framework-res.apk/res/values/array.xml
, avec la clé string-array name="backgroundprocess_detection_app_whitelist"
. Cette liste contient principalement des applications de carte et de fitness.1.Voici les étapes nécessaires pour décompiler un fichier .vdex:
--ignore-crc-error
)1Rant: cela montre à quel point la situation actuelle est mauvaise. OnePlus, est-ce vraiment la solution? Vous avez choisi 10-15 applications, qui peuvent être exécutées en arrière-plan, et vous ne vous souciez pas de toutes les autres? Comment créer une nouvelle application de fitness/carte/lecteur de musique qui fonctionne en toute sécurité sur votre appareil?
utilisez la méthode startForeground(id, notification)
dans votre service.
L'utilisateur doit savoir que quelque chose qui ne peut pas être tué par le système fonctionne en arrière-plan. Le système Android doit donc en informer l'utilisateur par une notification. Il sait donc exactement ce qui tue sa batterie.
En passant, vous pouvez utiliser WakeLock .
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PARTIAL_WAKE_LOCK,
TAG_FOR_DEBUG);
wakeLock.acquire()
Mais lisez à propos de WakeLock avant de l’utiliser ..__ Et n'oubliez pas de le désactiver lorsque votre travail est terminé.
Vous pouvez vérifier les verrous de sillage activés actuels à l’aide de la commande adb Shell dumpsys power
dans Terminal
J'ai passé plusieurs heures à résoudre ce problème. Xiaomi téléphone, Oreo. J'ai la solution, 2 étapes:
Xiaomi a besoin d'une autorisation supplémentaire: Paramètres-> Autorisations-> Démarrage automatique. Il existe une liste d'applications pouvant être démarrées automatiquement. BOOT_COMPLETED et START_STICKY ne suffisent pas. Facebook, Outlook, Skype + mon application est répertoriée ici. Je ne sais pas comment demander à l'utilisateur par programme d'accorder cette autorisation.
Le service est recréé mais NON redémarré, même si vous renvoyez START_STICKY. Après avoir supprimé l'application (supprimez les applications en cours d'exécution), onCreate est appelé à nouveau, mais PAS onStartCommand. Essayez Log.d () pour le voir. J'ai déplacé toute la logique dans onCreate EXCEPT en créant la notification, en appelant startForeground () et en renvoyant START_STICKY. Cela doit rester dans onStartCommand ().
L'optimisation de Batery doit également être désactivée pour l'application, mais elle était déjà requise par la version précédente d'Android.
Maintenant, mon service continue à fonctionner ou est recréé avec 100% de succès en quelques secondes.
J'ai rencontré le même problème dans mon OnePlus3 pour mon application. Ensuite, j'ai remarqué ces lignes dans logcat, chaque fois que mon application et mon service d'avant-plan étaient tués:
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}
Puis, recherchant sur Internet les mots-clés 'OHPD: [BgDetect] chkExcessCpu niveau: 1 doKills: true' m'a conduit à cette SO réponse:
Comme suggéré dans cette réponse et le problème de GitHub, verrouiller/épingler mon application a empêché Oxygen OS de tuer mon application (MainActivity and Forground Service).