ניפוי באגים ב-SDV

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

מתחברים למכשיר

הכלי העיקרי להתחברות למכשיר ולביצוע פעולות בו הוא ממשק הגישור של Android‏ (ADB). מוודאים שהנתיב של adb נמצא בנתיב של המערכת.

חיבור באמצעות הרשת

אם המכשיר נמצא באותה רשת ואתם יודעים את כתובת ה-IP שלו, אתם יכולים להתחבר באמצעות אתרנט. המערכת שלנו משתמשת רק בחיבורי רשת ל-adb:

# Connect to the device using its IP address and default port
adb connect <device_ip_address>:5555

חיבור למספר מכשירים

כדי לנהל כמה מכשירים מתחנת עבודה אחת, אתם יכולים להתחבר אליהם דרך כתובות IP שונות. אם אתם מריצים כמה מכונות וירטואליות במארח אחד, אתם צריכים להקצות יציאות שונות לכל מכשיר. כדי לעשות את זה, צריך להגדיר את ה-daemon של adb בכל מכשיר SDV כך שיאזין ליציאה ייחודית, למשל 5555 למכשיר הראשון ו-5556 למכשיר השני. אפשר גם להגדיר את המארח כך שיעביר את היציאות האלה לאורחים שונים:

# Connect to the first device
adb connect <device_1_ip_address>:5555

# Connect to a second device
adb connect <device_2_ip_address>:5555

# Connect to a second VM on first device on different port
adb connect <device_1_ip_address>:5556

# List all connected devices to verify
adb devices

כשמריצים פקודות adb נוספות, אפשר לטרגט מכשיר ספציפי באמצעות הדגל -s עם הכתובת המלאה שלו (ip:port):

# Run a shell command on the second VM on first device in the above example
adb -s <device_1_ip_address>:5556 shell

צפייה ביומנים

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

שימוש ב-logcat (יומני Android)

ב-logcat מוצגים יומנים משירותי המערכת, מסוכנים ומחבילות שירות:

# View all logs in real-time
adb logcat

# Filter logs by a specific tag (e.g., the name of your service)
adb logcat -s MyServiceTag

# Filter logs by priority (V: Verbose, D: Debug, I: Info, W: Warn, E: Error, F: Fatal)
# This shows only Error and Fatal messages for a specific tag
adb logcat MyServiceTag:E *:S

# Clear old logs before viewing new ones
adb logcat -c && adb logcat

# Show all logs and return
adb logcat -d

# Color logs by level
adb logcat -v color

# Show timestamps as time since boot
adb logcat -v monotonic

שימוש ב-dmesg (יומני ליבה)

הפקודה dmesg מציגה יומנים מליבת Linux. זה חיוני לניפוי באגים במקרים הבאים:

  • בעיות בחומרה ובדרייברים
  • תגובות לשגיאות ליבה קריטיות
  • דחיות של SELinux‏ (avc: denied) – מוצגות גם ב-logcat
# View all kernel messages
adb shell dmesg

# Follow kernel messages in real-time
adb shell dmesg -w

גישה ליומנים ב-Cuttlefish

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

  • ‫Logcat (יומני Android): cuttlefish/instances/cvd-1/logs/logcat
  • יומני ליבה (kernel): cuttlefish/instances/cvd-1/logs/kernel.log
  • יומני מרכז האפליקציות של Cuttlefish: cuttlefish/instances/cvd-1/logs/launcher.log (שימושיים לניפוי באגים בסביבת Cuttlefish עצמה)

אתם יכולים להשתמש בכלי שורת פקודה רגילים כמו cat,‏ less או tail -f כדי להציג את הקבצים האלה בזמן אמת.

אינטראקציה עם המעטפת ומערכת הקבצים

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

# Open an interactive shell on the device
adb shell

# From within the shell, you can check running processes
ps -A

# Or check the status of a specific service managed by init
getprop init.svc.<service_name>

ביצוע פעולות במערכת הקבצים

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

# Push a file from your computer to the device
adb push my_local_file.txt /data/local/tmp/

# Pull a file from the device to your computer
adb pull /data/tombstones/tombstone_00 .

ניפוי באגים באפליקציות (C++/Rust)

אפשר לנפות באגים באפליקציות אונליין או אופליין.

שימוש ב-lldb לניפוי באגים בזמן אמת

כדי לנפות באגים בשירות בזמן אמת באמצעות lldb, פועלים לפי השלבים הבאים (כדי לצרף את מנפה הבאגים מ-Android Studio for Platform, עיינו במאמרים ניפוי באגים ובדיקה וניפוי באגים בקוד הפלטפורמה):

  1. מפעילים מחדש את adb עם הרשאות בסיס (נדרש להעברה ליציאה אחרת):

    adb root
    
  2. אם לקובץ בינארי יש סמלים לניפוי באגים, צריך להעביר גרסה לא מופשטת מ-out/target/product/[SDV_FLAVOR]/symbols/[PARTITION]/bin/[EXECUTABLE]. לדוגמה, כדי להעלות את rpcagent מ-system_ext ומ-sdv_core_cf, מריצים את הפקודה:

    adb push out/target/product/sdv_core_cf/symbols/system_ext/bin/rpcagent /data/local/tmp
    
  3. מתחברים ללקוח LLDB באמצעות הסקריפט הנוח lldbclient.py:

    # Run and connect a binary on device, run on host:
    lldbclient.py -r /data/local/tmp/rpcagent
    
    # Connect to an existing process with PID 2759
    lldbclient.py -p 2759
    

    הסקריפט הזה מחבר את lldb מרחוק. כדי לראות את כל הדגלים הזמינים, מריצים את הפקודה lldbclient.py --help.

