ViewCapture en apps del sistema

ViewCapture es una herramienta de software que captura las propiedades de las vistas (como la ubicación, el tamaño, la escala y la visibilidad) adjuntas a las ventanas a las que está conectada. ViewCapture captura información sobre las diferentes vistas dentro de una ventana y sus propiedades, lo que te permite conocer el estado de la experiencia del usuario en momentos específicos y hacer un seguimiento de los cambios a lo largo del tiempo.

Las grabaciones de pantalla pueden visualizar el estado de una vista en un momento específico y mostrar cómo cambia, pero requieren recursos significativos de la CPU y pueden afectar el rendimiento. La herramienta ViewCapture tiene un menor impacto en los recursos y se puede habilitar con mayor frecuencia. Además, ViewCapture muestra las visualizaciones fotograma por fotograma a nivel de la vista, lo que facilita la inspección del estado de la vista en momentos específicos en comparación con las grabaciones de pantalla.

En esta página, se describe cómo integrar ViewCapture en apps del sistema.

Usar

ViewCapture.java implementa una instancia de onDrawListener y recopila un registro de ViewCapture durante el proceso de dibujo. Cada redibujo de fotograma activa un recorrido de la jerarquía del árbol de vistas que comienza en la vista raíz de la ventana. ViewCapture usa métodos getter públicos View.java para recuperar y copiar valores en un subproceso en segundo plano y mejorar el rendimiento. La implementación de ViewCapture optimiza este proceso verificando si una vista está sucia o invalidada con captureViewTree, lo que evita el recorrido de toda la jerarquía de vistas. captureViewTree solo está disponible para las apps del sistema y forma parte de la API de UnsupportedAppUsage. El uso de esta API se limita a las apps según la versión del SDK de destino.

Limitaciones

En esta sección, se describen las limitaciones de rendimiento y memoria de ViewCapture.

Rendimiento

La sobrecarga promedio del subproceso principal para el rendimiento de ViewCapture es de 195 μs. Sin embargo, en el peor de los casos, puede tardar aproximadamente 5 ms. Consulta el segmento vc#onDraw en el registro de Perfetto.

Los costos generales se deben principalmente a las siguientes acciones:

  1. Recorrer la jerarquía cuesta 50 μs, incluso cuando se poda.
  2. Extraer objetos de un asignador de listas libres para almacenar copias de las propiedades de la vista cuesta 20 μs.
  3. Recuperar cada valor de propiedad a través de una función de obtención genera muchas llamadas a funciones adicionales por vista, lo que cuesta 110 μs.

Por lo tanto, habilitar ViewCapture en el registro siempre activo (AOT) afecta negativamente el rendimiento del sistema y provoca tirones. Debido a estas limitaciones de rendimiento y memoria, este enfoque no está listo para la compilación AOT. Recomendamos ViewCapture solo para la depuración local y de laboratorio.

Memoria

El método de Perfetto para los registros de ViewCapture usa un solo búfer de anillo con una huella de memoria predefinida para evitar el uso excesivo de memoria. Este enfoque evita el consumo excesivo de memoria, ya que no se usan búferes de anillo separados para cada ventana. Sin embargo, no resuelve el problema de almacenar toda la jerarquía de vistas para cada estado en Perfetto para cada fotograma. Grabar una sola ventana, como NexusLauncher, puede producir más de 30 segundos de datos de ViewCapture en un búfer de 10 MB. Capturar más de 30 ventanas de la IU del sistema requiere un búfer más grande o un tiempo de grabación considerablemente más corto.

Instrucciones

Para incorporar ViewCapture en las apps del sistema, sigue estas instrucciones:

  1. Agrega la dependencia a tu archivo Android.bp, como se muestra en el código del Launcher.

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. Crea una instancia de ViewCapture cuando crees tu ventana, por ejemplo:

    • Ejemplo 1:

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

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (enableViewCaptureTracing()) {
            mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
              .startCapture(getRootView(), ".NotificationShadeWindowView");
        }
        ...
      }
      
  3. Cierra la instancia de ViewCapture cuando destruyas la ventana, como se muestra en los siguientes ejemplos:

    • Ejemplo 1:

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

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