Unabhängig davon, ob Sie ein App-gesteuertes Profil oder ein Trigger-basiertes Profil erfassen, speichert ProfilingManager die fertige Datei auf dem Gerät und liefert einen ProfilingResult an Ihren registrierten Callback. Rufen Sie ProfilingResult.getResultFilePath auf, um den Pfad des gespeicherten Profils abzurufen:
- Bei lokalen Tests: Ziehen Sie die Datei mit
adbauf Ihren Computer. - In der Produktion: Übergeben Sie den Pfad zu einem
WorkManager-Job, der das Profil komprimiert und auf Ihren Server hochlädt.
Profile von einem Gerät abrufen
In diesem Abschnitt wird beschrieben, wo ProfilingManager Profile auf dem Gerät speichert, wie die automatische Dateibereinigung funktioniert und wie Sie Dateien mit adb lokal abrufen.
Dateispeicherorte und Namensformate
ProfilingManager speichert die bearbeiteten Profile in Ihrem anwendungsspezifischen Speicherverzeichnis unter /data/user/0/<app>/files/profiling/. Das Format des Dateinamens hängt davon ab, wie das Profil erfasst wurde:
App-gesteuerte Profile:
profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>Wenn beim Anfordern des Profils kein Tag angegeben wurde, wird
<tag>_weggelassen:profile_<datetime>_uid-<uid>.<profile-type-ext>.Triggerbasierte Profile:
profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
Wobei:
<app>ist der Paketname Ihrer App.<tag>besteht aus den ersten 20 alphanumerischen Zeichen (und Bindestrichen) des vom Aufrufer bereitgestellten Tags, das mitsetTagkonfiguriert oder anrequestProfilingübergeben wurde. Es wird in Kleinbuchstaben umgewandelt und alle Zeichen außerhalb vona-z,0-9und-werden entfernt.<trigger_type>ist der ganzzahlige Konstantencode für den Trigger ausProfilingTrigger. Rufen Sie im Code immerProfilingResult.getTriggerTypeauf, anstatt den Dateinamen zu parsen.<datetime>ist das Datum und die Uhrzeit, zu der das Profil aufgezeichnet wurde (yyyy-MM-dd-HH-mm-ss-SSS).<uid>ist die Linux-Nutzer-ID Ihrer App (in aktuellenProfiling-Modulversionen enthalten).<profile-type-ext>ist die Dateiendung für den erfassten Profiltyp:.perfetto-tracefür System-Traces.perfetto-java-heap-dumpfür Java-Heap-Dumps.perfetto-heap-profilefür Heap-Profile.perfetto-stack-samplefür Stack-Sampling-Profile
Speicherplatz auf dem Gerät und Bereinigung
Wenn Sie schnell Speicherplatz auf dem Gerät freigeben möchten, löschen Sie jede Profildatei in Ihrem Upload-Worker sofort nach einem erfolgreichen Upload. Da die automatische Bereinigung nur ausgeführt wird, wenn ProfilingManager Ergebnisse an Ihre App liefert, können nicht hochgeladene Dateien sonst auf dem Laufwerk verbleiben, wenn Ihre App nach dem Beenden einer Kampagne keine Callbacks mehr registriert. Als Fallback für aktuelle Profiling-Modulversionen löscht ProfilingManager auch automatisch bereitgestellte Dateien in Ihrem app-spezifischen Speicherverzeichnis, die älter als 5 Tage sind, wenn neue Ergebnisse bereitgestellt werden.
Profile in der Produktion mit WorkManager hochladen
Da Profildateien mehrere Megabyte groß sein können, sollten Sie Uploads im Hintergrund planen, wenn das Gerät mit einem Netzwerk ohne Datenlimit (WLAN) verbunden ist, geladen wird und inaktiv ist.
Komprimieren Sie die Profildatei vor dem Hochladen (z. B. mit GZIPOutputStream oder ZipOutputStream). Perfetto-Protobuf-Profile und Java-Heap-Dumps werden erheblich komprimiert, was die Netzwerkbandbreite und die Kosten für den Back-End-Speicher reduziert.
WorkManager-Abhängigkeiten hinzufügen
ProfilingManager ist cloudunabhängig, sodass Sie den Upload von Profilen in ein beliebiges Backend mit WorkManager planen können. Fügen Sie die Bibliothek WorkManager zu der Datei build.gradle.kts hinzu:
Kotlin
dependencies { implementation("androidx.work:work-runtime:2.12.0") }
Groovy
dependencies { implementation 'androidx.work:work-runtime:2.12.0' }
Upload-Job planen
Wenn Ihre App eine ProfilingResult empfängt, planen Sie den Uploadjob. Im folgenden Beispiel wird die erste Profilerstellungsanfrage weggelassen. Ein vollständiges Anfragebeispiel finden Sie unter System-Trace aufzeichnen.
Kotlin
class TraceUploadWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) { override fun doWork(): Result { // Perform your uploading work here Log.d("ProfileTest", "Uploading trace: " + inputData.getString("PROFILE_PATH")) return Result.success() } } fun setupProfileUploadWorker(profileFilepath: String?) { val workMgr = WorkManager.getInstance(applicationContext) val workRequestBuilder = OneTimeWorkRequest.Builder(TraceUploadWorker::class) val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build() workRequestBuilder.setConstraints(constraints) val inputDataBuilder = Data.Builder() inputDataBuilder.putString("PROFILE_PATH", profileFilepath) workRequestBuilder.setInputData(inputDataBuilder.build()) workMgr.enqueue(workRequestBuilder.build()) }
Java
public static class TraceUploadWorker extends Worker { public TraceUploadWorker( @androidx.annotation.NonNull Context context, @androidx.annotation.NonNull WorkerParameters workerParams) { super(context, workerParams); } @androidx.annotation.NonNull @Override public Result doWork() { // Perform your uploading work here Log.d("ProfileTest", "Uploading trace: " + getInputData().getString("PROFILE_PATH")); return Result.success(); } } public void setupProfileUploadWorker(String profileFilepath) { WorkManager workMgr = WorkManager.getInstance(getApplicationContext()); OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder( TraceUploadWorker.class); Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresDeviceIdle(true) .setRequiresCharging(true) .build(); workRequestBuilder.setConstraints(constraints); Data.Builder inputDataBuilder = new Data.Builder(); inputDataBuilder.putString("PROFILE_PATH", profileFilepath); workRequestBuilder.setInputData(inputDataBuilder.build()); workMgr.enqueue(workRequestBuilder.build()); }
Code-Anleitung
Im vorherigen Beispiel werden die folgenden Schritte ausgeführt:
- Worker definieren: Erstellen Sie eine
TraceUploadWorker-Klasse, dieWorkererweitert. ImplementieredoWork, um zu prüfen, ob die Profildatei noch vorhanden ist, komprimiere sie und lade sie mit deinem Backend-SDK oder HTTP-Client hoch. Lösche die lokale Datei, sobald der Upload erfolgreich war. - Arbeit planen:
- Erstellen Sie einen
OneTimeWorkRequestfür Ihren Worker. - Einschränkungen festlegen: Verwende
setRequiredNetworkType(NetworkType.UNMETERED),setRequiresDeviceIdle(true)undsetRequiresCharging(true), damit der Upload nur ausgeführt wird, wenn das Gerät mit dem WLAN verbunden ist, geladen wird und sich im Ruhemodus befindet. - Daten übergeben: Verwenden Sie
setInputData, um den Profilpfad vongetResultFilePathan den Worker zu übergeben. - In die Warteschlange stellen: Senden Sie die Anfrage an
WorkManager, indem SieWorkManager.enqueueaufrufen.
- Erstellen Sie einen
Nächste Schritte
Nachdem Sie Profile abgerufen oder hochgeladen haben, können Sie sie in der Perfetto-Benutzeroberfläche visualisieren, einzelne Profile mit PerfettoSQL abfragen, Traces im Bulk analysieren oder Profile mit KI analysieren. Eine Anleitung zum Einrichten einer skalierbaren serverseitigen Analysepipeline finden Sie unter Bigtrace in Kubernetes bereitstellen.