Servicio de primer plano por Android

Actualización : No he encontrado una solución verdadera al problema. Lo que sí me ocurrió fue un método de volver a conectar automáticamente a un dispositivo bluetooth anterior en cualquier momento que se pierda la conexión. No es ideal, pero parece funcionar bastante bien. Me encantaría escuchar más sugerencias con respecto a esto sin embargo.

Estoy teniendo mucho el mismo problema que en esta pregunta: El servicio se está matando mientras que la celebración de bloqueo de la estela y después de llamar a startForeground incluyendo el dispositivo (Asus Transformer), el período de tiempo antes de que el servicio se detenga (30-45 minutos), el uso de Wake lock, el uso de startForeground (), y el hecho de que el problema no se produce si la aplicación está abierta cuando la pantalla se apaga.

Mi aplicación mantiene una conexión bluetooth a otro dispositivo y envía datos entre los dos, por lo que debe estar activo en todo momento para escuchar los datos. El usuario es capaz de iniciar y detener el servicio a voluntad, y de hecho esta es la única manera que he implementado para iniciar o detener el servicio. Una vez que el servicio se reinicia, se pierde la conexión Bluetooth con el otro dispositivo.

De acuerdo con la respuesta en la pregunta enlazada, startForeground () "reduce la probabilidad de un servicio que se está matando, pero no lo impide". Entiendo que para ser el caso, sin embargo, he visto muchos ejemplos de otras aplicaciones que no tienen este problema (Tasker, por ejemplo).

La utilidad de mi aplicación se reducirá considerablemente sin la posibilidad de que el servicio funcione hasta que sea detenido por el usuario. ¿¿¿Hay alguna manera de evitar esto???

Veo esto en mi logcat siempre que el servicio se detiene:

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: Debo también observar, esto no parece ocurrir en el otro dispositivo que estoy conectado a: HTC Legend que funciona Cyanogen

EDIT: Aquí está la salida de adb shell dumpsys activity services de 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} 

Y la salida de la adb shell dumpsys activity de 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) 

Estos parecen mostrar que el servicio se está ejecutando en primer plano.

Okey dokey He pasado por el infierno y de vuelta en este problema. A continuación le indicamos cómo proceder. Hay bichos. Esta publicación describe cómo analizar errores en la implementación y evitar problemas.

Sólo para resumir, aquí es cómo se supone que las cosas funcionan. Los servicios corrientes serán rutinariamente limpiados y terminados cada 30 minutos más o menos. Los servicios que deseen permanecer vivos durante más tiempo deben llamar a Service.startForeground, que coloca una notificación en la barra de notificaciones para que los usuarios sepan que su servicio está en ejecución permanente y potencialmente la vida de la batería. Sólo 3 procesos de servicio pueden designarse como servicios de primer plano en un momento dado. Si hay más de tres servicios en primer plano, Android presentará el servicio más antiguo como candidato para la eliminación y terminación.

Desafortunadamente, hay errores en Android con respecto a la priorización de servicios de primer plano, que son activados por varias combinaciones de banderas de enlace de servicio. Aunque haya nominado correctamente su servicio como servicio de primer plano, Android puede terminar su servicio de todos modos, si alguna vez se han realizado conexiones con servicios en su proceso con ciertas combinaciones de banderas de enlace. Los detalles se dan a continuación.

Tenga en cuenta que muy pocos servicios deben ser servicios de primer plano. Por lo general, sólo necesita ser un servicio de primer plano si tiene una conexión a Internet activa o de larga duración de algún tipo que puede activarse y desactivarse o cancelada por los usuarios. Ejemplos de servicios que necesitan el estado de primer plano: servidores UPNP, descargas de larga duración de archivos muy grandes, sincronización de sistemas de archivos por wi-fi y reproducción de música.

Si acaba de hacer sondeos de vez en cuando, o espera en los receptores de sistemas de difusión, o eventos del sistema, sería mejor despertar su servicio en un temporizador, o en respuesta a los receptores de radiodifusión, y luego dejar que su servicio muera una vez completado. Ese es el comportamiento diseñado para los servicios. Si simplemente debes permanecer vivo, sigue leyendo.

