ניפוי באגים ומקרי ANR

פתרון שגיאות ANR במשחק ל-Unity הוא תהליך מערכתי:

איור 1. שלבים לפתרון בעיות ANR במשחקים של Unity.

שילוב שירותי דיווח

שירותי דיווח כמו Android vitals,‏ Firebase Crashlytics ו-Backtrace (שותף מוסמך של Unity) מספקים רישום שגיאות וניתוח של המשחק בקנה מידה נרחב. כדאי לשלב את ערכות ה-SDK של שירותי הדיווח במשחק בשלב מוקדם של מחזור הפיתוח. לנתח איזה שירות דיווח הכי מתאים לצרכים ולתקציב של המשחק.

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

שילוב של ערכות SDK לדיווח לא משפיע על ביצועי המשחק או על גודל ה-APK.

ניתוח סמלים

בודקים את הדוחות משירות הדיווח ובודקים אם נתוני מעקב ה-stack בפורמט שאפשר לקרוא על ידי בני אדם. מידע נוסף זמין במאמר סימולציה של קריסות ו-ANR ב-Android למשחקי Unity.

איור 2. קריסה של נתונים שמציגים את מזהה ה-build וחסרים סמלי libil2cpp.so.

איך בודקים את מזהה ה-build של הסמל

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

ב-Windows או ב-macOS:

  1. עוברים לתיקיית הסמלים בהתאם לקצה העורפי של הסקריפט (ראו פתרון:)
    1. משתמשים בפקודה הבאה (ב-Windows, משתמשים ב-Cygwin כדי להריץ את השירות readelf)
    2. השימוש ב-Grep הוא אופציונלי כדי לסנן את פלט הטקסט
    3. צריך לחפש את מזהה ה-Build
readelf -n libil2cpp.so | grep 'Build ID'
Build ID: b42473fb7449e44e0182dd1f580c99bab0cd8a95

בדיקת קוד המשחק

אם ב-stack trace מופיעה פונקציה בספרייה libil2cpp.so, השגיאה התרחשה בקוד C# ‎ שהומר ל-C++‎. בספרייה libil2cpp.so יש לא רק את קוד המשחק, אלא גם יישומי פלאגין וחבילות.

שם הקובץ ב-C++ תואם לשם האסיפה שהוגדר בפרויקט Unity. אחרת, שם הקובץ יהיה שם ברירת המחדל של Assembly-C#. לדוגמה, באיור 3 מוצגת השגיאה בקובץ Game.cpp (מודגש בכחול), שהוא השם שהוגדר בקובץ הגדרת האסיפה. Logger הוא שם המחלקה (מודגש באדום) בסקריפט C# , ואחריו שם הפונקציה (מודגש בירוק). השם המלא שנוצר על ידי ממיר IL2CPP (מודגש בכתום).

איור 3. בדיקת סטאק הקריאות של הפרויקט מ-Backtrace.

