web-dev-qa-db-ja.com

前景サービスがOreoから殺される

私は、Oreoより前のすべてのOSバージョンで適切に動作するフォアグラウンドサービスを作成しました。 Oreoから、アプリケーションを閉じて、最近のアプリケーションを削除してから5分後にプロセスが強制終了されます。

Androidの開発者向けドキュメント バックグラウンド実行制限 OSは、フォアグラウンドサービスが実行され、通知ウィンドウに通知が表示されているアプリケーションを強制終了してはなりません。

開発者向けドキュメントのガイドラインに従って。以下の手順に従って、フォアグラウンドサービスを開始しました。

  1. フォアグラウンドサービスはstartForegroundService()メソッドで開始されます
  2. サービス開始後5秒以内に、startForeground()を使用してサービスの通知が表示されます
  3. serviceonStartCommand()からSTART_STICKYを返します

次の電話でこの問題に直面しています。

  1. OnePlus 5T
  2. Vivo
  3. オッポ

フォアグラウンドサービスが破壊されるのを防ぐために何を試みましたか?

  1. システムダイアログをユーザーに見せて居眠りモードを無効にすることで、アプリケーションの バッテリー最適化 を無効にします.

フォアグラウンドサービスを再起動しようとしましたか?

  1. AlarmManagerを使用して、onTaskRemoved()からサービスを再起動しました。詳細については、 このリンク を確認してください。

私の理解では、これらのメーカーはAOSPをカスタマイズしており、フォアグラウンドサービスの実行を許可するためのOSガイドラインを尊重していません。これらのメーカーは、ユーザーに長いバッテリー寿命を与えているため、これを行っている可能性があります。

フォアグラウンドサービスクラス

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

    }

同様のタイプの問題に直面し、この解決策を見つけることができた場合は、提案を共有してください。

10
Sagar Trehan

私はあなたと同じ状況にいるので、OnePlusの問題を分析しました。現在見ているように、解決策はありません。 OnePlusは明らかに悪い慣習に従っています。

この方法でプロセスを強制終了するソースコードをリリースしていないため、OnePlus ROM(OnePlus 5T 5.1.5を選択)をダウンロードし、それを抽出し、これを行う.classを見つけます。 (services.vdexのOnePlusHighPowerDetector.class)、それを逆コンパイルし、何が起こっているのかを見つけようとしました。

このクラスのバージョンはここで見つけることができます(私によるものではなく、おそらく私が使用したバージョンとは異なります): https://github.com/joshuous/oneplus_blobs_decompiled/blob/master /com/Android/server/am/OnePlusHighPowerDetector.Java

残念ながら、最も重要な関数は正常に逆コンパイルされません。しかし、とにかくバイトコードを分析できます。私が見つけたものは次のとおりです。

  • 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をご覧ください。

.vdexファイルを逆コンパイルするために必要な手順は次のとおりです。

  • Vdex Extractor を使用して、.vdexから.dexを作成します(おそらく--ignore-crc-errorオプション)
  • [〜#〜] jadx [〜#〜] を使用して.dexを逆コンパイルします(これは現在、私の意見では最高の逆コンパイラーです)、または dex2jar を使用して.dexを作成します。 .dexからjarし、任意のデコンパイラを使用して.jarを逆コンパイルします

1暴言:これは、現在の状況がどれほど悪いかを示しています。 OnePlus、これは本当に解決策ですか?バックグラウンドで実行できる10〜15個のアプリケーションを選択しましたが、他のすべてのアプリケーションを気にしませんか?デバイスで安全に動作する新しいフィットネス/マップ/音楽プレーヤーアプリケーションを作成するにはどうすればよいですか?

16
geza

この問題を解決するのに数時間費やしました。 Xiaomi電話、オレオ。私には解決策があります、2つのステップ:

  1. Xiaomiには追加の許可が必要です。設定->許可->自動起動。自動的に開始できるアプリケーションのリストがあります。 BOOT_COMPLETEDとSTART_STICKYでは不十分です。 Facebook、Outlook、Skype +私のアプリがここにリストされています。ユーザーにプログラムでこの許可を与えるように依頼する方法がわかりません。

  2. サービスは再作成されますが、START_STICKYを返しても再起動されません。アプリを強制終了(実行中のアプリからスワイプアウト)すると、onCreateが再度呼び出されますが、onStartCommandは呼び出されません。 Log.d()を試してみてください。通知を作成し、startForeground()を呼び出してSTART_STICKYを返す以外のすべてのロジックをonCreateに移動しました。これはonStartCommand()に残っている必要があります。

アプリケーションのBatery最適化も無効にする必要がありますが、以前のバージョンのAndroidで既に必要でした。

現在、私のサービスは数秒以内に実行を継続するか、100%成功して再作成されます。

3
Milan Švec

サービス内でstartForeground(id, notification)メソッドを使用します。

ユーザーは、システムによって殺されない何かがバックグラウンドで動作していることを知っている必要があります。そのため、Androidシステムは通知をユーザーに通知する必要があります。

ちなみにWakeLockを使用できます。

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

ただし、使用する前にWakeLockを読んでください。また、作業が終了したら無効にすることを忘れないでください。

Terminaladb Shell dumpsys powerコマンドを使用して、現在有効なウェイクロックを確認できます。

1
Viktor Vasyliev

私のアプリのOnePlus3でも同じ問題に直面しました。その後、アプリとフォアグラウンドサービスが強制終了されるたびに、logcatで次の行に気付きました。

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}

次に、キーワード「OHPD:[BgDetect] chkExcessCpu level:1 doKills:true」でインターネットを検索すると、このSO answer:

「フォークされたプロセスで過剰なCPUを検出する」ためにバックグラウンドサービスが強制終了されないようにする

その回答とGitHubの問題で示唆されているように、アプリをロック/ピン留めすると、Oxygen OSがアプリ(MainActivityおよびForground Service)を強制終了できなくなりました。

0
Jagan

oneplus 6tでは、このadbコマンドを実行します

設定putシステムcom_oneplus_systemui_recent_task_lockd_list {com.topjohnwu.magisk/a.c#0} {com.mycompany.MyAndroidApp/com.mycompany.MyAndroidApp.MainActivity#0}

com.topjohnwu.magiskおよびcom.mycompany.MyAndroidAppの強制終了を防ぎます

0
LiSong Xue