Estudos de caso

Como a WHOOP reduziu em mais de 90% as sessões de wake lock parciais em excesso

Leitura de 4 minutos

Criar um app Android para um wearable significa que o trabalho de verdade começa quando a tela é desligada. O WHOOP ajuda os membros a entender como o corpo deles responde ao treinamento, à recuperação, ao sono e ao estresse. Para os muitos membros do WHOOP no Android, a sincronização e a conectividade confiáveis em segundo plano são o que tornam esses insights possíveis.

No início deste ano, o Google Play lançou uma nova métrica no Android vitals: bloqueios de despertar parciais excessivos. Essa métrica mede a porcentagem de sessões de usuários em que o uso cumulativo e não isento de wake lock excede 2 horas em um período de 24 horas. O objetivo dessa métrica é ajudar você a identificar e resolver possíveis fontes de consumo da bateria, o que é essencial para oferecer uma ótima experiência do usuário.

A partir de 1º de março de 2026, os apps que não atingirem o limite de qualidade poderão ser excluídos das plataformas de descoberta do Google Play. Um aviso também pode ser colocado na página "Detalhes do app" da Google Play Store, indicando que o app pode usar mais bateria do que o esperado.

De acordo com Mayank Saini, engenheiro sênior do Android na WHOOP,  isso "deu à equipe a oportunidade de aumentar o nível de eficiência do Android" depois que o Android vitals sinalizou que o percentual de wake locks parciais em excesso do app era de 15%, o que excedeu o limite recomendado de 5%.

mayank.png

A equipe considerou a métrica do Android vitals como um sinal claro de que o trabalho em segundo plano estava mantendo a CPU ativa por mais tempo do que o necessário. Resolver isso permitiria que eles continuassem oferecendo uma ótima experiência do usuário e, ao mesmo tempo, diminuíssem o tempo ocioso em segundo plano e mantivessem a conectividade e a sincronização Bluetooth confiáveis e oportunas.

Identificar o problema

Para descobrir por onde começar, a equipe primeiro recorreu ao Android vitals para ter mais insights sobre quais bloqueios de despertar estavam afetando a métrica. Ao consultar o painel de wake locks parciais excessivos do Android vitals, eles identificaram que o maior contribuinte para wake locks parciais excessivos era um dos workers do WorkManager (identificado no painel como androidx.work.impl.background.systemjob.SystemJobService). Para oferecer suporte à "experiência sempre ativa" do WHOOP, o app usa o WorkManager para tarefas em segundo plano, como sincronização periódica e entrega de atualizações recorrentes ao wearable. 

Embora a equipe soubesse que o WorkManager adquire um wake lock ao executar tarefas em segundo plano, ela não tinha visibilidade de como todo o trabalho em segundo plano (além do WorkManager) era distribuído até a introdução da métrica de wake locks parciais excessivos no Android vitals.

Com o painel identificando o WorkManager como o principal contribuinte, a equipe pôde concentrar os esforços em identificar qual dos workers estava contribuindo mais e trabalhar para resolver o problema.

Usar métricas e dados internos para restringir a causa

A WHOOP já tinha uma infraestrutura interna configurada para monitorar as métricas do WorkManager. Eles monitoram periodicamente:

  1. Tempo médio de execução: por quanto tempo o worker é executado?
  2. Tempos limite: com que frequência o worker atinge o tempo limite em vez de concluir?
  3. Novas tentativas: com que frequência o worker tenta novamente se o trabalho atingir o tempo limite ou falhar?
  4. Cancelamentos: com que frequência o trabalho foi cancelado?

Ao rastrear mais do que apenas sucessos e falhas dos trabalhadores, a equipe tem visibilidade da eficiência do trabalho.

As métricas internas sinalizaram um tempo médio de execução alto para alguns workers, permitindo que eles restringissem ainda mais a investigação. 

Além das métricas internas, a equipe também usou o Inspetor de tarefas em segundo plano do Android Studio para inspecionar e depurar os workers de interesse, com foco específico nos bloqueios de ativação associados, para se alinhar à métrica sinalizada no Android vitals.

