מעקב אחר מעברים בחלונות באמצעות Winscope

Winscope הוא כלי אינטרנט שמאפשר למשתמשים לתעד, להפעיל מחדש ולנתח את המצבים של כמה שירותי מערכת במהלך אנימציות ומעברים ואחריהן. Winscope מתעד את כל מצבי השירות הרלוונטיים במערכת בקובץ מעקב. באמצעות ממשק המשתמש של Winscope עם קובץ המעקב, אפשר לבדוק את המצב של השירותים האלה בכל פריים של האנימציה, עם או בלי הקלטת מסך, על ידי הפעלה חוזרת של המעברים, ניתוח שלהם בניתוחים צעדים ותיקון באגים.

מעקבים נתמכים

Winscope מאפשר לאסוף מעקבים שונים או רצפים של מצבי שירות המערכת ולהציג אותם באופן חזותי. אפשר להגדיר את הטרייסים האלה בהתאם לתרחישי שימוש ספציפיים, החל מעומסי עבודה נמוכים ועד לרמת פירוט גבוהה. אלה הטראסים שנתמכים ב-Winscope:

  • EventLog: איסוף הרשומה של אירוע האבחון של המערכת באמצעות EventLog. ב-Winscope, המידע הזה משמש רק לזיהוי ולתצוגה של סימנים של CUJ.
  • IME: מעקב אחר אירועים מצינור עיבוד הנתונים של עורך שיטות הקלט (IME), כולל IMS,‏ IMMS ו-IME Client.
  • קלט: מעקב אחר אירועי קלט מחלקים שונים בצינור עיבוד הנתונים של אירועי הקלט.
  • ProtoLog: איסוף הודעות ProtoLog משירותי המערכת והקוד של שירותי המערכת שפועלים בתהליכי הלקוח.
  • הקלטת מסך: צילום מסך לצד הנתונים.
  • מעבר בין מעטפות: תיעוד פרטי המערכת של מעבר בין חלונות ופעילויות.
  • SurfaceFlinger: איסוף נתוני מעקב של SurfaceFlinger שמכילים מידע על משטחים (שכבות), כמו מיקום, מאגר ותמהיל.
  • Transactions: מעקב אחרי קבוצת השינויים האטומיים שהתקבלו על ידי SurfaceFlinger באמצעות SurfaceControl לצורך יצירה.
  • ViewCapture: צילום מגוון מאפיינים של כל התצוגות מחלונות המערכת שתומכים ב-ViewCapture, כמו ממשק המשתמש של המערכת ומרכז האפליקציות.
  • מנהל חלונות: מעקב אחרי מצבים של מנהל החלונות שמכילים פרטים שקשורים לחלונות, כולל אירועי קלט ומיקוד, כיוון המסך, מעברים, אנימציות, מיקום וטרנספורמציות.

קובצי dump נתמכים

Winscope יכול לאסוף ולהציג דמפים של מצב, שהם קובצי snapshot של מצב המכשיר שצולמו ברגעים ספציפיים שהוגדרו על ידי המשתמש. בניגוד למעקב אחר נתונים, שנאסף באופן רציף במהלך השימוש במכשיר ויכול להשפיע על הביצועים, יצירת קבצים זמניים מתבצעת רק ברגעים שהוגדרו על ידי המשתמש, כדי להבטיח שהביצועים והרמת רמת הפירוט לא יושפעו. כך אפשר לבצע ניתוח ממוקד ויעיל יותר של מצב המכשיר בנקודות זמן ספציפיות. אלה קובצי ה-dump שנתמכים ב-Winscope:

  • מנהל חלונות: יצירת גרסת dump של מצב יחיד של מנהל החלונות.
  • SurfaceFlinger: יצירת dump של קובץ snapshot יחיד של SurfaceFlinger.
  • צילום מסך: צריך לצלם מסך לצד ה-dumps.

משאבים

