ViewCapture w aplikacjach systemowych

ViewCapture to narzędzie, które rejestruje właściwości widoków (takie jak lokalizacja, rozmiar, skala i widoczność) w oknach, do których jest podłączone. Funkcja ViewCapture rejestruje informacje o różnych widokach w oknie i ich właściwościach, dzięki czemu możesz dowiedzieć się, jak wyglądają wrażenia użytkownika w określonych momentach i śledzić zmiany w czasie.

Nagrywanie ekranu pozwala wizualizować stan widoku w określonym momencie i pokazywać, jak się zmienia, ale wymaga to znacznych zasobów procesora i może mieć wpływ na wydajność. Narzędzie ViewCapture ma mniejszy wpływ na zasoby i może być częściej włączane. Dodatkowo ViewCapture wyświetla wizualizacje klatka po klatce na poziomie widoku, dzięki czemu łatwiej jest sprawdzić stan widoku w określonych momentach w porównaniu z nagraniami ekranu.

Na tej stronie opisaliśmy, jak włączyć ViewCapture w aplikacji systemowej.

Użyj

ViewCapture.java implementuje instancję onDrawListener i zbiera ślad ViewCapture podczas procesu rysowania. Każde ponowne rysowanie ramki powoduje przeszukiwanie hierarchii drzewa widoku, zaczynając od widoku okna skojarzonego z widokiem głównym. ViewCapture używa publicznych metod View.javagetter, aby pobierać i kopiować wartości do wątku w tle w celu zwiększenia wydajności. Implementacja ViewCapture optymalizuje ten proces, sprawdzając, czy widok jest nieaktualny lub nieprawidłowy za pomocą captureViewTree, dzięki czemu unika przeszukiwania całej hierarchii widoków. captureViewTree jest dostępna tylko w przypadku aplikacji systemowych i jest częścią interfejsu UnsupportedAppUsage API. Korzystanie z tego interfejsu API jest ograniczone do aplikacji, których docelowa wersja pakietu SDK jest zgodna z wymaganiami.

Ograniczenia

W poniższych sekcjach opisaliśmy wydajność i ograniczenia pamięci podczas uruchamiania narzędzia ViewCapture.

Wydajność

Średni czas wykonywania głównego wątku w przypadku funkcji ViewCapture to 195 μs. W najgorszym przypadku może to jednak potrwać około 5 ms. Zapoznaj się z odcinkiem vc#onDraw w śladzie Perfetto.

Koszty ogólne wynikają głównie z tych działań:

  1. Przejście przez hierarchię zajmuje 50 μs, nawet po usunięciu zbędących elementów.
  2. Pobieranie obiektów z alokutora listy wolnych elementów w celu przechowywania kopii właściwości widoku kosztuje 20 μs.
  3. Pobieranie wartości każdej właściwości za pomocą funkcji gettera powoduje wiele dodatkowych wywołań funkcji na widok, co kosztuje 110 μs.

Włączenie funkcji ViewCapture w trybie ciągłego śledzenia (AOT) negatywnie wpływa na wydajność systemu i powoduje zacinanie. Ze względu na te ograniczenia dotyczące wydajności i pamięci to podejście nie jest gotowe do skompilowania AOT. Zalecamy korzystanie z ViewCapture tylko w laboratorium i przy lokalnym debugowaniu.

Pamięć

Metoda Perfetta dotycząca śladów ViewCapture używa pojedynczego pierścieniowego bufora, który ma wstępnie zdefiniowany ślad pamięci, aby zapobiec nadmiernemu używaniu pamięci. Takie podejście zapobiega nadmiernemu zużyciu pamięci, ponieważ nie wymaga korzystania z osobnych buforów pierścieniowych dla każdego okna. Nie rozwiązuje jednak problemu przechowywania całej hierarchii widoku dla każdego stanu w Perfetto w przypadku każdego kadru. Nagranie jednego okna, takiego jak NexusLauncher, może wygenerować ponad 30 sekund danych ViewCapture w buforze o rozmiary 10 MB. Jednak rejestrowanie ponad 30 okienek z interfejsu systemu wymaga albo większego bufora, albo znacznie krótszego okna nagrywania.

Instrukcje

Aby włączyć ViewCapture w aplikacjach systemowych:

  1. Dodaj zależność do pliku Android.bp, jak pokazano w kodzie Launchera.

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. Utwórz instancję ViewCapture podczas tworzenia okna, na przykład:

    • Przykład 1:

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

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (enableViewCaptureTracing()) {
            mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
              .startCapture(getRootView(), ".NotificationShadeWindowView");
        }
        ...
      }
      
  3. Zamknij instancję ViewCapture podczas niszczenia okna, jak pokazano w tych przykładach:

    • Przykład 1:

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

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