Android

A ideia por trás da correção

O texto explica uma solução para um problema de travamento em sistemas Android, causado pela sobreposição simultânea de eventos como carregamento de classes e criação/terminação de threads durante a inicialização. A proposta é interromper as notificações do JDWP sobre esses eventos, evitando assim o acúmulo que leva ao travamento, sem afetar o funcionamento da aplicação.

Compartilhar
Medium

A ideia por trás da correção

Vamos lembrar o que realmente dispara o deadlock. É necessário que três tempestades atinjam a camada de depuração ao mesmo tempo, exatamente no momento do anexo:

  • CLASS_PREPARE — milhares de classes carregando todas ao mesmo tempo;
  • THREAD_END / THREAD_START — centenas de threads curtas-vidas;
  • Pressão do GC — alocação pesada durante o início.

Deixe esses três sinais se sobrepor na janela de anexação, e a runtime cai diretamente no estreito ponto entre ObjectTagTable/commonRef e processamento de referências frágeis do sistema.

Há uma segunda face mais prática também. O JDWP é um protocolo síncrono: para cada um desses eventos, a runtime aguarda uma resposta da camada de depuração. Em uma carga em massa (na ordem de 20.000 classes em 25 segundos) você acumula uma avalanche de +40.000 eventos, o binder simplesmente não consegue acompanhar, a fila infla — e o thread principal para completamente. Mesmo onde nunca chega a um deadlock completo, isso sozinho é suficiente para um ANR. Então o problema é realmente duplo: um deadlock estrutural dentro do ART e uma simples superação de um canal síncrono.

A correção adequada no lado AOSP tem que romper o ciclo de bloqueio em si — por exemplo, adiando a entrega do evento livre-JVMTI até depois da seção frágil do sistema fechar. Mas isso é internos da runtime; não podemos alcançar lá a partir do código da aplicação.

O que podemos fazer é abordá-lo de outro lado e remover a pressão. Se o ART parar de notificar a camada JDWP sobre inícios e mortes de threads (e, se você quiser, preparações de classe também), não há avalanche — e sem avalanche significa que a janela do deadlock nunca abre. A lógica da aplicação não poderia se importar menos: esses eventos existem puramente para o próprio livro-razão telemétrico do depurador; eles têm zero efeito sobre como seu código funciona.

Tecnicamente toda a tarefa se resume a uma coisa: interceptar um punhado de métodos internos art::RuntimeCallbacks e trocar por nops. A ferramenta para o trabalho — um hook inline em símbolos nativos libart.so.

Fonte original

Conteúdo traduzido e adaptado pela redação do Notícias Mobile. Confira também a matéria na fonte original.

Leia a matéria completa