Atualização : Não encontrei uma solução verdadeira para o problema. O que eu descobri foi um método de reconectar automaticamente a um dispositivo bluetooth anterior sempre que a conexão for perdida. Não é ideal, mas parece funcionar muito bem. Eu adoraria ouvir mais sugestões sobre isso.
Estou tendo o mesmo problema desta pergunta: serviço sendo interrompido enquanto mantém o wake lock e depois de chamar startForeground incluindo o dispositivo (Asus Transformer), o período de tempo antes do serviço ser interrompido (30-45 minutos), o uso de wake lock, o uso de startForeground () e o fato de que o problema não ocorre se o aplicativo for aberto quando a tela desligar.
Meu aplicativo mantém uma conexão bluetooth com outro dispositivo e envia dados entre os dois, portanto, deve estar ativo o tempo todo para ouvir os dados. O usuário pode iniciar e interromper o serviço à vontade e, de fato, esta é a única maneira que implementei para iniciar ou interromper o serviço. Assim que o serviço for reiniciado, a conexão bluetooth com o outro dispositivo será perdida.
De acordo com a resposta da pergunta vinculada, startForeground () "reduz a probabilidade de um serviço ser encerrado, mas não o impede". Eu entendo que seja o caso, porém tenho visto muitos exemplos de outros aplicativos que não têm esse problema (Tasker, por exemplo).
A utilidade do meu aplicativo será bastante reduzida sem a capacidade do serviço ser executado até ser interrompido pelo usuário. Existe alguma maneira de evitar isso ??
Vejo isso no meu logcat sempre que o serviço é interrompido:
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
EDITAR: também devo observar que isso não parece ocorrer no outro dispositivo ao qual estou conectado: HTC Legend executando o Cyanogen
EDIT: Aqui está o resultado 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}
E a saída 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)
Eles parecem mostrar que o serviço está sendo executado em primeiro plano.
fonte
Respostas:
Entendido. Eu já passei pelo inferno e voltei com esse problema. Veja como proceder. Existem bugs. Esta postagem descreve como analisar bugs na implementação e contornar os problemas.
Para resumir, é assim que as coisas devem funcionar. Os serviços em execução serão eliminados rotineiramente e encerrados a cada 30 minutos ou mais. Os serviços que desejam permanecer ativos por mais tempo devem chamar Service.startForeground, que coloca uma notificação na barra de notificação, para que os usuários saibam que seu serviço está funcionando permanentemente e potencialmente consumindo bateria. Apenas 3 processos de serviço podem se autodenominar como serviços de primeiro plano a qualquer momento. Se houver mais de três serviços em primeiro plano, o Android nomeará o serviço mais antigo como candidato para eliminação e encerramento.
Infelizmente, existem bugs no Android com relação à priorização de serviços de primeiro plano, que são acionados por várias combinações de sinalizadores de vinculação de serviço. Mesmo que você tenha nomeado corretamente seu serviço como um serviço de primeiro plano, o Android pode encerrar seu serviço de qualquer maneira, se alguma conexão aos serviços em seu processo tiver sido feita com certas combinações de sinalizadores de ligação. Os detalhes são fornecidos abaixo.
Observe que muito poucos serviços precisam ser serviços de primeiro plano. Geralmente, você só precisa ser um serviço de primeiro plano se tiver uma conexão à Internet constantemente ativa ou de longa duração de algum tipo que possa ser ligada e desligada ou cancelada pelos usuários. Exemplos de serviços que precisam do status de primeiro plano: servidores UPNP, downloads de longa duração de arquivos muito grandes, sincronização de sistemas de arquivos por wi-fi e reprodução de música.
Se você está apenas pesquisando ocasionalmente, ou esperando em receptores de transmissão do sistema ou eventos do sistema, seria melhor ativar seu serviço em um cronômetro, ou em resposta a receptores de transmissão, e então deixar seu serviço morrer quando concluído. Esse é o comportamento projetado para serviços. Se você simplesmente precisa permanecer vivo, continue lendo.
Depois de marcar as caixas em requisitos conhecidos (por exemplo, chamar Service.startForeground), o próximo lugar a observar é nos sinalizadores que você usa nas chamadas Context.bindService. Os sinalizadores usados para vincular afetam a prioridade do processo do serviço de destino de várias maneiras inesperadas. Mais especificamente, o uso de certos sinalizadores de ligação pode fazer com que o Android faça downgrade incorretamente de seu serviço de primeiro plano para um serviço regular. O código usado para atribuir a prioridade do processo foi agitado fortemente. Notavelmente, há revisões na API 14+ que podem causar bugs ao usar sinalizadores de ligação mais antigos; e existem bugs definitivos em 4.2.1.
Seu amigo em tudo isso é o utilitário sysdump, que pode ser usado para descobrir qual prioridade o gerente de atividades atribuiu ao seu processo de serviço e identificar casos em que atribuiu uma prioridade incorreta. Coloque seu serviço em funcionamento e emita o seguinte comando em um prompt de comando em seu computador host:
processos de atividade do adb shell dumpsys> tmp.txt
Use o bloco de notas (não o wordpad / escrita) para examinar o conteúdo.
Primeiro, verifique se você conseguiu executar o serviço em primeiro plano. A primeira seção do arquivo dumpsys contém uma descrição das propriedades ActivityManager para cada processo. Procure uma linha como a seguinte que corresponda ao seu aplicativo na primeira seção do arquivo dumpsys:
APLICATIVO UID 10068 ProcessRecord {41937d40 2205: tunein.service / u0a10068}
Verifique se foregroundServices = true na seção a seguir. Não se preocupe com as configurações ocultas e vazias; eles descrevem o estado das Atividades no processo e não parecem ser particularmente relevantes para processos com serviços neles. Se foregroundService não for verdadeiro, você precisará chamar Service.startForeground para torná-lo verdadeiro.
A próxima coisa que você precisa examinar é a seção próxima ao final do arquivo intitulada "Lista de LRU do processo (classificada por oom_adj):". As entradas nesta lista permitem que você determine se o Android realmente classificou seu aplicativo como um serviço de primeiro plano. Se o seu processo está no final desta lista, é um candidato principal para o extermínio sumário. Se o seu processo estiver próximo ao topo da lista, ele é virtualmente indestrutível.
Vejamos uma linha nesta tabela:
Proc #31: adj=prcp /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)
Este é um exemplo de serviço de primeiro plano que fez tudo certo. O campo-chave aqui é o campo "adj =". Isso indica a prioridade que seu processo foi atribuído pelo ActivityManagerService depois que tudo foi dito feito. Você deseja que seja "adj = prcp" (serviço visível em primeiro plano); ou "adj = vis" (processo visível com uma atividade) ou "anterior" (processo com uma atividade em primeiro plano). Se for "adj = svc" (processo de serviço), ou "adj = svcb" (serviço legado?), Ou "adj = bak" (processo em segundo plano vazio), então seu processo é um provável candidato a encerramento e será encerrado não menos frequentemente do que a cada 30 minutos, mesmo se não houver qualquer pressão para recuperar a memória. Os sinalizadores restantes na linha são principalmente informações de diagnóstico de depuração para engenheiros do Google. As decisões de rescisão são feitas com base nos campos adj. Resumidamente, / FS indica um serviço de primeiro plano; / FA indica um processo em primeiro plano com uma atividade. / B indica um serviço em segundo plano. O rótulo no final indica a regra geral sob a qual o processo recebeu uma prioridade. Normalmente, deve corresponder ao campo adj =; mas o valor adj = pode ser ajustado para cima ou para baixo em alguns casos devido a sinalizadores de ligação em ligações ativas com outros serviços ou atividades.
Se você tropeçou em um bug com sinalizadores de ligação, a linha dumpsys será semelhante a esta:
Proc #31: adj=bak /FS trm= 0 2205:tunein.service/u0a10068 (fg-service)
Observe como o valor do campo adj está incorretamente definido como "adj = bak" (processo em segundo plano vazio), o que se traduz aproximadamente em "por favor, termine-me agora para que eu possa encerrar esta existência inútil" para fins de eliminação do processo. Observe também o sinalizador (fg-service) no final da linha, que indica que "regras de serviço forground foram usadas para determinar a configuração" adj ". Apesar do fato de as regras fg-service terem sido usadas, este processo recebeu uma configuração adj "bak", e não viverá por muito tempo. Simplificando, isso é um bug.
Portanto, o objetivo é garantir que seu processo sempre obtenha "adj = prcp" (ou melhor). E o método para atingir esse objetivo é ajustar os sinalizadores de ligação até conseguir evitar bugs na atribuição de prioridade.
Aqui estão os bugs que conheço. (1) Se QUALQUER serviço ou atividade já se vinculou ao serviço usando Context.BIND_ABOVE_CLIENT, você corre o risco de que a configuração adj = seja rebaixada para "bak", mesmo que a vinculação não esteja mais ativa. Isso é particularmente verdadeiro se você também tiver ligações entre serviços. Um bug claro nas fontes 4.2.1. (2) Definitivamente, nunca use BIND_ABOVE_CLIENT para uma vinculação serviço a serviço. Não o use para conexões de atividade para serviço. O sinalizador usado para implementar o comportamento BIND_ABOVE_CLIENT parece ser definido por processo, em vez de por conexão, então ele aciona bugs com ligações serviço a serviço, mesmo se não houver uma atividade ativa a serviço vinculação com o conjunto de sinalizadores. Também parece haver problemas com o estabelecimento de prioridade quando há vários serviços no processo, com ligações de serviço a serviço. Usando Context.BIND_WAIVE_PRIORITY (API 14) em ligações serviço a serviço parece ajudar. Context.BIND_IMPORTANT parece ser uma ideia mais ou menos boa ao vincular de uma Activity a um serviço. Fazer isso aumenta a prioridade do processo um degrau acima quando a atividade está em primeiro plano, sem causar nenhum dano aparente quando a atividade é pausada ou concluída.
Mas, no geral, a estratégia é ajustar seus sinalizadores de bindService até que sysdump indique que seu processo recebeu a prioridade correta.
Para meus propósitos, usando Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT para ligações de atividade para serviço e Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY para ligações serviço a serviço parece fazer a coisa certa. Sua milhagem pode ser diferente.
Meu aplicativo é bastante complexo: dois serviços de segundo plano, cada um dos quais pode conter independentemente estados de serviço de primeiro plano, mais um terceiro que também pode assumir o estado de serviço de primeiro plano; dois dos serviços se ligam condicionalmente; o terceiro liga-se ao primeiro, sempre. Além disso, as atividades são executadas em um processo separado (torna a animação mais suave). Executar as Atividades e Serviços no mesmo processo não pareceu fazer diferença.
A implementação das regras para processos de eliminação (e o código-fonte usado para gerar o conteúdo dos arquivos sysdump) podem ser encontrados no arquivo android principal
frameworks\base\services\java\com\android\server\am\ActivityManagerService.java.
Boa chance.
PS: Esta é a interpretação das strings sysdump para Android 5.0. Não trabalhei com eles, então faça deles o que quiser. Eu acredito que você deseja que 4 seja 'A' ou 'S' e 5 seja "IF" ou "IB" e 1 seja o mais baixo possível (provavelmente abaixo de 3, uma vez que apenas 3 processos de serviço em primeiro plano são mantidos ativos na configuração padrão).
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
fonte
bindService()
se eu precisar executar o serviço constantemente? Não é suficiente apenas ligarstartForeground()
para o serviço? Para comunicação com o servidor I usando EventBus.Se estiver dizendo "não quero mais ...", então esse processo não tem um serviço ativo nele que esteja atualmente no estado startForeground (). Certifique-se de que sua chamada para está realmente sendo bem-sucedida - se você está vendo a notificação postada, não há mensagens no log naquele ponto reclamando de nada, etc. Use também "serviços de atividade de shell dumpsys adb" para olhar estado do seu serviço e certifique-se de que está realmente marcado como primeiro plano. Além disso, se estiver corretamente em primeiro plano, na saída de "adb shell dumpsys activity", você verá na seção que mostra o ajuste OOM dos processos que seu processo está atualmente no primeiro plano devido a esse serviço.
fonte