ViewCapture в системных приложениях

ViewCapture — это программный инструмент, который фиксирует свойства элементов интерфейса (таких как местоположение, размер, масштаб и видимость), прикрепленных к окнам, к которым он подключен. ViewCapture собирает информацию о различных элементах интерфейса внутри окна и их свойствах, позволяя отслеживать состояние пользовательского интерфейса в определенные моменты времени и контролировать изменения с течением времени.

Запись экрана позволяет визуализировать состояние представления в определенный момент времени и показать, как оно изменяется, но она требует значительных ресурсов процессора и может влиять на производительность. Инструмент ViewCapture потребляет меньше ресурсов и может быть включен чаще. Кроме того, ViewCapture отображает визуализацию покадрово на уровне представления, что упрощает проверку состояния представления в определенные моменты по сравнению с записью экрана.

На этой странице описано, как интегрировать ViewCapture в системные приложения.

Использовать

В ViewCapture.java реализован экземпляр onDrawListener , который собирает трассировку ViewCapture во время процесса отрисовки. Каждая перерисовка кадра запускает обход иерархии дерева представлений, начиная с корневого представления окна. ViewCapture использует открытые методы-геттеры из View.java для получения и копирования значений в фоновый поток для повышения производительности. Реализация ViewCapture оптимизирует этот процесс, проверяя, является ли представление измененным или недействительным, с помощью captureViewTree , тем самым избегая обхода всей иерархии представлений. captureViewTree доступен только для системных приложений и является частью API UnsupportedAppUsage. Использование этого API ограничено приложениями, основанными на их целевой версии SDK.

Ограничения

В этом разделе описываются ограничения производительности и памяти ViewCapture.

Производительность

В среднем, накладные расходы основного потока для производительности ViewCapture составляют 195 мкс. Однако в худших случаях это может занять приблизительно 5 мс. См. фрагмент vc#onDraw в трассировке Perfetto .

Накладные расходы в основном обусловлены следующими действиями:

  1. Обход иерархии занимает 50 мкс, даже после обрезки.
  2. Извлечение объектов из списка свободных памяти для хранения копий свойств представления занимает 20 мкс.
  3. Получение значения каждого свойства через функцию-геттер приводит к множеству дополнительных вызовов функций для каждого представления, что занимает 110 мкс.

Следовательно, включение ViewCapture в режиме постоянной трассировки (AOT) негативно влияет на производительность системы и приводит к рывкам. Из-за этих ограничений производительности и памяти данный подход не подходит для AOT. Мы рекомендуем использовать ViewCapture только для лабораторных и локальных отладок.

Память

Метод Perfetto для трассировки ViewCapture использует единый кольцевой буфер с предопределенным объемом памяти, чтобы предотвратить чрезмерное использование памяти. Такой подход предотвращает избыточное потребление памяти, избегая отдельных кольцевых буферов для каждого окна. Однако он не решает проблему хранения всей иерархии представлений для каждого состояния в Perfetto для каждого кадра. Запись одного окна, например NexusLauncher, может дать более 30 секунд данных ViewCapture в буфере размером 10 МБ. Захват более 30 окон из системного пользовательского интерфейса требует либо большего буфера, либо значительно меньшего времени записи.

Инструкции

Чтобы добавить ViewCapture в системные приложения, выполните следующие действия:

  1. Добавьте зависимость в файл Android.bp , как показано в коде Launcher .

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. При создании окна создайте экземпляр ViewCapture, например:

    • Пример 1 :

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

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (enableViewCaptureTracing()) {
            mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
              .startCapture(getRootView(), ".NotificationShadeWindowView");
        }
        ...
      }
      
  3. Закрывайте экземпляр ViewCapture при уничтожении окна, как показано в следующих примерах:

    • Пример 1 :

      @Override
      public void onDestroy() {
        ...
        if (mViewCapture != null) mViewCapture.close();
      }
      
    • Пример 2 :

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