Investigação: como distinguir entre variantes de trabalhadores

A WHOOP usa agendamento único e periódico para alguns trabalhadores. Isso permite que o app reutilize a mesma lógica do Worker para tarefas idênticas com os mesmos critérios de sucesso, diferindo apenas no tempo.

Usando as métricas internas, foi possível restringir a pesquisa a um determinado worker, mas não foi possível saber se o bug ocorreu quando o worker era único, periódico ou ambos. Por isso, eles lançaram uma atualização para usar o método setTraceTag do WorkManager para distinguir entre as variantes únicas e periódicas do mesmo Worker.

Esse detalhe extra permitiria identificar definitivamente qual variante do worker (periódica ou única) estava contribuindo mais para sessões com bloqueios de despertar parciais excessivos. No entanto, a equipe se surpreendeu quando os dados revelaram que nenhuma das variantes parecia contribuir mais do que a outra.

Manmeet Tuteja, engenheiro do Android II na WHOOP, disse: "Essa divisão também nos ajudou a confirmar que o problema estava acontecendo nas duas variantes, o que apontou para um problema de lógica de negócios compartilhada dentro da implementação do worker, e não para uma configuração de programação".

manmeet.png

Analisar o comportamento dos trabalhadores e corrigir a causa raiz

Com o conhecimento de que precisavam analisar a lógica dentro do worker,  a equipe reexaminou o comportamento dos workers sinalizados durante a investigação. Especificamente, eles estavam procurando instâncias em que o trabalho poderia estar travando e não sendo concluído.

Tudo isso culminou na descoberta da causa raiz dos wake locks em excesso:

Um CoroutineWorker projetado para aguardar uma conexão com o sensor WHOOP antes de prosseguir. 

Se o treino começou sem um sensor conectado, whoopSensorFlow, que indica se o sensor está conectado, era null. O SensorWorker não tratou isso como uma condição de saída antecipada e continuou sendo executado, aguardando indefinidamente uma conexão. Como resultado, o WorkManager manteve um wake lock parcial até que o trabalho atingisse o tempo limite, o que levou a um alto uso de wake lock em segundo plano e a um reagendamento frequente e indesejado do SensorWorker.

Para resolver isso, a equipe do WHOOP atualizou a lógica do worker para verificar o status da conexão antes de tentar executar a lógica de negócios principal.

Se o sensor não estiver disponível, o worker será encerrado, evitando um cenário de tempo limite e liberando o wake lock. O snippet de código a seguir mostra a solução:

class SensorWorker(appContext: Context, params: WorkerParameters): CoroutineWorker(appContext, params) {
   override suspend fun doWork(): Result {
      ...
      // Check the sensor state and perform work or return failure
       return whoopSensorFlow.replayCache
            .firstOrNull()
            ?.let { cachedData ->
                processSensorData(cachedData)
                Result.success()
            } ?: run {
                Result.failure()
            }
}

Redução de 90% nas sessões com wake locks parciais em excesso

Depois de lançar a correção, a equipe continuou monitorando o painel do Android vitals para confirmar o impacto das mudanças. 

No fim das contas, a WHOOP viu a porcentagem excessiva de wake lock parcial cair de 15% para menos de 1% apenas 30 dias depois de implementar as mudanças no Worker. 

partialWake.png

Como resultado das mudanças, a equipe teve menos casos de tempo limite de trabalho sem conclusão, o que resultou em tempos de execução médios mais baixos. 

O conselho da equipe da WHOOP para outros desenvolvedores que querem melhorar a eficiência do trabalho em segundo plano:

sarthak.png

Começar

Se você quiser reduzir os wake locks parciais excessivos do app ou melhorar a eficiência do worker, consulte a métrica de wake locks parciais excessivos do app no Android vitals e confira a documentação de wake locks para mais práticas recomendadas e estratégias de depuração. 

Escrito por:
Continuar lendo