במאמר הפעלת Winscope מוסבר איך יוצרים ומפעילים את Winscope.

מידע נוסף על איסוף נתוני מעקב זמין במאמר תיעוד נתוני מעקב.

במאמר העלאת נתוני מעקב מוסבר איך מעלים נתוני מעקב באמצעות ממשק המשתמש של Winscope באינטרנט.

מידע נוסף על ניתוח נתוני מעקב זמין במאמר ניתוח נתוני מעקב.

דוגמאות

בדוגמה הבאה מוסבר איך לנפות באגים של כשל בבדיקה של הבהוב ובאג שדווח על ידי משתמש.

הבדיקה של התנודות בבהירות נכשלה

בדוגמה הזו מוסבר איך משתמשים ב-Winscope כדי לנפות באגים בבדיקה של הבהוב.

בדיקת הכישלון בבדיקה

כדי לקבוע את סוג הבעיה ולבדוק את הודעת הכישלון של הבדיקה, פועלים לפי השלבים הבאים.

  1. כדי לקבוע את סוג הבעיה, בודקים את שם המבחן ואת שם הכיתה.

    שם הבדיקה והכיתה:

    FlickerTestsNotification com.android.server.wm.flicker.notification.OpenAppFromLockscreenNotificationColdTest#appLayerBecomesVisible[ROTATION_0_GESTURAL_NAV]
    

    סוג הבעיה:

    • ב-CUJ מתייחסים להפעלת אפליקציה מהתראה במסך הנעילה (OpenAppFromLockscreenNotificationColdTest).

    • לפי הבדיקה, האפליקציה אמורה להיות גלויה (#appLayerBecomesVisible).

  2. בודקים את הודעת הכשל של הבדיקה, שמספקת מידע מקיף על הכשל, כולל:

    • השוואה בין התוצאה הצפויה לבין התוצאה הגלויה בפועל
    • חותמות זמן שיעזרו לכם לזהות מתי אירעה התקלה
    • השם של הארטיפקט או הקובץ שמשויכים לכשלים
    • מידע נוסף לפי הקשר שרלוונטי להבנת התקלה ולניפוי הבאגים שלה
    android.tools.flicker.subject.exceptions.IncorrectVisibilityException: com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity# should be visible
    
    Where?
        Timestamp(UNIX=2024-05-10T11:04:14.227572545(1715339054227572545ns), UPTIME=37m21s184ms79178ns(2241184079178ns), ELAPSED=0ns)
    
    What?
        Expected: com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#
        Actual: [e636ecd com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3457: Buffer is empty, Visible region calculated by Composition Engine is empty, com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458: Visible region calculated by Composition Engine is empty]
    
    Other information
        Artifact: FAIL__OpenAppFromLockscreenNotificationColdTest_ROTATION_0_GESTURAL_NAV.zip
    
    Check the test run artifacts for trace files
    
        at android.tools.flicker.subject.layers.LayerTraceEntrySubject.isVisible(LayerTraceEntrySubject.kt:187)
        at android.tools.flicker.subject.layers.LayersTraceSubject$isVisible$1$1.invoke(LayersTraceSubject.kt:151)
        at android.tools.flicker.subject.layers.LayersTraceSubject$isVisible$1$1.invoke(LayersTraceSubject.kt:150)
        at android.tools.flicker.assertions.NamedAssertion.invoke(NamedAssertion.kt:32)
        at android.tools.flicker.assertions.CompoundAssertion.invoke(CompoundAssertion.kt:42)
        at android.tools.flicker.assertions.AssertionsChecker.test(AssertionsChecker.kt:79)
        at android.tools.flicker.subject.FlickerTraceSubject.forAllEntries(FlickerTraceSubject.kt:59)
        at android.tools.flicker.assertions.AssertionDataFactory$createTraceAssertion$closedAssertion$1.invoke(AssertionDataFactory.kt:46)
        at android.tools.flicker.assertions.AssertionDataFactory$createTraceAssertion$closedAssertion$1.invoke(AssertionDataFactory.kt:43)
        at android.tools.flicker.assertions.AssertionDataImpl.checkAssertion(AssertionDataImpl.kt:33)
        at android.tools.flicker.assertions.ReaderAssertionRunner.doRunAssertion(ReaderAssertionRunner.kt:35)
        at android.tools.flicker.assertions.ReaderAssertionRunner.runAssertion(ReaderAssertionRunner.kt:29)
        at android.tools.flicker.assertions.BaseAssertionRunner.runAssertion(BaseAssertionRunner.kt:36)
        at android.tools.flicker.legacy.LegacyFlickerTest.doProcess(LegacyFlickerTest.kt:59)
        at android.tools.flicker.assertions.BaseFlickerTest.assertLayers(BaseFlickerTest.kt:89)
        at com.android.server.wm.flicker.notification.OpenAppTransition.appLayerBecomesVisible_coldStart(OpenAppTransition.kt:51)
        at com.android.server.wm.flicker.notification.OpenAppFromNotificationColdTest.appLayerBecomesVisible(OpenAppFromNotificationColdTest.kt:64)
    

    דוגמת הפלט הזו מציינת את הפרטים הבאים:

    • הבעיה מתרחשת ב-2024-05-10T11:04:14.227572545.

    • NotificationActivity אמור להיות גלוי, אבל הוא לא גלוי.

    • שם קובץ הארטיפקט שמכיל את הטרייסים לניפוי באגים הוא FAIL__OpenAppFromLockscreenNotificationColdTest_ROTATION_0_GESTURAL_NAV.

ניפוי באגים

כדי לקבוע מה גורם לרטט:

  1. מורידים את קובצי המעקב ומטעינים אותם ב-Winscope. Winscope נפתח עם SurfaceFlinger שנבחר באופן אוטומטי:

    דף נחיתה של Winscope עם תצוגת SurfaceFlinger

    איור 1. דף נחיתה של Winscope עם תצוגת SurfaceFlinger.

  2. כדי לנווט לחותמת הזמן שבה מתרחשת הבעיה, מעתיקים את חותמת הזמן מהודעת החריגה ומדביקים אותה בשדה חותמת הזמן. אפשר להעתיק את חותמת הזמן בפורמט שקריא לבני אדם (2024-05-10T11:04:14.227572545) ולהדביק אותה בשדה הראשון, או להעתיק את חותמת הזמן בננו-שניות (1715339054227572545ns) ולהדביק אותה בשדה השני.

    תיבת דו-שיח של חותמת זמן

    איור 2. תיבת הדו-שיח של חותמת הזמן.

  3. מקישים על מקש החץ שמאלה כדי לנווט לפריים הקודם. במצב הזה, אפליקציית NotificationActivity מוצגת בסרטון בצורה תקינה, וניתן לראות את פני השטח של האפליקציה ושל מסך הפתיחה. הם מסומנים בקופסאות ירוקות בתצוגה התלת-ממדית ובצ'יפ V באלמנטי ההיררכיה שלהם.

    השמות של האפליקציה ומסך הפתיחה הם:

    com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458`
    
    Splash Screen com.android.server.wm.flicker.testapp#3453
    

    המשמעות היא שהאפליקציה הופעל כשהמסך הפך לשחור, והאירוע הזה מתרחש במהלך הפעלת האפליקציה כי מסך הפתיחה עדיין גלוי:

    בזמן הפעלת האפליקציה

    איור 3. כשהאפליקציה מופעלת.

  4. מקישים על מקש החץ ימינה כדי לנווט חזרה לפריים הבא, שבו מתרחש הפליקרים. בתצוגת rects, NotificationShade מוצג במסך במקום האפליקציה. המשטחים הבאים מוצגים בפריים הזה:

    • שכבות-על לקישוט המסך (למעלה ולמטה)
    • סרגל הניווט
    • מיקום הסמן (מהקלטת המסך)

      פעילות של הבהוב

      איור 4. פעילות של הבהוב.

  5. בוחרים את פעילות האפליקציה בתצוגת ההיררכיה. אם הוא לא מופיע, משביתים את המתג שליד Show only V. לאחר מכן, בודקים את תצוגת הנכסים.

    שם פני האפליקציה הוא:

    com.android.server.wm.flicker.testapp/com.android.server.wm.flicker.testapp.NotificationActivity#3458`
    

    נכסי אפליקציות

    איור 5. נכסי אפליקציות.

    פעילות האפליקציה מוגדרת כגלויה ואטומה, אבל השטח לא מוצג בגלל שגיאה מסוג Invisible due to: null visible region. הסיבה לכך היא שפני שטח אטומים נוספים הוצבו לפניו במהלך יצירת התמונה. ההשערה הזו נובעת מכך שהריבוע NotificationShade נמצא מול הריבוע NotificationActivity בתצוגה התלת-ממדית, וייתכן שהריבוע NotificationShade הגלוי (הירוק) הוא השכבה שנבחרה.

  6. כדי לאמת את ההשערה הזו, בוחרים את פני השטח NotificationShade הגלוי בפריים הנוכחי ובודקים את המאפיינים שלו. הדגלים מוגדרים לערך OPAQUE|ENABLE_BACKPRESSURE (0x102). שם הפלטפורמה של NotificationShade הוא NotificationShade#3447. לאחר מכן, לוחצים על החץ ימינה כדי לחזור לפריים הקודם (לפני הפליקרים) ובודקים שוב את המאפיינים של המשטח NotificationShade. שימו לב שבמקום OPAQUE, הדגל ENABLE_BACKPRESSURE (0x100) מופיע רק על פני השטח. כך אפשר לוודא ש-NotificationShade הופך לאטום לפני שהאפליקציה מוכנה להשקה. מכיוון שה-NotificationShade מופיע לפני ה-NotificationActivity, האפליקציה לא מוצגת. ה-NotificationShade הוא שחור, ולכן המסך משחיר לרגע, מה שגורם לרטט.

  7. בודקים בקוד למה NotificationShade הופך לאטום מוקדם מדי.

באג שדווח על ידי משתמש

לפעמים קשה לנפות באגים שדווחו על ידי משתמשים כי לרוב הם לא כוללים מידע מפורט. בניגוד לכשל בבדיקה של הבהוב, שמספק חותמות זמן ספציפיות, פרטי רכיבים והקלטות מסך, בדרך כלל באגים שמדווחים על ידי משתמשים כוללים רק תיאור קצר של הבעיה.

בדוח המחקר שלנו, המידע היחיד שסופק הוא הכותרת המסך הבהיק כשפתחתי מחדש את האפליקציה מהמסך המפוצל וחותמת זמן משוערת של 18 באפריל 2024, 15:51 (שעון גריניץ', שעה פחות 4).

כדי לנפות באג שדווח על ידי משתמש:

  1. טוענים את קובץ המעקב ב-Winscope. Winscope נפתח עם SurfaceFlinger שנבחר באופן אוטומטי.

    דף נחיתה של Winscope עם תצוגת SurfaceFlinger

    איור 6. דף נחיתה של Winscope עם תצוגת SurfaceFlinger.

  2. כדי לנווט לחותמת הזמן המשוערת שדווחה על ידי המשתמש, במקרה הזה 3:50 PM GMT-04:00, מזינים 15:50:00 בשדה של חותמת הזמן שקריא לבני אדם.

    תיבת דו-שיח של חותמת זמן

    איור 7. תיבת הדו-שיח של חותמת הזמן.

  3. משתמשים בתצוגת rects כדי לזהות מה צויר על המסך. כדי לקבל תצוגה טובה יותר, משתמשים בפס ההזזה Rotation כדי לשנות את הפרספקטיבה של המלבנים. אם מסמנים את האפשרויות Show only V ו-Flat בתצוגה Hierarchy, אפשר לראות את הטפט, שכבת-העל של 'עיצוב המסך', פורמט Letterbox, מרכז האפליקציות, אנשי הקשר ומסך החיוג.

    שמות החבילות הם:

    • מרכז האפליקציות: com.google.android.apps.nexuslauncher/com.google.android.apps.nexuslauncher.NexusLauncherActivity#40602

    • אנשי קשר: com.google.android.contacts/com.android.contacts.activities.PeopleActivity#40565

    • Dialer: ‏ com.google.android.dialer/com.google.android.dialer.extensions.GoogleDialtactsActivity#40564

    בנוסף למשטחים הגלויים (ריבועים ירוקים), מוצג מלבן אפור שמייצג את המשטח של אזור התצוגה, שנקרא Unknown display. כדי לשפר את החשיפה, לוחצים על (סמל החשיפה) לצד המשטח ScreenDecorHwcOverlay#64 כדי להסתיר את המלבן התואם ולהציג את המשטחים שמאחוריו. אנחנו מסירים את שכבת-העל לצורך הניתוח כי היא לא גלויה למשתמש ולא תדווח כאנימציה מהבהבת.

    דוח משתמשים

    איור 8. דוח משתמש.

  4. אחרי שמזהים את המשטחים שקשורים לתצוגת המסך המפוצל, משתמשים בניתוח המעברות כדי לעבור על פעולות שונות של משתמשים ולמצוא את התנודות. לוחצים על הכרטיסייה Transitions ב-Winscope כדי להציג גרפית את רשימת המעברים שהופעלו:

    מעברים

    איור 9. מעברים.

    המעבר שהופעל במהלך הפריים הזה מודגש בכחול. במקרה הזה, דגלים המעבר כוללים את הערך TRANSIT_FLAG_IS_RECENTS, שמציין שהמשתמש נכנס למסך 'מהזמן האחרון'.

  5. לוחצים על הקישור בעמודה Dispatch Time (במקרה הזה 2024-04-18, 15:50:57.205) כדי לנווט לנקודת הזמן הזו ולאמת את ה-rects בכרטיסייה Surface Flinger. כדי לוודא שהמצב של המכשיר תקין במהלך המעבר, אפשר להקיש על מקש החץ הימני ולעקוב אחרי המעבר תוך התבוננות ב-rects.

    מרכז האפליקציות מופיע בשעה 15:50:57.278, אבל האנימציה לא מתחילה באותו זמן. הטפט כבר גלוי כי לא מצויר דבר בין האפליקציות במסך המפוצל (המחיצה). בפריים אחד קודם (15:50:57.212), הטפט לא גלוי והמפריד מוצג. כך נראה המסך המפוצל כשאין אנימציה.

    המסך לפני הפליקרים

    איור 10. המסך לפני אירוע הבהוב.

  6. כדי לבדוק את המעבר הבא, לוחצים ישירות על ציר הזמן. המצבים של SurfaceFlinger מיוצגים בשורה של בלוקים כחולים בהירים. מעברים מיוצגים בשורה של בלוקים ורוד.

    סוף המעבר הראשון

    איור 11. סוף המעבר הראשון.

    לוחצים על השורה SurfaceFlinger במיקום ההתחלה של המעבר הבא. באיור 11, המיקום האנכי של הסמן מסומן על ידי הקו הכחול הדק. הרקע הכחול בהיר של השורה SurfaceFlinger מציג את המיקום האופקי שלה. מקישים על מקש החץ ימינה כדי לעבור בין התמונות ולראות אם יש הבהוב. מוודאים שהמכשיר נראה מתאים למעבר הזה.

  7. כדאי לדלג על המעבר הבא כי משך הזמן שלו קצר מאוד, ולכן סביר להניח שהוא לא מכיל הבהוב. במקום זאת, לוחצים על ציר הזמן בשורה של SurfaceFlinger במיקום ההתחלה של המעבר הארוך הבא, כפי שמצוין על ידי הסמן בתמונה הבאה.

    סוף המעבר השני

    איור 12. סוף המעבר השני.

    במהלך המעבר הזה, בשלב 15:51:13.239, אפשר לראות שהשכבות Splash Screen של שתי האפליקציות, אנשי הקשר והמרכז לחיוג נמצאות באותו צד של המסך:

    מסכי פתיחה

    איור 13. מסכי פתיחה.

  8. יש לציין איזו אפליקציה נמצאת בצד הלא נכון. כדי להוסיף סימנייה למיקום הנוכחי, לוחצים על סמל הדגל לצד שדה הקלט ns. כך תוכלו לחזור למסגרת הזו מאוחר יותר.

    הוספת סימנייה

    איור 14. מוסיפים סימנייה.

  9. כדי לנווט למסגרת בסוף המעבר, לוחצים ישירות על ציר הזמן, למשל על 15:51:13.859. כאן שתי האפליקציות נמצאות במיקום הסופי שלהן, עם חייגן בצד ימין ואנשי קשר בצד שמאל:

    המסך המפוצל הסופי

    איור 15. המסך המפוצל הסופי.

  10. לוחצים על הדגל של הסימניה בציר הזמן כדי לחזור לפריים עם התנודות.

    ציר הזמן של הסימניות

    איור 16. ציר הזמן של הסימניות.

    שתי האפליקציות נמצאות בצד שמאל, מה שמצביע על כך שהחייגן נמצא במיקום שגוי.

  11. לוחצים על מסך הפתיחה של חייגן כדי להציג את המאפיינים שלו. כדאי לבדוק במיוחד את מאפייני הטרנספורמציה שלו בתצוגה נכסים שנבחרו.

    טרנספורמציה של מאפיינים

    איור 17. טרנספורמציה של מאפיינים.

    הטרנספורמציה המחושבת חלה על המשטח הזה, אבל לא מוגדרת ברמה הזו. העמודות המחושבות והעמודות המבוקשות כוללות ערכים שונים, מה שמציין שהטרנספורמציה עוברת בירושה מפני השטח של ההורה.

  12. מבטלים את הבחירה באפשרות Flat בתצוגה היררכית כדי להציג את עץ ההיררכיה כולו, מנווטים לקודמי העץ של ממשק האפליקציה עד שהטרנספורמציות Calculated ו-Requested זהות, ומציגים את הטרנספורמציה שנשלחה לממשק Surface(name=Task=7934)/@0x1941191_transition-leash#40670.

  13. מוודאים מתי הטרנספורמציה הוגדרה לראשונה ואיזה ערך הוגדרה. כדי לכווץ את הנכסים שנבחרו, לוחצים על הסמל לצד השם:

    לכווץ את הנכסים שנבחרו

    איור 18. מכווצים את הנכסים שנבחרו.

  14. בוחרים באפשרות Show diff בתצוגה Proto Dump כדי להדגיש את המאפיינים שמשתנים בפריים הזה. מקלידים transform בשדה החיפוש של הטקסט כדי לסנן את המאפיינים:

    show diff

    איור 19. הצגת ההבדלים.

    ההמרה מוגדרת מ-IDENTITY ל-SCALE|TRANSLATE|ROT_270 בפריים הזה של transition-leash.

    המידע הזה מראה שהבהוב התרחש כשהטרנספורמציה הוחלו על שרשור האנימציה של האפליקציה של חייגן המסך המפוצל.

    זיהוי הפליקרים

    איור 20. זיהוי התנודות.

  15. מאתרים בקוד את הסיבה לכך שהטרנספורמציה הזו מוגדרת לשרשור המעבר למסך מפוצל.