Repository navigation
Impedir loop de alarm clock e try-catch no attachForegroundTask - #9
Conversation
Marca com [GAUDIUM/OEM] e [GAUDIUM] os pontos do fork que existem por causa de dispositivos especificos ou que divergem de proposito do upstream, para que um merge futuro nao os remova por engano: - startForeground() nos caminhos de update e stop (Motorola e outros OEMs) - createNotificationChannel() antes do startForeground() - shouldReattach=false no catch do onStartCommand - guarda de lateinit em foregroundTaskOptions no onDestroy - som em thread separada (ANR em playCustomSound) - iOS: som customizado com playSound=false, reset de content.sound, notificacao com corpo vazio Somente comentarios, sem mudanca de comportamento. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
O ciclo "onDestroy -> setRestartAlarm(5s) -> RestartReceiver -> startForegroundService -> startForeground() lanca -> stopForegroundService -> onDestroy" nao tinha teto: enquanto a causa raiz persistisse (cota de FGS esgotada, start de FGS nao permitido em background) o alarme era reagendado a cada 5 segundos indefinidamente, drenando bateria e acordando o aparelho. - Adiciona RestartBudget: backoff de 5s/30s/2min/10min/30min, teto de 5 tentativas e janela de 1h que devolve o orcamento ao cheio. - Zera o orcamento quando o startForeground() realmente passa, e tambem em um start explicito vindo do Dart. - onTaskRemoved passa a compartilhar o mesmo orcamento (mantendo 1s na primeira tentativa), senao viraria a nova fonte do loop. - Troca setAlarmClock por setExactAndAllowWhileIdle: os dois concedem a janela de allowlist que permite iniciar FGS em background no Android 12+, mas o setAlarmClock e tratado como despertador do usuario e chega a exibir o icone de alarme na status bar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
O caminho API_STOP do onStartCommand fica fora do try/catch, entao uma excecao em attachForegroundTask() (startForeground() recusado pelo sistema) abortava o stopForegroundService antes do stopSelf(): o servico continuava vivo e o _isRunningServiceState seguia true, fazendo o isRunningService() do Dart mentir e o start seguinte falhar com ServiceAlreadyStartedException. - Envolve o reattach em try/catch, dentro de stopForegroundService, cobrindo de uma vez os caminhos de onStartCommand, onDestroy e onTimeout. - Move stopSelf() e a atualizacao do state flow para um finally. - Remove Log.d ruidoso com TAG truncada no update do ForegroundServiceManager. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
✅ Review postada — #9 (review) job_id: |
There was a problem hiding this comment.
Fix bem fundamentado: adiciona orçamento com backoff exponencial (RestartBudget) para conter o loop de restart via AlarmManager e envolve o reattach de OEM em try/catch pra garantir que o teardown do service sempre aconteça, mesmo quando attachForegroundTask() falha. Os comentários no código documentam a cadeia causal (por quê do loop, por quê do try/catch) de forma consistente com o histórico de workarounds de OEM já existente no arquivo.
| with(prefs.edit()) { | ||
| putInt(PrefsKey.RESTART_ATTEMPT_COUNT, attempts + 1) | ||
| putLong(PrefsKey.RESTART_WINDOW_START, if (isNewWindow) now else windowStart) | ||
| commit() |
There was a problem hiding this comment.
Nit (Performance) — commit() é síncrono e bloqueia a thread principal (chamado em onDestroy/onTaskRemoved, caminhos sensíveis a ANR). Se a durabilidade imediata não for estritamente necessária (o alarme é local, não lê os prefs de outro processo), apply() evita o I/O bloqueante. Se a escolha foi deliberada para garantir que o contador sobreviva a um kill do processo logo após, vale um comentário explicando — hoje não é óbvio pra quem for mexer depois.
There was a problem hiding this comment.
O apply() enfileira a escrita, que ainda vai ocorrer na thread principal dependendo do ciclo de vida
|
CI tá falhando com a versão do gradle, que subiu na PR #10. Essa foi criada apenas para visualizar as alterações pontuais das correções. A PR 10 que será a liberada. |

No description provided.