זיהוי של תקלות בממשק המשתמש

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

כשמתרחשת בעיה של jank, בדרך כלל זה קורה בגלל האטה או חסימה של קריאה אסינכרונית ב-thread של ממשק המשתמש (ברוב האפליקציות, זה ה-thread הראשי). אפשר להשתמש במעקב מערכת כדי לזהות את מקור הבעיה.

זיהוי של תנועות קופצות ב-Android מגרסה 12 ואילך

במכשירים עם Android 12 (API ברמה 31) ומעלה, מעקב שנתפס מוצג במסלול Janky frames בחלונית Display ב-CPU Profiler.

כדי לזהות בעיות בממשק (jank):

  1. ב-Android Studio, בוחרים באפשרות View > Tool Windows > Profiler (תצוגה > חלונות כלים > כלי לניתוח ביצועים) או לוחצים על Profile (ניתוח ביצועים) בסרגל הכלים.

    אם מופיעה תיבת הדו-שיח Select Deployment Target (בחירת יעד פריסה), בוחרים את המכשיר שבו רוצים לפרוס את האפליקציה לצורך יצירת פרופיל. אם חיברתם מכשיר באמצעות USB אבל הוא לא מופיע ברשימה, צריך לוודא שהפעלתם ניפוי באגים ב-USB.

  2. לוחצים במקום כלשהו בציר הזמן של CPU כדי לפתוח את הכלי CPU Profiler.

  3. בתפריט ההגדרות של CPU Profiler, בוחרים באפשרות System Trace ולוחצים על Record. אחרי שמסיימים את האינטראקציה עם האפליקציה, לוחצים על עצירה.

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

  5. אחרי שמוצאים פריים עם תנועה קופצנית, לוחצים עליו. אפשר גם להקיש על M כדי לשנות את רמת הזום ולהתמקד בפריים שנבחר. האירועים הרלוונטיים מודגשים ב-threads האלה: ה-thread הראשי, RenderThread ו-GPU completion. צילום מסך של Profiler שבו מוצגים פריימים עם תנועות קופצות ושרשורים ראשיים

  6. אפשר גם לראות את כל המסגרות או פירוט של זמן העיבוד. כדי לעשות זאת, מסמנים את תיבות הסימון All Frames (כל המסגרות) ו-Lifecycle (מחזור חיים), בהתאמה. צילום מסך של כלי הפרופיל כמו שלמעלה, אבל עם תיבות הסימון All Frames (כל המסגרות) ו-Lifecycle (מחזור חיים) מסומנות

זיהוי של תנועות קופצות ב-Android 11

במכשירים עם Android 11 (רמת API‏ 30), טראס שצולם מוצג בקטע Frame Lifecycle ב-CPU Profiler.

קטע של מחזור החיים של מסגרת עם טראקים שונים

הקטע Frame Lifecycle מכיל את שם השכבה וארבעה טראקים. כל רכיב מייצג שלב אחד בצינור הרינדור של המסגרת. הרכיבים של מחזור החיים של מסגרת הם:

  1. Frame Lifecycle (Layer name): שם השכבה מופיע בסוגריים בשם הקטע. שכבה היא יחידה אחת של קומפוזיציה.
  2. Application: המסלול הזה מראה את הזמן שחלף מהרגע שבו המאגר הוצא מהתור על ידי האפליקציה ועד הרגע שבו הוא הוכנס בחזרה לתור. בדרך כלל, זה תואם לאירועי המעקב ב-RenderThread.
  3. המתנה ל-GPU: בטראק הזה מוצג משך הזמן שהמאגר היה בבעלות ה-GPU. זהו הזמן שחולף מרגע שליחת המאגר אל ה-GPU ועד שה-GPU מסיים את העבודה שלו על המאגר. הנתון הזה לא מציין שיחידת ה-GPU פעלה רק על המאגר הזה במהלך הזמן הזה. כדי לקבל מידע מפורט על מה שה-GPU עובד עליו במהלך פרק זמן מסוים, מומלץ להשתמש ב-Android GPU Inspector.
  4. הרכב: במסלול הזה מוצג הזמן שחל מהרגע שבו SurfaceFlinger מתחבר למאגר ושולח אותו להרכבה, ועד שהמאגר נשלח לתצוגה.
  5. פריימים שמוצגים: בטראק הזה מוצג משך הזמן שבו הפריימים הוצגו במסך.

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

ב-Android Studio מוצגים גם כל הפריימים בטבלת המעקב בפורמט של טבלה בכרטיסייה All Frames.

טבלה של כל המסגרות בנתוני המעקב בכרטיסייה All Frames (כל המסגרות)

העמודות Frame #‎,‏ Application,‏ Wait for GPU ו-Composition מייצגות את אותם נתונים כמו הרצועות בקטע Frame Lifecycle שמופיע למעלה. העמודה משך הפריים מייצגת את הזמן שחלף מתחילת האפליקציה ועד לתחילת הפריימים שמוצגים. זהו משך הזמן שנדרש כדי לעבד פריים מקצה לקצה.

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

