Служба переднего плана убивается 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 running 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 71

2 ответа:

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

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

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

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

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

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

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

adb shell dumpsys activity processes > tmp.txt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

для моих целей, используя контекст.BIND_AUTO_CREATE / контекст.BIND_IMPORTANT для Привязок действия к службе и контекста.BIND_AUTO_CREATE / контекст.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" вы увидите в разделе, показывающем OOM adj процессов, что ваш процесс в настоящее время находится на переднем плане из-за этой службы.