Después de haber marcado las casillas en requisitos bien conocidos (por ejemplo, llamar a Service.startForeground), el siguiente lugar para buscar es en las banderas que utiliza en las llamadas Context.bindService. Los indicadores utilizados para enlazar afectan la prioridad del proceso de servicio de destino en una variedad de formas inesperadas. Más particularmente, el uso de ciertas banderas de enlace puede hacer que Android degrade incorrectamente su servicio de primer plano a un servicio regular. El código utilizado para asignar la prioridad del proceso se ha producido bastante. Cabe destacar que hay revisiones en API 14+ que pueden causar errores cuando se usan antiguos indicadores de enlace; Y hay errores definidos en 4.2.1.

Su amigo en todo esto es la utilidad sysdump, que se puede utilizar para determinar qué prioridad el Administrador de actividades ha asignado a su proceso de servicio y detectar casos en los que ha asignado una prioridad incorrecta. Haga que su servicio funcione y ejecute el comando siguiente desde el símbolo del sistema de su computadora host:

Adb shell dumpsys actividad procesos> tmp.txt

Utilice el bloc de notas (no wordpad / write) para examinar el contenido.

Primero compruebe que ha logrado ejecutar su servicio en estado de primer plano. La primera sección del archivo dumpsys contiene una descripción de las propiedades de ActivityManager para cada proceso. Busque una línea como la siguiente que corresponde a su aplicación en la primera sección del archivo dumpsys:

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

Compruebe que foregroundServices = true en la sección siguiente. No se preocupe por los ajustes ocultos y vacíos; Describen el estado de las Actividades en el proceso y no parecen ser particularmente relevantes para los procesos con servicios en ellos. Si foregroundService no es true, necesita llamar a Service.startForeground para que sea verdad.

La siguiente cosa que usted necesita mirar es la sección cerca del final del archivo titulado "Proceso LRU lista (ordenado por oom_adj):". Las entradas en esta lista le permiten determinar si Android ha clasificado realmente su aplicación como un servicio de primer plano. Si su proceso está en la parte inferior de esta lista, es un excelente candidato para el exterminio de resumen. Si su proceso está cerca de la parte superior de la lista, es prácticamente indestructible.

Veamos una línea en esta tabla:

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

Este es un ejemplo de un servicio de primer plano que ha hecho todo bien. El campo clave aquí es el campo "adj =". Eso indica la prioridad que el ActivityManagerService asignó a su proceso después de que todo fue dicho. Usted quiere que sea "adj = prcp" (visible servicio de primer plano); O "adj = vis" (proceso visible con una actividad) o "fore" (proceso con una actividad de primer plano). Si es "adj = svc" (proceso de servicio), o "adj = svcb" (servicio heredado?), O "adj = bak" (proceso de fondo vacío), entonces su proceso es un candidato probable para la terminación, y será terminado No menos frecuentemente que cada 30 minutos, incluso si no hay ninguna presión para recuperar la memoria. Los demás indicadores en la línea son principalmente información de depuración de diagnóstico para los ingenieros de Google. Las decisiones sobre la terminación se basan en los campos adjuntos. En pocas palabras, / FS indica un servicio de primer plano; / FA indica un proceso de primer plano con una actividad. / B indica un servicio de fondo. La etiqueta al final indica la regla general bajo la cual el proceso fue asignado una prioridad. Normalmente debe coincidir con el campo adj =; Pero el valor adj = se puede ajustar hacia arriba o hacia abajo en algunos casos debido a los indicadores de enlace en enlaces activos con otros servicios o actividades.

Si ha tropezado con un error con banderas de enlace, la línea dumpsys se verá así:

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

Observe cómo el valor del campo adj se establece incorrectamente en "adj = bak" (proceso de fondo vacío), que se traduce aproximadamente en "por favor, por favor, termina ahora para que pueda terminar esta existencia sin sentido" con el propósito de eliminar el proceso. Observe también el indicador (fg-service) al final de la línea que indica que "las reglas de servicio forground se usaron para determinar el ajuste" adj "A pesar de que se usaron las reglas fg-service, este proceso se asignó un ajuste adj "Bak", y no va a vivir por mucho tiempo.Por supuesto, esto es un error.

Por lo tanto, la meta es asegurar que su proceso obtenga siempre "adj = prcp" (o mejor). Y el método para lograr ese objetivo es ajustar las banderas de enlace hasta que logre evitar errores en la asignación de prioridad.

