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 przycięciu.
  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 ramach funkcji Always On Tracing (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 do debugowania lokalnego.

Pamięć

Metoda Perfetta dotycząca śladów ViewCapture korzysta z pojedynczego pierścieniowego bufora pamięci, który ma zdefiniowany z góry rozmiar śladu pamięci, aby zapobiec nadmiernemu wykorzystaniu 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();
       }
        ...
      }