ViewCapture w aplikacjach systemowych

ViewCapture to narzędzie programowe, 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 momencie i pokazywać, jak się 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 dowiesz się, 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. Aby zwiększyć wydajność, ViewCapture używa publicznych View.java metod pobierania do pobierania i kopiowania wartości do wątku w tle. Implementacja ViewCapture optymalizuje ten proces, sprawdzając, czy widok jest zmodyfikowany lub unieważniony, za pomocą funkcji captureViewTree, co pozwala uniknąć przechodzenia przez całą hierarchię widoków. captureViewTree jest dostępna tylko w aplikacjach systemowych i jest częścią interfejsu API UnsupportedAppUsage. Korzystanie z tego interfejsu API jest ograniczone do aplikacji na podstawie docelowej wersji pakietu SDK.

Ograniczenia

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

Wydajność

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

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

  1. Przechodzenie przez hierarchię kosztuje 50 μs, nawet jeśli jest ona przycięta.
  2. Pobieranie obiektów z alokatora freelist w celu przechowywania kopii właściwości widoku kosztuje 20 μs.
  3. Pobieranie każdej wartości właściwości za pomocą funkcji pobierającej powoduje wiele dodatkowych wywołań funkcji na widok, co kosztuje 110 μs.

W związku z tym włączenie ViewCapture w trybie śledzenia zawsze włączonego (AOT) negatywnie wpływa na wydajność systemu i powoduje zacinanie się. Ze względu na te ograniczenia wydajności i pamięci to podejście nie jest gotowe do AOT. Zalecamy używanie ViewCapture tylko do debugowania w laboratorium i lokalnego.

Pamięć

Metoda Perfetto do śladów ViewCapture używa pojedynczego bufora pierścieniowego o predefiniowanym rozmiarze, aby zapobiec nadmiernemu wykorzystaniu pamięci. To podejście zapobiega nadmiernemu zużyciu pamięci, ponieważ nie używa oddzielnych buforów pierścieniowych dla każdego okna. Nie rozwiązuje to jednak problemu przechowywania całej hierarchii widoków dla każdego stanu w Perfetto dla każdej klatki. Nagrywanie pojedynczego okna, np. NexusLauncher, może wygenerować ponad 30 sekund danych ViewCapture w buforze o rozmiarze 10 MB. Rejestrowanie ponad 30 okien z interfejsu systemowego 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. Po zniszczeniu okna zamknij instancję ViewCapture, 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();
       }
        ...
      }