לא משנה אם אתם יוצרים פרופיל מבוסס-אפליקציה או פרופיל מבוסס-טריגר, ProfilingManager שומר את הקובץ המלא במכשיר ושולח ProfilingResult לקריאה החוזרת (callback) הרשומה שלכם. מפעילים את ProfilingResult.getResultFilePath כדי לקבל את הנתיב של הפרופיל השמור:
- במהלך בדיקה מקומית: מושכים את הקובץ למחשב באמצעות
adb. - בסביבת ייצור: מעבירים את הנתיב למשימת
WorkManagerשמכווצת את הפרופיל ומעלה אותו לשרת.
אחזור פרופילים ממכשיר
בקטע הזה מוסבר איפה ProfilingManager שומר פרופילים במכשיר, איך פועל ניקוי הקבצים האוטומטי ואיך לשלוף קבצים באופן מקומי באמצעות adb.
מיקומי קבצים ופורמטים של שמות
ProfilingManager שומר פרופילים מצונזרים בספריית האחסון הספציפית לאפליקציה ב-/data/user/0/<app>/files/profiling/. הפורמט של שם הקובץ תלוי באופן שבו הפרופיל נלכד:
פרופילים מבוססי-אפליקציה:
profile_<tag>_<datetime>_uid-<uid>.<profile-type-ext>אם לא צוין תג בבקשה לפרופיל,
<tag>_מושמט:profile_<datetime>_uid-<uid>.<profile-type-ext>.פרופילים שמבוססים על טריגרים:
profile_trigger-type-<trigger_type>_<datetime>_uid-<uid>.<profile-type-ext>
כאשר:
-
<app>הוא שם החבילה של האפליקציה. -
<tag>הוא עד 20 התווים האלפאנומריים הראשונים (ומקפים) של התג שסופק על ידי המתקשר, שהוגדר באמצעותsetTagאו הועבר אלrequestProfiling, הומר לאותיות קטנות, וכל התווים מחוץ ל-a-z, ל-0-9ול--הוסרו. -
<trigger_type>הוא קוד קבוע של מספר שלם לטריגר מ-ProfilingTrigger. תמיד צריך להפעיל אתProfilingResult.getTriggerTypeבקוד במקום לנתח את שם הקובץ. -
<datetime>הוא התאריך והשעה שבהם הפרופיל תועד (yyyy-MM-dd-HH-mm-ss-SSS). -
<uid>הוא מזהה המשתמש של האפליקציה ב-Linux (כלול בגרסאות האחרונות של המודולProfiling). -
<profile-type-ext>היא סיומת הקובץ של סוג הפרופיל שנוצר:.perfetto-traceלעקבות המערכת-
.perfetto-java-heap-dumpלתמונות מצב של הזיכרון מ-Java -
.perfetto-heap-profileלתמונות מצב של ערימה -
.perfetto-stack-sampleלפרופילים של דגימת מחסנית
אחסון וניקוי במכשיר
כדי לפנות נפח האחסון במכשיר באופן מיידי, מחקו כל קובץ פרופיל ב-worker של ההעלאה מיד אחרי שההעלאה מסתיימת (כי הניקוי האוטומטי פועל רק כש-ProfilingManager מעביר תוצאות לאפליקציה, וקבצים שלא הועלו יכולים להישאר בדיסק אם האפליקציה מפסיקה לרשום קריאות חוזרות אחרי סיום הקמפיין). כגיבוי בגרסאות האחרונות של מודול Profiling, ProfilingManager גם מוחק באופן אוטומטי קבצים שנמסרו בספריית האחסון הספציפית לאפליקציה, אם הם ישנים יותר מ-5 ימים, כשנמסרות תוצאות חדשות.
העלאת פרופילים בסביבת הייצור באמצעות WorkManager
מכיוון שגודל הקבצים של הפרופילים יכול להיות כמה מגה-בייט, כדאי לתזמן את ההעלאות של גרסת הייצור ברקע כשהמכשיר מחובר לרשת ללא הגבלת נפח (Wi-Fi), נטען ולא בשימוש.
לפני ההעלאה, דוחסים את קובץ הפרופיל (לדוגמה, באמצעות GZIPOutputStream או ZipOutputStream). פרופילי Perfetto protobuf ותמונות מצב של הזיכרון ב-Java נדחסים באופן משמעותי, וכך מפחיתים את רוחב הפס של הרשת ואת עלויות האחסון בקצה העורפי.
הוספת יחסי תלות של WorkManager
ProfilingManager לא תלוי בענן, כך שאפשר לתזמן את העלאת הפרופילים לכל בקאנד באמצעות WorkManager. מוסיפים את הספרייה WorkManager לקובץ build.gradle.kts:
Kotlin
dependencies { implementation("androidx.work:work-runtime:2.12.0") }
מגניב
dependencies { implementation 'androidx.work:work-runtime:2.12.0' }
תזמון של משימת העלאה
כשהאפליקציה מקבלת ProfilingResult, מתזמנים את משימת ההעלאה. בדוגמה הבאה לא מופיעה בקשת הפרופיילינג הראשונית. דוגמה לבקשה מלאה מופיעה בקטע תיעוד עקבות המערכת.
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()); }
הדרכה מפורטת על הקוד
בדוגמה שלמעלה מתבצעים השלבים הבאים:
- הגדרת ה-worker: יוצרים מחלקה של
TraceUploadWorkerשמרחיבה אתWorker. מטמיעים אתdoWorkכדי לוודא שקובץ הפרופיל עדיין קיים, דוחסים ומעלים אותו באמצעות ה-SDK לקצה העורפי או צד הלקוח ב-HTTP, ומוחקים את הקובץ המקומי אחרי שההעלאה מסתיימת. - תזמון העבודה:
- יוצרים
OneTimeWorkRequestלעובד. - הגדרת אילוצים: משתמשים ב-
setRequiredNetworkType(NetworkType.UNMETERED), ב-setRequiresDeviceIdle(true)וב-setRequiresCharging(true)כדי שההעלאה תפעל רק כשהמכשיר מחובר ל-Wi-Fi, נטען ולא בשימוש. - העברת נתונים: משתמשים ב-
setInputDataכדי להעביר את נתיב הפרופיל מ-getResultFilePathל-worker. - Enqueue: שליחת הבקשה אל
WorkManagerבאמצעות קריאה ל-WorkManager.enqueue.
- יוצרים
השלבים הבאים
אחרי שאחזרתם או העליתם פרופילים, אתם יכולים להציג אותם בממשק המשתמש של Perfetto, להריץ שאילתות על פרופילים ספציפיים באמצעות PerfettoSQL, לנתח עקבות בכמות גדולה או לנתח פרופילים באמצעות AI. במאמר פריסת Bigtrace ב-Kubernetes מוסבר איך להגדיר צינור עיבוד נתונים לניתוח בצד השרת, שניתן להתאים לעומס.