ViewCapture in System-Apps

ViewCapture ist ein Softwaretool, mit dem die Eigenschaften der Ansichten (z. B. Position, Größe, Skalierung und Sichtbarkeit) erfasst werden, die mit den Fenstern verknüpft sind, an die es angehängt ist. ViewCapture erfasst Informationen zu den verschiedenen Ansichten in einem Fenster und deren Eigenschaften. So können Sie den Zustand der Nutzererfahrung zu bestimmten Zeitpunkten ermitteln und Änderungen im Zeitverlauf verfolgen.

Bildschirmaufzeichnungen können den Zustand einer Ansicht zu einem bestimmten Zeitpunkt visualisieren und zeigen, wie sie sich ändert. Sie erfordern jedoch erhebliche CPU-Ressourcen und können sich auf die Leistung auswirken. Das ViewCapture-Tool hat weniger Auswirkungen auf die Ressourcen und kann häufiger aktiviert werden. Außerdem zeigt ViewCapture Visualisierungen Frame für Frame auf Ansichtsebene an. So lässt sich der Ansichtsstatus zu bestimmten Zeitpunkten einfacher prüfen als bei Bildschirmaufzeichnungen.

Auf dieser Seite wird beschrieben, wie Sie ViewCapture in System-Apps einbinden.

Verwenden

ViewCapture.java implementiert eine Instanz von onDrawListener und erfasst während des Zeichenvorgangs einen ViewCapture-Trace. Jedes erneute Zeichnen eines Frames löst eine Durchlaufung der Ansichtsbaumhierarchie aus, die bei der Stammansicht des Fensters beginnt. ViewCapture verwendet öffentliche View.java Getter-Methoden, um Werte abzurufen und in einen Hintergrundthread zu kopieren, um die Leistung zu verbessern. Die ViewCapture-Implementierung optimiert diesen Prozess, indem sie mit captureViewTreeprüft, ob eine Ansicht geändert oder ungültig ist. So wird die Durchlaufung der gesamten Ansichtshierarchie vermieden. captureViewTree ist nur für System-Apps verfügbar und Teil der UnsupportedAppUsage API. Die Verwendung dieser API ist auf Apps beschränkt, die auf der Ziel-SDK-Version basieren.

Beschränkungen

In diesem Abschnitt werden die Leistungs- und Arbeitsspeicherbeschränkungen von ViewCapture beschrieben.

Leistung

Der durchschnittliche Main-Thread-Overhead für die ViewCapture-Leistung beträgt 195 μs. Im schlimmsten Fall kann es jedoch etwa 5 ms dauern. Weitere Informationen finden Sie im vc#onDraw Slice im Perfetto Trace.

Die Overhead-Kosten sind hauptsächlich auf die folgenden Aktionen zurückzuführen:

  1. Das Durchlaufen der Hierarchie kostet 50 μs, auch wenn sie gekürzt ist.
  2. Das Abrufen von Objekten aus einem Freelist-Allocator zum Speichern von Kopien der Ansichtseigenschaften kostet 20 μs.
  3. Das Abrufen jedes Eigenschaftswerts über eine Getter-Funktion führt zu vielen zusätzlichen Funktionsaufrufen pro Ansicht und kostet 110 μs.

Wenn Sie ViewCapture in der Always-on-Tracerstellung (AOT) aktivieren, wirkt sich das negativ auf die Systemleistung aus und führt zu Rucklern. Aufgrund dieser Leistungs- und Arbeitsspeicherbeschränkungen ist dieser Ansatz nicht für AOT geeignet. Wir empfehlen ViewCapture nur für das Debugging im Labor und lokal.

Arbeitsspeicher

Die Methode von Perfetto für ViewCapture-Traces verwendet einen einzelnen Ringpuffer mit einem vordefinierten Speicherbedarf, um eine übermäßige Arbeitsspeichernutzung zu verhindern. Dieser Ansatz verhindert eine übermäßige Arbeitsspeichernutzung, da keine separaten Ringpuffer für jedes Fenster erforderlich sind. Das Problem, die gesamte Ansichtshierarchie für jeden Zustand in Perfetto für jeden Frame zu speichern, wird dadurch jedoch nicht gelöst. Wenn Sie ein einzelnes Fenster wie NexusLauncher aufzeichnen, können in einem 10-MB-Puffer mehr als 30 Sekunden an ViewCapture-Daten erfasst werden. Wenn Sie mehr als 30 Fenster aus der System-UI erfassen möchten, ist entweder ein größerer Puffer oder eine deutlich kürzere Aufzeichnungszeit erforderlich.

Anleitung

So binden Sie ViewCapture in System-Apps ein:

  1. Fügen Sie der Datei Android.bp die Abhängigkeit hinzu, wie in dem Launcher-Code gezeigt.

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. Erstellen Sie beim Erstellen des Fensters eine ViewCapture-Instanz, z. B.:

    • Beispiel 1:

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

      private SafeCloseable mViewCapture;
      
      @Override
      protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (enableViewCaptureTracing()) {
            mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
              .startCapture(getRootView(), ".NotificationShadeWindowView");
        }
        ...
      }
      
  3. Schließen Sie die ViewCapture-Instanz, wenn Sie das Fenster zerstören, wie in den folgenden Beispielen gezeigt:

    • Beispiel 1:

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

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