Служба переднего плана убита Android

обновление: Я не нашел верного решения проблемы. Что я придумал способ автоматического переподключения к предыдущему устройство Bluetooth любое соединение потеряно. Это не идеально, но, кажется, работает довольно хорошо. Я хотел бы услышать еще какие-либо предложения по этому поводу.

у меня такая же проблема, как и в этом вопросе:обслуживание будучи убитым пока держащ замок пробуждения и после называя startForeground включая устройство (ASUS Transformer), время до остановки службы (30-45 минут), использование блокировки пробуждения, использование startForeground () и тот факт, что проблема не возникает, если приложение открыто, когда экран гаснет.

мое приложение поддерживает соединение bluetooth с другим устройством и отправляет данные между ними, поэтому оно должно быть активным все время для прослушивания данных. Пользователь может запускать и останавливать службу по желанию, и в факт это единственный способ, который я реализовал, чтобы запустить или остановить службу. После перезапуска службы соединение bluetooth с другим устройством будет потеряно.

согласно ответу в связанном вопросе, startForeground ()"уменьшает вероятность гибели службы, но не предотвращает ее". Я понимаю, что это так, однако я видел много примеров других приложений, которые не имеют этой проблемы (Tasker, например).

полезность моего приложения будет значительно сокращен без возможности запуска службы до тех пор, пока не будет остановлен пользователем. Есть ли способ избежать этого???

Я вижу это в моем logcat всякий раз, когда служба остановлена:

ActivityManager: No longer want com.howettl.textab (pid 32321): hidden #16
WindowManager: WIN DEATH: Window{40e2d968 com.howettl.textab/com.howettl.textab.TexTab paused=false
ActivityManager: Scheduling restart of crashed service com.howettl.textab/.TexTabService in 5000ms

EDIT: я также должен отметить, что это, похоже, не происходит на другом устройстве, к которому я подключен: HTC Legend работает Cyanogen

EDIT: вот результат adb shell dumpsys activity services:

* ServiceRecord{40f632e8 com.howettl.textab/.TexTabService}

intent={cmp=com.howettl.textab/.TexTabService}

packageName=com.howettl.textab

processName=com.howettl.textab

baseDir=/data/app/com.howettl.textab-1.apk

resDir=/data/app/com.howettl.textab-1.apk

dataDir=/data/data/com.howettl.textab

app=ProcessRecord{40bb0098 2995:com.howettl.textab/10104}

isForeground=true foregroundId=2 foregroundNoti=Notification(contentView=com.howettl.textab/0x1090087 vibrate=null,sound=null,defaults=0x0,flags=0x6a)

createTime=-25m42s123ms lastActivity=-25m42s27ms

 executingStart=-25m42s27ms restartTime=-25m42s124ms

startRequested=true stopIfKilled=false callStart=true lastStartId=1

Bindings:

* IntentBindRecord{40a02618}:

  intent={cmp=com.howettl.textab/.TexTabService}

  binder=android.os.BinderProxy@40a9ff70

  requested=true received=true hasBound=true doRebind=false

  * Client AppBindRecord{40a3b780 ProcessRecord{40bb0098 2995:com.howettl.textab/10104}}

    Per-process Connections:

      ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}

All Connections:

  ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}

и выход adb shell dumpsys activity:

* TaskRecord{40f5c050 #23 A com.howettl.textab}

numActivities=1 rootWasReset=false

affinity=com.howettl.textab

intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.howettl.textab/.TexTab}

realActivity=com.howettl.textab/.TexTab

lastActiveTime=4877757 (inactive for 702s)

