Обновление : я не нашел верного решения проблемы. Что я придумал, так это метод автоматического переподключения к предыдущему устройству Bluetooth в любое время, когда соединение потеряно. Это не идеально, но, похоже, работает неплохо. Я хотел бы услышать больше предложений по этому поводу.
У меня почти такая же проблема, как и в этом вопросе: служба убита при удерживании блокировки пробуждения и после вызова startForeground, включая устройство (Asus Transformer), время до остановки службы (30-45 минут), использование wake lock, использование startForeground () и тот факт, что проблема не возникает, если приложение открыто, когда экран гаснет.
Мое приложение поддерживает соединение Bluetooth с другим устройством и отправляет данные между ними, поэтому оно должно быть постоянно активным для прослушивания данных. Пользователь может запускать и останавливать службу по своему желанию, и фактически это единственный способ, который я реализовал для запуска или остановки службы. После перезапуска службы соединение Bluetooth с другим устройством теряется.
Согласно ответу на связанный вопрос, startForeground () «снижает вероятность того, что служба будет уничтожена, но не предотвращает это». Я понимаю, что это так, однако я видел много примеров других приложений, в которых нет этой проблемы (например, Tasker).
Полезность моего приложения будет значительно снижена без возможности запуска службы до остановки пользователем. Есть ли способ избежать этого ???
Я вижу это в моем журнале всякий раз, когда служба останавливается:
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
РЕДАКТИРОВАТЬ: Я также должен отметить, что этого не происходит на другом устройстве, к которому я подключен: HTC Legend с Cyanogen
РЕДАКТИРОВАТЬ: Вот результат 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)
Похоже, они показывают, что служба работает на переднем плане.
источник
Ответы:
Оки Доки. Я прошел через ад и вернулся к этой проблеме. Вот как действовать. Есть баги. В этой публикации описывается, как анализировать ошибки в реализации и обходить проблемы.
Подводя итог, вот как все должно работать. Запущенные службы будут регулярно очищаться и завершаться каждые 30 минут или около того. Службы, которые хотят работать дольше указанного срока, должны вызывать Service.startForeground, который помещает уведомление на панель уведомлений, чтобы пользователи знали, что ваша служба работает постоянно и потенциально расходует заряд батареи. Только 3 сервисных процесса могут назначать себя сервисами переднего плана в любой момент времени. Если существует более трех служб переднего плана, Android назначит самую старую службу в качестве кандидата на очистку и завершение.
К сожалению, в Android есть ошибки в отношении приоритезации служб переднего плана, которые запускаются различными комбинациями флагов привязки служб. Даже если вы правильно назначили свою службу в качестве службы переднего плана, Android в любом случае может прекратить работу вашей службы, если какие-либо подключения к службам в вашем процессе когда-либо были выполнены с определенными комбинациями флагов привязки. Подробности приведены ниже.
Обратите внимание, что очень немногие службы должны быть службами переднего плана. Как правило, вам нужно быть службой переднего плана, только если у вас есть постоянно активное или длительное подключение к Интернету какого-либо типа, которое может быть включено и выключено или отменено пользователями. Примеры служб, которым требуется статус переднего плана: серверы UPNP, длительная загрузка очень больших файлов, синхронизация файловых систем по Wi-Fi и воспроизведение музыки.
Если вы просто изредка опрашиваете или ждете приемников системных широковещательных сообщений или системных событий, вам лучше разбудить службу по таймеру или в ответ на приемники широковещательной рассылки, а затем позволить вашей службе умереть после завершения. Это стандартное поведение для сервисов. Если вы просто обязаны остаться в живых, читайте дальше.
Установив флажки для хорошо известных требований (например, при вызове Service.startForeground), следующее место, куда нужно обратить внимание, - это флаги, которые вы используете в вызовах Context.bindService. Флаги, используемые для привязки, влияют на приоритет целевого процесса службы множеством неожиданных способов. В частности, использование определенных флагов привязки может привести к тому, что Android неправильно понизит вашу службу переднего плана до обычной службы. Код, используемый для назначения приоритета процесса, был сильно переработан. Примечательно, что в API 14+ есть исправления, которые могут вызывать ошибки при использовании старых флагов привязки; и в 4.2.1 есть определенные ошибки.
Ваш друг во всем этом - служебная программа sysdump, с помощью которой можно выяснить, какой приоритет диспетчер операций назначил вашему процессу обслуживания, и выявить случаи, когда он назначил неверный приоритет. Установите и запустите свою службу, а затем введите следующую команду из командной строки на своем главном компьютере:
adb shell dumpsys activity процессы> tmp.txt
Используйте блокнот (не блокнот / запись), чтобы изучить содержимое.
Сначала убедитесь, что вам удалось успешно запустить службу в состоянии переднего плана. Первый раздел файла dumpsys содержит описание свойств ActivityManager для каждого процесса. Найдите в первом разделе файла dumpsys строку вроде следующей, которая соответствует вашему приложению:
APP UID 10068 ProcessRecord {41937d40 2205: tunein.service / u0a10068}
Убедитесь, что foregroundServices = true в следующем разделе. Не беспокойтесь о скрытых и пустых настройках; они описывают состояние Activity в процессе и не кажутся особенно актуальными для процессов, в которых есть сервисы. Если 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. Решения о расторжении принимаются на основании полей прил. Вкратце, / 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, этому процессу был назначен параметр adj "бак", и долго он не проживет .. Проще говоря, это баг.
Итак, цель состоит в том, чтобы ваш процесс всегда получал "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 находится на переднем плане, без какого-либо видимого вреда, когда Activity приостановлено или завершено.
Но в целом стратегия состоит в том, чтобы настроить флаги bindService до тех пор, пока sysdump не укажет, что ваш процесс получил правильный приоритет.
Для моих целей, используя Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT для привязок операций к услугам и Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY для привязок сервиса к сервису, кажется, делает правильные вещи. Ваш пробег может отличаться.
Мое приложение довольно сложное: две фоновые службы, каждая из которых может независимо хранить состояния службы переднего плана, плюс третья, которая также может принимать состояние службы переднего плана; две службы связываются друг с другом условно; третий всегда привязан к первому. Кроме того, Activites запускаются в отдельном процессе (делает анимацию более плавной). Выполнение действий и служб в одном процессе, похоже, не имело никакого значения.
Реализация правил для процессов очистки (и исходный код, используемый для генерации содержимого файлов 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
источник
bindService()
если мне нужен постоянно работающий Сервис? Мало ли просто позвонитьstartForeground()
в сервис? Для связи с сервером я использовал EventBus.Если он говорит «больше не хочу ...», то в этом процессе нет активной службы, которая в настоящее время находится в состоянии startForeground (). Убедитесь, что ваш вызов к этому действительно успешен - вы видите опубликованное уведомление, в этот момент в журнале нет сообщений с жалобами на что-либо и т. Д. Также используйте "службы действий dumpsys оболочки adb", чтобы посмотреть на состояние вашей службы и убедитесь, что он действительно отмечен как передний план. Также, если это правильно, то в выводе «adb shell dumpsys activity» вы увидите раздел, показывающий OOM adj для процессов, которые ваш процесс в настоящее время находится на уровне переднего плана из-за этой службы.
источник