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 an die Fenster angehängt sind, an die es angehängt ist. Mit ViewCapture werden Informationen zu den verschiedenen Ansichten innerhalb eines Fensters und ihren Properties erfasst. So können Sie den Zustand der Nutzererfahrung zu bestimmten Zeitpunkten ermitteln und Änderungen im Zeitverlauf verfolgen.

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

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

Verwenden

ViewCapture.java implementiert eine Instanz von onDrawListener und erfasst während des Zeichnens eine ViewCapture-Spur. Jedes Neuzeichnen des Frames löst eine Durchlaufung der Ansichtsstruktur aus, beginnend bei der Stammansicht des Fensters. ViewCapture verwendet öffentliche View.java-Gettermethoden, um Werte abzurufen und in einen Hintergrund-Thread zu kopieren, um die Leistung zu verbessern. Die ViewCapture-Implementierung optimiert diesen Vorgang, indem mit captureViewTree geprüft wird, ob eine Ansicht ungültig ist oder geändert wurde. So wird das Durchlaufen der gesamten Ansichtshierarchie vermieden. captureViewTree ist nur für System-Apps verfügbar und Teil der UnsupportedAppUsage API. Die Nutzung dieser API ist auf Apps beschränkt, die die Ziel-SDK-Version verwenden.

Beschränkungen

In den folgenden Abschnitten werden die Leistungs- und Arbeitsspeichereinschränkungen beim Ausführen von ViewCapture beschrieben.

Leistung

Der durchschnittliche Overhead des Hauptthreads für die ViewCapture-Leistung beträgt 195 μs. Im schlimmsten Fall kann es jedoch etwa 5 ms dauern. Sehen Sie sich dazu den vc#onDraw-Speichereintrag im Perfetto-Trace an.

Die Gemeinkosten sind hauptsächlich auf die folgenden Aktionen zurückzuführen:

  1. Das Durchlaufen der Hierarchie kostet 50 µs, auch wenn sie beschnitten wurde.
  2. Das Abrufen von Objekten aus einem Freelist-Allocator zum Speichern von Kopien von Datensatzeigenschaften kostet 20 µs.
  3. Wenn Sie jeden Property-Wert über eine Getter-Funktion abrufen, führt das zu vielen zusätzlichen Funktionsaufrufen pro Ansicht, was 110 µs kostet.

Wenn Sie ViewCapture bei der Always-On-Aufzeichnung (AOT) aktivieren, wirkt sich das negativ auf die Systemleistung aus und führt zu Rucklern. Aufgrund dieser Leistungs- und Speichereinschränkungen ist dieser Ansatz nicht für AOT geeignet. Wir empfehlen ViewCapture nur für Labs und lokales Debuggen.

Arbeitsspeicher

Die Methode von Perfetto für ViewCapture-Traces verwendet einen einzelnen Ringbuffer mit einem vordefinierten Arbeitsspeicherbedarf, um eine übermäßige Arbeitsspeichernutzung zu verhindern. Dieser Ansatz verhindert einen übermäßigen Arbeitsspeicherverbrauch, da keine separaten Ringbuffer für jedes Fenster verwendet werden. Das Problem, dass die gesamte Ansichtshierarchie für jeden Status in Perfetto für jeden Frame gespeichert wird, wird dadurch jedoch nicht behoben. Wenn Sie ein einzelnes Fenster wie NexusLauncher aufzeichnen, können über 30 Sekunden an ViewCapture-Daten in einem 10-MB-Puffer generiert werden. Wenn Sie jedoch mehr als 30 Fenster aus der Systemoberfläche erfassen möchten, ist entweder ein größerer Puffer oder ein deutlich kürzerer Aufnahmezeitraum erforderlich.

Anleitung

So richten Sie ViewCapture in System-Apps ein:

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

    android_library {
        name: "YourLib",
        static_libs: [
              ...
            "//frameworks/libs/systemui:view_capture",
              ...
        ],
        platform_apis: true,
        privileged: true,
    }
    
  2. Erstellen Sie eine ViewCapture-Instanz, wenn Sie das Fenster erstellen, z. B. so:

    • 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 schließen, 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();
       }
        ...
      }