ViewCapture em apps do sistema

O ViewCapture é uma ferramenta de software que captura as propriedades das visualizações (como localização, tamanho, escala e visibilidade) anexadas às janelas em que está conectado. O ViewCapture captura informações sobre as várias visualizações em uma janela e as propriedades delas, informando o estado da experiência do usuário em momentos específicos e rastreando as mudanças ao longo do tempo.

As gravações de tela podem mostrar o estado de uma visualização em um momento específico e como ela muda, mas elas exigem recursos significativos da CPU e podem afetar o desempenho. A ferramenta ViewCapture tem menos impacto nos recursos e pode ser ativada com mais frequência. Além disso, o ViewCapture mostra visualizações quadro por quadro no nível da visualização, facilitando a inspeção do estado da visualização em momentos específicos em comparação com gravações de tela.

Esta página descreve como integrar o ViewCapture a apps do sistema.

Uso

ViewCapture.java implementa uma instância de onDrawListener e coleta um traço de ViewCapture durante o processo de exibição. Cada quadro redesenhado aciona uma translação da hierarquia da árvore de visualização, começando pela visualização raiz da janela. O ViewCapture usa métodos de getter View.java públicos para buscar e copiar valores para uma linha de execução em segundo plano e melhorar o desempenho. A implementação da ViewCapture otimiza esse processo verificando se uma visualização está suja ou invalidada usando captureViewTree, evitando a travessia de toda a hierarquia de visualizações. captureViewTree está disponível apenas para apps do sistema e faz parte da API UnsupportedAppUsage. O uso dessa API é limitado a apps baseados na versão do SDK de destino.

Limitações

As seções a seguir descrevem as limitações de desempenho e memória na execução do ViewCapture.

Desempenho

A sobrecarga média da linha de execução principal para a performance do ViewCapture é 195 μs. No entanto, no pior cenário, pode levar aproximadamente 5 ms. Consulte a fatia vc#onDraw no rastreamento do Perfetto.

Os custos indiretos são principalmente devido às seguintes ações:

  1. A travessia da hierarquia custa 50 μs, mesmo quando podada.
  2. Extrair objetos de um alocador de lista livre para armazenar cópias de propriedades de visualização custa 20 μs.
  3. A busca de cada valor de propriedade por uma função getter resulta em muitas chamadas de função adicionais por visualização, custando 110 μs.

Portanto, ativar o ViewCapture no rastreamento sempre ativo (AOT, na sigla em inglês) afeta negativamente o desempenho do sistema e causa instabilidade. Devido a essas limitações de desempenho e memória, essa abordagem não está pronta para AOT. Recomendamos o ViewCapture apenas para laboratório e depuração local.

Memória

O método do Perfetto para rastros de ViewCapture usa um único buffer de anel, que tem um consumo de memória predefinido para evitar o uso excessivo de memória. Essa abordagem evita o consumo excessivo de memória evitando o uso de buffers de anel separados para cada janela, mas não resolve o problema de armazenar toda a hierarquia de visualização para cada estado no Perfetto para cada frame. A gravação de uma única janela, como NexusLauncher, pode produzir mais de 30 segundos de dados de ViewCapture em um buffer de 10 MB. No entanto, capturar mais de 30 janelas da IU do sistema exige um buffer maior ou uma janela de tempo de gravação consideravelmente menor.

Instruções

Siga estas instruções para integrar o ViewCapture a apps do sistema:

  1. Adicione a dependência ao arquivo Android.bp, conforme mostrado no código do inicializador.

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. Crie uma instância de ViewCapture ao criar a janela, por exemplo:

    • Exemplo 1:

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        ...
        mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
      }
      
    • Exemplo 2:

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (enableViewCaptureTracing()) {
            mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
              .startCapture(getRootView(), ".NotificationShadeWindowView");
        }
        ...
      }
      
  3. Feche a instância da ViewCapture ao destruir a janela, conforme mostrado nos exemplos abaixo:

    • Exemplo 1:

      @Override
      public void onDestroy() {
        ...
        if (mViewCapture != null) mViewCapture.close();
      }
      
    • Exemplo 2:

      @Override
      protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mViewCaptureCloseable != null) {
            mViewCaptureCloseable.close();
       }
        ...
      }