ניתוח קובצי dump של קריסות (tombstones)

כששירות קורס, נוצר קובץ tombstone ב-/data/tombstones/. הקובץ מכיל דוח קריסות, מפת זיכרון ומידע חיוני אחר.

שולפים את קובץ ה-tombstone ומשתמשים בכלי שמזהה סמלים (כמו lldb או סקריפט ייעודי) כדי לנתח אותו באמצעות הגרסה הלא מופשטת של הקובץ הבינארי.

ניתוח הביצועים

ב-SDV יש כמה כלים למדידת ביצועים.

בדיקת השימוש במעבד (CPU) ובזיכרון

  • ‫top: מציג בזמן אמת את התהליכים שפועלים, ממוינים לפי השימוש ב-CPU.

    adb shell top -m 10  # Show top 10 processes
    
  • ‫procrank: פירוט של השימוש בזיכרון בתהליך ספציפי או במערכת כולה.

    adb shell procrank
    

שימוש ב-dumpsys למצב השירות

‫dumpsys הוא כלי יעיל לשליחת שאילתות לגבי המצב הפנימי של כל שירות מערכת ב-Android.

# List all available services
adb shell dumpsys -l

# Dump the state of a specific service or agent
adb shell dumpsys <service_name>

שימוש ב-torq לניתוח ביצועים

‫torq הוא כלי שורת פקודה שמפשט את משימות יצירת הפרופילים והמעקב ב-Android. הוא מאפשר להריץ את Simpleperf, את Perfetto ומשימות אופייניות אחרות במהלך ניתוח ביצועי המערכת.

שימוש ב-Perfetto למעקב

‫Perfetto הוא הכלי הרגיל למעקב ברמת המערכת ב-Android. בעזרת Perfetto אפשר לתעד אירועי מערכת, נקודות מעקב ברמת האפליקציה ומוני ביצועים, ולהציג אותם בציר זמן.

השלבים העיקריים:

  1. מוסיפים נקודות מעקב בקוד C++‎ או Rust:
    • ‫C++‎: משתמשים ב-Perfetto SDK עם פקודות מאקרו של TRACE_EVENT.
    • ‫Rust: משתמשים בארגז tracing, שפולט אירועי ATrace שתואמים ל-Perfetto.
  2. יוצרים קובץ תצורה מסוג textproto כדי לציין מקורות נתונים (לדוגמה, ftrace, track_event), קטגוריות ותגים.
  3. משתמשים בסקריפט record_android_trace (external/perfetto/tools/record_android_trace) עם קובץ התצורה כדי לתעד את המעקב מהמכשיר.
  4. פותחים את קובץ המעקב שנוצר בממשק המשתמש של Perfetto באינטרנט כדי לנתח את התנהגות המערכת, לזהות צווארי בקבוק ולהבין את האינטראקציות בין השירותים.

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

שימוש ב-Simpleperf ליצירת פרופילים

‫Simpleperf הוא כלי שורת פקודה רב-תכליתי ליצירת פרופילים של ביצועים ב-Android, בדומה ל-perf של Linux.

תרחישים נפוצים לדוגמה:

  • יצירת פרופיל של המעבד: זיהוי הפונקציות שצורכות הכי הרבה זמן מעבד.
  • ניתוח מחוץ למעבד (CPU): ניתוח הסיבות לכך ששרשורים נמצאים במצב שינה או חסומים.
  • מוני חומרה: גישה למוני ביצועים של חומרה.

פקודות לדוגמה:

# Go to simpleperf scripts
cd system/extras/simpleperf/scripts

# Profile system for 20 seconds and record call graph
./app_profiler.py --system_wide -r "--call-graph fp --duration 20"

# Record a profile for a specific process (PID 1)
./app_profiler.py --pid 1 -r "--call-graph fp --duration 5"

# Pull the profile data
adb pull /data/local/tmp/perf.data .

# Generate a report with symbol resolution
./report_html.py --add_source_code --source_dirs $ANDROID_BUILD_TOP --add_disassembly -o report.html

Simpleperf מציע עוד הרבה אירועים ואפשרויות. במדריך ל-Simpleperf יש מסמכי תיעוד מקיפים.

דחיות של SELinux

תיאור הבעיה: השירות לא מתחיל, לא ניגש לקובץ או לא משתמש ביכולת, ומופיעה הודעת avc: denied ב-dmesg או ב-logcat.

[ 123.456] avc: denied { read } for pid=789 comm="my_service" name="some_file" dev="sda1" ino=123 scontext=u:r:my_service_t:s0 tcontext=u:object_r:some_file_t:s0 tclass=file permissive=0

ניפוי באגים מהיר (למטרות פיתוח בלבד)

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

# Disabling SELinux requires root permission
adb root

# Set SELinux to permissive mode
adb shell setenforce 0

# Check the current mode (should return "Permissive")
adb shell getenforce

תיקון: הכלי audit2allow מעץ המקור של Android בהודעת הדחייה. כך נוצר כלל המדיניות הנכון של .te שצריך להוסיף להגדרת SELinux של המכשיר.