כדי לזהות ולחקור את הבעיה של תנועה קופצנית ב-Android 11, מבצעים את השלבים הבאים:

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

    העמודה 'אפליקציה' ממוינת בסדר יורד

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

    תצוגת ציר זמן לצד טבלת מסגרות

  3. מחפשים שרשורים רלוונטיים בקטעים Frame Lifecycle ו-Threads.

    הקטעים 'מחזור החיים של מסגרות' ו'שרשורים'

זיהוי של jank ב-Android מגרסה 10 ומטה

במכשירים עם Android מגרסה 10 (רמת API‏ 29) ומטה, מידע רלוונטי על צינור הגרפיקה של מערכת ההפעלה מוצג בקטע יחיד במעקב המערכת של CPU Profiler שנקרא Display.

חלון ממשק המשתמש של התצוגה

  • מסגרות: בקטע הזה מוצגים שרשור ממשק המשתמש ואירועי מעקב RenderThread באפליקציה. אירועים שנמשכים יותר מ-16 אלפיות השנייה צבועים באדום כדי להדגיש מסגרות פוטנציאליות עם תנועה קופצנית, כי הם חורגים מהזמן המוקצב לעיבוד ב-60 פריימים לשנייה (fps).
  • SurfaceFlinger: בקטע הזה מוצג מתי SurfaceFlinger מעבד את מאגרי המסגרות. ‫SurfaceFlinger הוא תהליך מערכת שאחראי לשליחת מאגרי נתונים לתצוגה.
  • VSYNC: בקטע הזה מוצג VSYNC, אות שמסנכרן את צינור התצוגה. בטראק מוצג האות VSYNC-app, שמראה מתי האפליקציה מתחילה מאוחר מדי. בדרך כלל, זה קורה כי ה-thread של ממשק המשתמש עמוס. היא גורמת להבהוב גלוי במסך במהלך אנימציה, ומוסיפה חביון קלט נוסף עד שהאנימציה או הגלילה מסתיימות. הנתון הזה חשוב במיוחד לצפייה במסכים עם קצב רענון גבוה, כי יכול להיות שהם יתרחשו בתדירות גבוהה יותר מ-60 פעמים בשנייה או בקצב משתנה.
  • BufferQueue: בקטע הזה מוצג מספר מאגרי הפריימים שנמצאים בתור וממתינים לצריכה על ידי SurfaceFlinger. באפליקציות שמופעלות במכשירים עם Android 9 (רמת API‏ 28) ומעלה, אפשר לראות את מספר המאגרים של BufferQueue (0,‏ 1 או 2) של משטח האפליקציה. BufferQueue יכול לעזור לכם להבין את המצב של מאגרי התמונות כשהם עוברים בין רכיבי הגרפיקה של Android. לדוגמה, ערך של 2 מציין שהאפליקציה משתמשת כרגע בזיכרון משולש, מה שגורם לזמן אחזור נוסף של קלט.

בקטע Display מוצגים אותות שימושיים לזיהוי בעיות פוטנציאליות בממשק (jank). לדוגמה, אם השרשור של ממשק המשתמש או RenderThread נמשך יותר מ-16 אלפיות השנייה. כדי לבדוק פרטים מדויקים לגבי הגורם לבעיות בממשק, אפשר לעיין בקטע Threads, שבו מוצגים השרשורים שרלוונטיים לעיבוד התמונה של ממשק המשתמש.

הקטע 'פרוטוקולי Thread' בקטע 'תצוגה'

באיור שלמעלה, בקטע Threads מוצגים שרשור ממשק המשתמש (java.com.google.samples.apps.iosched), RenderThread והשרשור GPU completion. אלה השרשורים שרלוונטיים לרינדור של ממשק המשתמש ועשויים לתרום לבעיות בביצועים.

כדי לזהות jank ב-Android מגרסה 10 ומטה, פועלים לפי השלבים הבאים:

  1. מעיינים בטראק Frames (מסגרות) בDisplay (תצוגה). המסגרות האדומות הן מועמדות לבדיקה.

    הקטע 'מסגרות' בקטע 'תצוגה'

  2. אם מזהים פריים עם תנועה קופצנית, אפשר להגדיל אותו על ידי הקשה על W או גלגול גלגל העכבר תוך כדי לחיצה על Control (Command ב-macOS). ממשיכים להתקרב עד שמתחילים לראות את אירועי המעקב בשרשור של ממשק המשתמש ואת RenderThread.

    מעקב אחרי אירועים בשרשור של ממשק המשתמש וב-RenderThread

    באיור שלמעלה, Choreographer#doFrame מופיע כששרשור ממשק המשתמש קורא ל-Choreographer כדי לתאם בין אנימציה, פריסת תצוגה, ציור תמונה ותהליכים קשורים. DrawFrames הערך הזה מציין מתי RenderThread יוצר פקודות ציור בפועל ל-GPU.

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

    תפריט שבו מוצג משך הזמן המדויק של רכיב בממשק המשתמש

מידע נוסף

מידע נוסף על צמצום ה-jank זמין במאמר מקורות נפוצים ל-jank.