ViewCapture w aplikacjach systemowych

ViewCapture to narzędzie, które rejestruje właściwości widoków (takie jak lokalizacja, rozmiar, skala i widoczność) dołączonych do okien, z którymi jest powiązane. ViewCapture rejestruje informacje o różnych widokach w oknie i ich właściwościach, dzięki czemu możesz poznać stan wrażeń użytkownika w określonych momentach i śledzić zmiany w czasie.

Nagrania ekranu mogą wizualizować stan widoku w określonym czasie i pokazywać, jak się on zmienia, ale wymagają znacznych zasobów procesora i mogą wpływać na wydajność. Narzędzie ViewCapture ma mniejszy wpływ na zasoby i można je włączać częściej. Dodatkowo ViewCapture wyświetla wizualizacje klatka po klatce na poziomie widoku, co ułatwia sprawdzanie stanu widoku w określonych momentach w porównaniu z nagraniami ekranu.

Na tej stronie opisujemy, jak wdrożyć ViewCapture w aplikacjach systemowych.

Użyj

ViewCapture.java implementuje instancję onDrawListener i zbiera ślad ViewCapture podczas procesu rysowania. Każde ponowne narysowanie klatki powoduje przejście przez hierarchię drzewa widoków, zaczynając od widoku głównego okna. ViewCapture używa publicznych metod pobierania View.java, aby pobierać i kopiować wartości do wątku w tle, co zwiększa wydajność. Implementacja ViewCapture optymalizuje ten proces, sprawdzając, czy widok jest nieaktualny lub unieważniony, za pomocą captureViewTree, dzięki czemu nie trzeba przechodzić przez całą hierarchię 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 w zależności od docelowej wersji pakietu SDK.

Ograniczenia

W tej sekcji opisano ograniczenia wydajności i pamięci funkcji ViewCapture.

Wydajność

Średni narzut głównego wątku w przypadku wydajności ViewCapture wynosi 195 μs. W najgorszych przypadkach może to zająć około 5 ms. Sprawdź wycinek vc#onDraw w śladzie Perfetto.

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

  1. Przejście przez hierarchię kosztuje 50 μs, nawet w przypadku przycinania.
  2. Pobieranie obiektów z alokatora listy swobodnej 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 pobierającej powoduje wiele dodatkowych wywołań funkcji na widok, co kosztuje 110 μs.

Włączenie funkcji ViewCapture w trybie śledzenia na wygaszonym ekranie (AOT) negatywnie wpływa na wydajność systemu i powoduje zacinanie się obrazu. Ze względu na te ograniczenia wydajności i pamięci to podejście nie jest gotowe do kompilacji AOT. Zalecamy używanie funkcji ViewCapture tylko do debugowania w laboratorium i lokalnie.

Pamięć

Metoda Perfetto do śledzenia ViewCapture używa pojedynczego bufora pierścieniowego o zdefiniowanym rozmiarze pamięci, aby zapobiec nadmiernemu wykorzystaniu pamięci. Takie podejście zapobiega nadmiernemu zużyciu pamięci, ponieważ nie wymaga oddzielnych buforów pierścieniowych dla każdego okna. Nie rozwiązuje to jednak problemu z przechowywaniem całej hierarchii widoków dla każdego stanu w Perfetto w przypadku każdej klatki. Nagrywanie pojedynczego okna, np. NexusLauncher, może wygenerować ponad 30 sekund danych ViewCapture w buforze o rozmiarze 10 MB. Przechwytywanie ponad 30 okien interfejsu systemu wymaga większego bufora lub znacznie krótszego czasu nagrywania.

Instrukcje

Aby wdrożyć ViewCapture w aplikacjach systemowych, wykonaj te czynności:

  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. Podczas tworzenia okna utwórz instancję ViewCapture, 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();
       }
        ...
      }