* Hist #1: ActivityRecord{40a776c8 com.howettl.textab/.TexTab}

    packageName=com.howettl.textab processName=com.howettl.textab

    launchedFromUid=2000 app=ProcessRecord{40bb0098 2995:com.howettl.textab/10104}

    Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.howettl.textab/.TexTab }

    frontOfTask=true task=TaskRecord{40f5c050 #23 A com.howettl.textab}

    taskAffinity=com.howettl.textab

    realActivity=com.howettl.textab/.TexTab

    base=/data/app/com.howettl.textab-1.apk/data/app/com.howettl.textab-1.apk data=/data/data/com.howettl.textab

    labelRes=0x7f060000 icon=0x7f020000 theme=0x0

    stateNotNeeded=false componentSpecified=true isHomeActivity=false

    configuration={ scale=1.0 imsi=0/0 loc=en_CA touch=3 keys=2/1/1 nav=1/2 orien=L layout=0x10000014 uiMode=0x11 seq=6}

    launchFailed=false haveState=true icicle=Bundle[mParcelledData.dataSize=1644]

    state=STOPPED stopped=true delayedResume=false finishing=false

    keysPaused=false inHistory=true visible=false sleeping=true idle=true

    fullscreen=true noDisplay=false immersive=false launchMode=2

    frozenBeforeDestroy=false thumbnailNeeded=false

    connections=[ConnectionRecord{40a76920 com.howettl.textab/.TexTabService:@40b998b8}]

...

Proc #15: adj=prcp /F 40e75070 959:android.process.acore/10006 (provider)

          com.android.providers.contacts/.ContactsProvider2<=Proc{40bb0098 2995:com.howettl.textab/10104}

Proc #16: adj=bak+2/F 40bb0098 2995:com.howettl.textab/10104 (foreground-service)

они, кажется, показывают, что служба работает на переднем плане.

2 ответов


Okey dokey. Я прошел через ад и вернулся к этой проблеме. Вот как действовать дальше. Есть жуки. В этой публикации описывается, как анализировать ошибки в реализации и обходить проблемы.

В общем, вот как все должно работать. Запущенные службы будут регулярно очищаться и прекращаться каждые 30 минут или около того. Службы, которые хотят остаться в живых дольше, чем это, должны вызвать службу.startForeground, который помещает уведомление в уведомление бар, так что пользователи знают, что ваш сервис постоянно работает и потенциально сосать срок службы батареи. Только 3 процесса обслуживания могут назначать себя в качестве служб переднего плана в любой момент времени. Если существует более трех служб переднего плана, Android выдвинет самую старую службу в качестве кандидата на очистку и прекращение.

к сожалению, в Android есть ошибки в отношении приоритизации услуг переднего плана, которые запускаются различными комбинациями услуг флаги привязки. Даже если вы правильно назначили свою службу в качестве службы переднего плана, Android может прекратить вашу службу в любом случае, если какие-либо подключения к службам в вашем процессе когда-либо были сделаны с определенными комбинациями флагов привязки. Подробности приведены ниже.

обратите внимание, что очень мало услуг должны быть на переднем плане услуг. Как правило, вам нужно только быть сервисом переднего плана, если у вас есть постоянно активное или длительное подключение к Интернету, которое может быть включено и выключено или отменено пользователями. Примеры служб, которым требуется статус переднего плана: серверы UPNP, длительные загрузки очень больших файлов, синхронизация файловых систем по wi-fi и воспроизведение музыки.

если вы просто опрашиваете иногда или ждете системных широковещательных приемников или системных событий, Вам было бы лучше разбудить свою службу по таймеру или в ответ на широковещательные приемники, а затем позволить вашей службе умереть после завершения. Это как-конструированное поведение для сервисы. Если вы просто обязаны остаться в живых, читайте дальше.

проверив флажки на хорошо известных требованиях(например, вызов службы.startForeground), следующее место для просмотра-флаги, которые вы используете в контексте.bindService звонки. Флаги, используемые для привязки, влияют на приоритет целевого процесса обслуживания различными неожиданными способами. В частности, использование определенных флагов привязки может привести к тому, что Android неправильно понизит ваш сервис переднего плана до обычной службы. Код, используемый для назначения приоритета процесса была довольно сильно перемешана. Примечательно, что в API 14+ есть изменения, которые могут вызвать ошибки при использовании старых флагов привязки; и есть определенные ошибки в 4.2.1.

ваш друг во всем этом-утилита sysdump, которая может быть использована, чтобы выяснить, какой приоритет менеджер действий назначил вашему процессу обслуживания, и определить случаи, когда он назначил неправильный приоритет. Запустите службу, а затем выполните следующую команду из командная строка на главном компьютере:

процессы активности dumpsys оболочки adb > tmp.txt

используйте блокнот (не wordpad/write) для изучения содержимого.

сначала убедитесь, что вам удалось успешно запустить службу в состоянии переднего плана. Первый раздел файла dumpsys содержит описание свойств ActivityManager для каждого процесса. Найдите следующую строку, соответствующую вашему приложению в первом разделе dumpsys файл:

APP uid 10068 ProcessRecord{41937d40 2205:tunein.service / u0a10068}

убедитесь, что foregroundServices=true в следующем разделе. Не беспокойтесь о скрытых и пустых настройках; они описывают состояние действий в процессе и, похоже, не особенно актуальны для процессов со службами в них. Если foregroundService не соответствует истине,необходимо вызвать службу.startForeground, чтобы сделать это правдой.

следующее, что вы нужно посмотреть раздел в конце файла под названием " список процессов LRU (сортировка по oom_adj):". Записи в этом списке позволяют определить, действительно ли Android классифицировал ваше приложение как службу переднего плана. Если ваш процесс находится в нижней части этого списка, это главный кандидат на полное уничтожение. Если ваш процесс находится в верхней части списка, он практически неразрушим.

давайте посмотрим на строку в этой таблице:

  Proc #31: adj=prcp /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)

это пример службы переднего плана, которая сделала все правильно. Ключевое поле здесь-поле " adj=". Это указывает на приоритет, который ваш процесс был назначен ActivityManagerService после того, как все было сказано. Вы хотите, чтобы это было "adj=prcp" (видимая служба переднего плана); или "adj=vis" (видимый процесс с активностью) или "fore" (процесс с активностью переднего плана). Если это " adj=svc "(процесс обслуживания) или" adj=svcb " (устаревшая служба?), или " adj=bak "(пустой фоновый процесс), затем ваш процесс является вероятным кандидатом на прекращение и будет прекращаться не реже, чем каждые 30 минут, даже если нет никакого давления на восстановление памяти. Остальные флаги в строке-это в основном диагностическая отладочная информация для инженеров Google. Решения о прекращении принимаются на основании полей adj. Вкратце, /FS указывает службу переднего плана; /FA указывает процесс переднего плана с активностью. B указывает справочную службу. Метка в конце указывает на общее правило в соответствии с которым этому процессу был присвоен приоритет. Обычно он должен соответствовать полю adj=; но значение adj= может быть скорректировано вверх или вниз в некоторых случаях из-за флагов привязки на активных привязках с другими службами или действиями.

если вы споткнулись об ошибку с флагами привязки, строка dumpsys будет выглядеть так:

  Proc #31: adj=bak /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)

обратите внимание, как значение поля adj неправильно установлено в " adj=bak "(пустой фоновый процесс), что примерно переводится как " пожалуйста пожалуйста, прекратите меня сейчас, чтобы я мог закончить это бессмысленное существование " для целей процесса очистки. Также обратите внимание на флаг (FG-service) в конце строки, который указывает, что "правила forground service использовались для определения параметра "adj". Несмотря на то, что были использованы правила FG-сервиса, этому процессу была присвоена настройка adj "bak", и он долго не проживет. Проще говоря, это ошибка.

таким образом, цель состоит в том, чтобы гарантировать, что ваш процесс всегда получает "adj=prcp" (или лучше.) И метод для достижения этой цели-настроить флаги привязки, пока вам не удастся избежать ошибок в назначении приоритета.

вот ошибки, о которых я знаю. (1) если какая-либо служба или действие когда-либо были привязаны к службе с использованием контекста.BIND_ABOVE_CLIENT, вы рискуете, что параметр adj= будет понижен до "bak", даже если эта привязка больше не активна. Это особенно верно, если у вас также есть привязка между службами. Явная ошибка в источниках 4.2.1. (2) Определенно никогда не используйте bind_above_client для привязки службы к службе. Не используйте его и для соединений activity-to-service. Флаг, используемый для реализации поведения BIND_ABOVE_CLIENT, по-видимому, устанавливается на основе каждого процесса, а не на основе каждого соединения, поэтому он вызывает ошибки с привязками службы к службе, даже если нет активной привязки активности к службе с набором флагов. Также, по-видимому, возникают проблемы с установлением приоритета, когда в процессе есть несколько служб, с служб привязки. Использование Контекста.Кажется, что помогает bind_waive_priority (API 14) в привязках службы к службе. Контекст.Bind_important кажется более или менее хорошей идеей при привязке от действия к сервису. Это повышает приоритет вашего процесса на одну ступеньку, когда деятельность находится на переднем плане, не причиняя никакого видимого вреда, когда деятельность приостановлена или закончена.

но в целом стратегия заключается в настройке флагов bindService до тех пор, пока sysdump не укажет что ваш процесс получил правильный приоритет.

для моих целей, используя контекст.Bind_auto_create / Context.BIND_IMPORTANT для Привязок Activity-to-service и контекста.Bind_auto_create / Context.Bind_waive_priority для Привязок службы к службе, похоже, делает правильную вещь. Ваш пробег может отличаться.

мое приложение довольно сложное: две фоновые службы, каждая из которых может независимо содержать состояния службы переднего плана, плюс третья, которая также может занять передний план состояние службы; две службы связываются друг с другом условно; третья связывается с первой, всегда. Кроме того, действия выполняются в отдельном процессе (делает анимацию более плавной). Выполнение действий и служб в одном и том же процессе, казалось, не имело никакого значения.

реализация правил для процессов очистки, (и исходный код, используемый для создания содержимого файлов sysdump) можно найти в основном файле android

frameworks\base\services\java\com\android\server\am\ActivityManagerService.java.

Бон шанс.

PS: вот интерпретация строк sysdump для Android 5.0. Я с ними не работал, так что делайте с ними, что хотите. Я считаю, что вы хотите, чтобы 4 был " A "или" S", а 5 - " IF " или "IB", а 1-как можно ниже (возможно, ниже 3, поскольку только 3 три процесса службы переднего плана активны в конфигурации по умолчанию).

Example:
   Proc # : prcp  F/S/IF trm: 0 31719: neirotech.cerebrum.attention:blePrcs/u0a77 (fg-service)

Format:
   Proc # {1}: {2}  {3}/{4}/{5} trm: {6} {7}: {8}/{9} ({10}

1: Order in list: lower is less likely to get trimmed.

2: Not sure.

3:
    B: Process.THREAD_GROUP_BG_NONINTERACTIVE
    F: Process.THREAD_GROUP_DEFAULT

4:
    A: Foreground Activity
    S: Foreground Service
    ' ': Other.

5:
    -1: procState = "N ";
        ActivityManager.PROCESS_STATE_PERSISTENT: procState = "P ";
    ActivityManager.PROCESS_STATE_PERSISTENT_UI:procState = "PU";
    ActivityManager.PROCESS_STATE_TOP: procState = "T ";
    ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND: procState = "IF";
    ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND: procState = "IB";
    ActivityManager.PROCESS_STATE_BACKUP:procState = "BU";
    ActivityManager.PROCESS_STATE_HEAVY_WEIGHT: procState = "HW";
    ActivityManager.PROCESS_STATE_SERVICE: procState = "S ";
    ActivityManager.PROCESS_STATE_RECEIVER: procState = "R ";
    ActivityManager.PROCESS_STATE_HOME: procState = "HO";
    ActivityManager.PROCESS_STATE_LAST_ACTIVITY: procState = "LA";
    ActivityManager.PROCESS_STATE_CACHED_ACTIVITY: procState = "CA";
    ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT: procState = "Ca";
    ActivityManager.PROCESS_STATE_CACHED_EMPTY: procState = "CE";

{6}: trimMemoryLevel

{8} Process ID.
{9} process name
{10} appUid 

Если он говорит "больше не хочу..."тогда в этом процессе нет активной службы, которая в настоящее время находится в состоянии startForeground (). Убедитесь, что ваш призыв к тому, что на самом деле преуспеть-что вы видите запись, нет сообщений в журнале в этот момент жаловался на что-нибудь и т. д. Также используйте "adb shell dumpsys activity services", чтобы посмотреть на состояние вашей службы и убедиться, что она действительно отмечена как передний план. Также, если это правильно на переднем плане тогда в выводе "adb shell dumpsys activity" вы увидите в разделе, показывающем Оом adj процессов, что ваш процесс в настоящее время находится на переднем плане из-за этой службы.