Подтвердить что ты не робот

Наземное обслуживание, убитое 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}

  [email protected]

  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)

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Используйте блокнот (не WordPad/запись), чтобы изучить содержимое.

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

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

Убедитесь, что foregroundServices = true в следующем разделе. Не беспокойтесь о скрытых и пустых настройках; они описывают состояние деятельности в процессе и не кажутся особенно актуальными для процессов с услугами в них. Если foregroundService неверен, вам нужно вызвать Service.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) в конце строки, который указывает, что "правила наземной службы использовались для определения настройки" adj ". Несмотря на то, что правила fg-service были использованы, этому процессу была назначена установка" bak", и он не будет долго жить. Положительно, это ошибка.

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

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

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

Для моих целей, используя Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT для привязок к действию для обслуживания и Context.BIND_AUTO_CREATE | Контекст .BIND_WAIVE_PRIORITY для привязок сервисов к сервисам, кажется, делает правильные вещи. Ваш пробег может отличаться.

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

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

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 

Ответ 2

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