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 , как показано в коде запуска .

    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();
       }
        ...
      }