כדי לבדוק את קוד המשחק:

  • בודקים את הפרויקט ב-C# כדי לאתר קוד חשוד. בדרך כלל, חריגות שלא טופלו ב-C# לא גורמות ל-ANR או לקריסה של האפליקציה. עם זאת, חשוב לוודא שהקוד פועל כמו שצריך במצבים שונים. בודקים אם הקוד משתמש במודול מנוע של צד שלישי, ומנתחים אם השגיאה נגרמה בגלל גרסה שפורסמה לאחרונה. בנוסף, כדאי לבדוק אם עדכנתם לאחרונה את Unity או אם השגיאה מתרחשת רק במכשירים ספציפיים.
  • מייצאים את המשחק כפרויקט Android Studio. גישה מלאה לקוד המקור המומר של המשחק ב-C# מאפשרת לכם למצוא את הפונקציה שגורמת ל-ANR. הקוד ב-C++ נראה שונה מאוד מהקוד ב-C#, ובעיות בהמרת הקוד הן נדירות. אם תמצאו משהו, תוכלו לשלוח כרטיס תמיכה ל-Unity.
  • בודקים את קוד המקור של המשחק ומוודאים שכל הלוגיקה שפועלת בקריאות החזרה (callbacks) של OnApplicationFocus()‎ ו-OnApplicationPause()‎ מתבצעת בצורה תקינה.
    • למנוע Unity יש זמן קצוב להשהיית הביצוע. עומס עבודה מוגזם בקריאות החזרה האלה יכול לגרום ל-ANR.
    • להוסיף יומנים או נתיבי ניווט לחלקים מהקוד כדי לשפר את ניתוח הנתונים.
  • משתמשים ב-Unity Profiler כדי לבדוק את הביצועים של המשחק. יצירת פרופיל של האפליקציה היא גם דרך מצוינת לזהות צווארי בקבוק שעשויים לגרום ל-ANR.
  • דרך מצוינת לזהות פעולות קלט/פלט ארוכות ב-thread הראשי היא להשתמש במצב מחמיר.
  • ניתוח היסטוריית הדיווח של Android Vitals או של שירות אחר, ובדיקה של גרסאות המשחק שפורסמו ועם השגיאה שמופיעה בהן הכי הרבה. בודקים את קוד המקור בהיסטוריית בקרת הגרסאות ומשווים בין שינויי הקוד בין גרסאות. אם מצאתם משהו חשוד, נסו כל שינוי או תיקון פוטנציאלי בנפרד.
  • בודקים את היסטוריית הדיווחים על מקרי ANR ב-Google Play לגבי המכשירים וגרסאות Android שמקבלים את מספר הדיווחים הגבוה ביותר על מקרי ANR. אם המכשירים או הגרסאות לא עדכניים, סביר להניח שאפשר להתעלם מהם בבטחה אם הפעולה הזו לא משפיעה על הרווחיות של המשחק. חשוב לבדוק את הנתונים האלה היטב, כי קבוצה מסוימת של משתמשים לא תוכל יותר לשחק במשחק. מידע נוסף מופיע במרכז הבקרה של ההפצה.
  • בודקים את קוד המקור של המשחק כדי לוודא שלא קוראים לקוד שעלול לגרום לבעיה. לדוגמה, השימוש ב-finish יכול להיות הרסני אם לא משתמשים בו בצורה נכונה. מידע נוסף על פיתוח ל-Android זמין במדריכים למפתחים של Android.
  • אחרי בדיקת הנתונים וייצוא הגרסה היציבה של המשחק ל-Android Studio, אתם עובדים עם קוד C ו-C++. כך תוכלו להפיק תועלת מלאה מהכלים מעבר לפתרונות הרגילים של Unity, כמו Android Memory Profiler,‏ Android CPU Profiler ו-perfetto.

קוד מנוע Unity

כדי לדעת אם אירוע ANR מתרחש בצד של מנוע Unity, מחפשים את הערכים libUnity.so או libMain.so בנתוני המעקב אחר סטאק. אם מצאתם אותם, בצעו את הפעולות הבאות:

  • קודם כול, כדאי לחפש בערוצי הקהילה (Unity Forums, ‏ Unity Discussions, ‏ Stackoverflow).
  • אם לא מוצאים דבר, אפשר לדווח על באג כדי לפתור את הבעיה. יש לספק מעקב סטאק מסמל כדי שמהנדסי המנוע יוכלו להבין טוב יותר את השגיאה ולפתור אותה.
  • בודקים אם ב-Unity LTS העדכני ביותר בוצעו שיפורים שקשורים לבעיות שלכם. אם כן, צריך לשדרג את המשחק כך שישתמש בגרסה הזו. (יכול להיות שהפתרון הזה אפשרי רק למפתחים מסוימים).
  • אם הקוד משתמש ב-Activity מותאם אישית במקום בברירת המחדל, צריך לבדוק את הקוד של Java כדי לוודא שהפעילות לא גורמת לבעיות.

SDK של צד שלישי

  • בודקים שכל הספריות של צד שלישי עדכניות ושאין דיווחים על קריסות או על אירועי ANR בגרסה האחרונה של Android.
  • אפשר להיכנס לפורומים של Unity כדי לבדוק אם השגיאות כבר טופלו בגרסה מאוחרת יותר, או אם Unity או חבר קהילה סיפקו פתרון זמני.
  • מעיינים בדוח ה-ANR של Google Play ומוודאים ש-Google לא זיהתה את השגיאה. Google מודעת לחלק ממקרי ה-ANR ופועלת באופן פעיל לתיקון שלהם.

ספריית המערכת

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

סיבות ליציאה

ApplicationExitInfo הוא ממשק API ל-Android שעוזר להבין את הגורמים לשגיאות ANR. אם המשחק שלכם מבוסס על Unity 6 ואילך, תוכלו להפעיל את ApplicationExitInfo ישירות. בגרסאות ישנות יותר של Unity, תצטרכו להטמיע פלאגין משלכם כדי להפעיל קריאות ApplicationExitInfo מ-Unity.

גם Crashlytics משתמש ב-ApplicationExitInfo, אבל הטמעה משלכם מאפשרת לכם לשלוט בצורה מדויקת יותר ולצרף מידע רלוונטי יותר.