Aquí están los errores que conozco. (1) Si algún servicio o actividad se ha vinculado al servicio utilizando Context.BIND_ABOVE_CLIENT, corre el riesgo de que el ajuste adj = sea degradado a "bak" aunque no esté activo. Esto es particularmente cierto si también tiene enlaces entre servicios. Un error claro en las fuentes 4.2.1. (2) Definitivamente nunca utilice BIND_ABOVE_CLIENT para un enlace de servicio a servicio. No lo utilice también para las conexiones de actividad a servicio. El indicador utilizado para implementar el comportamiento BIND_ABOVE_CLIENT parece estar establecido en una base por proceso, en lugar de una base por conexión, por lo que desencadena errores con enlaces de servicio a servicio, incluso si no hay una actividad activa a servicio Vinculante con la bandera establecida. También parece haber problemas con el establecimiento de prioridad cuando hay múltiples servicios en el proceso, con servicio a servicio de enlaces. El uso de Context.BIND_WAIVE_PRIORITY (API 14) en los enlaces de servicio a servicio parece ayudar. Context.BIND_IMPORTANT parece ser una idea más o menos buena cuando se vincula desde una actividad a un servicio. Si lo hace, su prioridad de proceso es un punto más alto cuando la Actividad está en primer plano, sin causar ningún daño aparente cuando la Actividad está detenida o finalizada.

Pero en general, la estrategia consiste en ajustar los indicadores bindService hasta que sysdump indique que su proceso ha recibido la prioridad correcta.

Para mis propósitos, usar Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT para enlaces de actividad a servicio y Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY para enlaces de servicio a servicio parece hacer lo correcto. Su kilometraje puede variar.

Mi aplicación es bastante compleja: dos servicios de fondo, cada uno de los cuales independientemente puede mantener estados de servicio en primer plano, además de un tercero que también puede tomar estado de servicio en primer plano; Dos de los servicios se unen condicionalmente; El tercero se une al primero, siempre. Además, las actividades se ejecutan en un proceso separado (hace la animación más suave). Ejecutar las actividades y los servicios en el mismo proceso no parecía hacer ninguna diferencia.

La implementación de las reglas para los procesos de barrido (y el código fuente utilizado para generar el contenido de los archivos sysdump) se puede encontrar en el archivo core android

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

Buena oportunidad.

PS: Aquí está la interpretación de las cadenas de sysdump para Android 5.0. No he trabajado con ellos, así que haz de ellos lo que quieras. Creo que usted quiere que 4 sea 'A' o 'S', y 5 sea "SI" o "IB", y 1 sea lo más bajo posible (probablemente por debajo de 3, ya que solo 3 tres procesos de servicio en primer plano se mantienen activos En configuración predeterminada).

 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 

Si está diciendo "ya no quiere …" entonces ese proceso no tiene un servicio activo en el que está actualmente en el estado startForeground (). Compruebe que su llamada a que realmente está teniendo éxito – que está viendo la notificación enviada, no hay mensajes en el registro en ese punto quejándose de nada, etc También utilizar "servicios de actividad de dumpsys de shell de adb" para ver el Estado de su servicio y asegúrese de que está marcado como primer plano. También si está correctamente en primer plano entonces en la salida de "adb shell dumpsys actividad" verá en la sección que muestra el OOM adj de los procesos que su proceso está actualmente en el primer plano debido a ese servicio.

  • Aplicación de Android que requiere archivos de datos grandes
  • ¿Posible inflar una disposición de XML en un servicio? (Androide)
  • Cómo tratar un objeto JSON grande en Android
  • StartForeground () no muestra mi notificación
  • ¿Cuál es la diferencia entre Thread.run () y Handler.post () y Service en Android?
  • Phonegap Android Internet no funciona
  • ¿Qué es un servicio web en android?
  • Error en Callin Java webservice de Android usando k-Soap
  • La solicitud de servicio web no funciona en el navegador android android; Pero está trabajando en el navegador de PC
  • ¿Cómo acceder a un contexto de aplicación ya en ejecución desde un servicio de adaptador de sincronización en Android?
  • Retofit2 error java.io.EOFException: Fin de la entrada en la línea 1 columna 1
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.