ניפוי אודיו

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

כיור טי

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

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

ההוראות בסעיף זה מיועדות לאנדרואיד 7.x ומעלה. עבור Android 5.x ו-6.x, החלף את /data/misc/audioserver ב- /data/misc/media . בנוסף, עליך להשתמש ב-userdebug או ב-eng build. אם אתה משתמש ב-userdebug build, השבת את verity באמצעות:

adb root && adb disable-verity && adb reboot

הגדרה בזמן הידור

  1. cd frameworks/av/services/audioflinger
  2. ערוך Configuration.h .
  3. בטל תגובה #define TEE_SINK .
  4. בנה מחדש libaudioflinger.so .
  5. adb root
  6. adb remount
  7. דחוף או סנכרן את libaudioflinger.so החדש ל- /system/lib של המכשיר.

הגדרת זמן ריצה

  1. adb shell getprop | grep ro.debuggable
    אשר שהפלט הוא: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    ודא שהפלט הוא:

    drwx------ media media ... media
    

    אם הספרייה לא קיימת, צור אותה באופן הבא:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    כאשר הערך af.tee הוא מספר המתואר להלן.
  5. chmod 644 /data/local.prop
  6. reboot

ערכים עבור נכס af.tee

הערך של af.tee הוא מספר בין 0 ל-7, המבטא סכום של מספר ביטים, אחד לכל תכונה. ראה את הקוד ב- AudioFlinger::AudioFlinger() ב- AudioFlinger.cpp להסבר על כל סיביות, אך בקצרה:

  • 1 = קלט
  • 2 = פלט FastMixer
  • 4 = AudioRecord ו- AudioTrack לכל רצועה

אין עדיין סיביות למאגר עמוק או למיקסר רגיל, אבל אתה יכול לקבל תוצאות דומות באמצעות "4".

בדוק ורכש נתונים

  1. הפעל את בדיקת השמע שלך.
  2. adb shell dumpsys media.audio_flinger
  3. חפש שורה בפלט של dumpsys כגון זה:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    זהו קובץ PCM .wav.
  4. לאחר מכן adb pull כל קבצי /data/misc/audioserver/*.wav המעניינים אותם; שים לב ששמות קבצי dump ספציפיים למסלול אינם מופיעים בפלט dumpsys , אך עדיין נשמרים ב- /data/misc/audioserver עם סגירת המסלול.
  5. סקור את קבצי ה-dump לחששות פרטיות לפני שתשתף עם אחרים.

הצעות

נסה את הרעיונות הבאים לקבלת תוצאות שימושיות יותר:

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

לשחזר

כפי שצוין לעיל, אין להשאיר את תכונת כיור הטי פעילה. שחזר את המבנה והמכשיר שלך באופן הבא:

  1. החזר את השינויים בקוד המקור ל- Configuration.h .
  2. בנה מחדש libaudioflinger.so .
  3. דחוף או סנכרן את libaudioflinger.so המשוחזר ל- /system/lib של המכשיר.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

פקודות מאקרו של ALOGx

ה-API הסטנדרטי לרישום שפת Java ב-Android SDK הוא android.util.Log .

ה-API של שפת C המקביל ב-Android NDK הוא __android_log_print המוצהר ב- <android/log.h> .

בתוך החלק המקורי של מסגרת אנדרואיד, אנו מעדיפים פקודות מאקרו בשם ALOGE , ALOGW , ALOGI , ALOGV וכו'. הם מוצהרים ב- <utils/Log.h> , ולמטרות מאמר זה נתייחס אליהם ביחד כ- ALOGx .

כל ממשקי ה-API הללו קלים לשימוש ומובנים היטב, כך שהם נפוצים בכל פלטפורמת האנדרואיד. בפרט תהליך mediaserver , הכולל את שרת הסאונד AudioFlinger, עושה שימוש נרחב ALOGx .

עם זאת, יש כמה מגבלות ל- ALOGx ולחברים:

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

NBLOG, media.log ו- MediaLogService

ממשקי ה-API NBLOG והתהליך media.log המשויך ושירות MediaLogService יוצרים יחד מערכת רישום חדשה יותר עבור מדיה, ותוכננו במיוחד כדי לטפל בבעיות שלמעלה. אנו נשתמש באופן רופף במונח "media.log" כדי להתייחס לשלושתם, אך באופן קפדני NBLOG הוא ה-API לרישום C++, media.log הוא שם תהליך לינוקס, ו- MediaLogService הוא שירות קלסר אנדרואיד לבחינת היומנים.

"ציר זמן" media.log הוא סדרה של רשומות יומן שהסדר היחסי שלהן נשמר. לפי המוסכמה, כל שרשור צריך להשתמש בציר הזמן שלו.

יתרונות

היתרונות של מערכת media.log הם בכך שהיא:

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

ארכיטקטורה

הדיאגרמה שלהלן מציגה את הקשר בין תהליך mediaserver לבין תהליך init , לפני הצגת media.log :

ארכיטקטורה לפני media.log

איור 1. ארכיטקטורה לפני media.log

נקודות בולטות:

  • init forks ו-execs mediaserver .
  • init מזהה את המוות של mediaserver , ומתפצלת מחדש לפי הצורך.
  • רישום ALOGx אינו מוצג.

התרשים שלהלן מציג את הקשר החדש של הרכיבים, לאחר הוספת media.log לארכיטקטורה:

ארכיטקטורה אחרי media.log

איור 2. ארכיטקטורה אחרי media.log

שינויים חשובים:

  • לקוחות משתמשים NBLOG API כדי לבנות ערכי יומן ולצרף אותם למאגר עגול בזיכרון משותף.
  • MediaLogService יכול לזרוק את התוכן של המאגר העגול בכל עת.
  • המאגר העגול מתוכנן כך שכל פגיעה בזיכרון המשותף לא תקרוס MediaLogService , והוא עדיין יוכל לזרוק כמה שיותר מהמאגר שאינו מושפע מהשחיתות.
  • המאגר העגול אינו חוסם וללא נעילה הן לכתיבת ערכים חדשים והן לקריאת ערכים קיימים.
  • לא נדרשות קריאות למערכת הקרנל כדי לכתוב או לקרוא מהמאגר העגול (מלבד חותמות זמן אופציונליות).

איפה להשתמש

נכון לאנדרואיד 4.4, יש רק כמה נקודות יומן ב-AudioFlinger שמשתמשות במערכת media.log . למרות שממשקי ה-API החדשים אינם קלים לשימוש כמו ALOGx , הם גם לא קשים במיוחד. אנו ממליצים לך ללמוד את מערכת הרישום החדשה לאותם מקרים שבהם היא חיונית. בפרט, זה מומלץ עבור שרשורים של AudioFlinger שחייבים לרוץ בתדירות גבוהה, מעת לעת וללא חסימה כגון שרשורי FastMixer ו- FastCapture .

איך להישתמש

הוסף יומנים

ראשית, עליך להוסיף יומנים לקוד שלך.

בשרשורי FastMixer ו- FastCapture , השתמש בקוד כגון זה:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

מכיוון שציר הזמן הזה NBLog משמש רק את השרשורים של FastMixer ו- FastCapture , אין צורך בהדרה הדדית.

בשרשורים אחרים של AudioFlinger, השתמש mNBLogWriter :

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

עבור שרשורים שאינם FastMixer ו- FastCapture , ניתן להשתמש בציר הזמן NBLog של השרשור הן על ידי השרשור עצמו והן על ידי פעולות מקשר. NBLog::Writer אינו מספק כל אי הכללה הדדית מרומזת לכל ציר זמן, אז ודא שכל היומנים מתרחשים בהקשר שבו ה-mutex mLock של השרשור מוחזק.

לאחר שהוספת את היומנים, בנה מחדש את AudioFlinger.

זהירות: נדרש ציר זמן נפרד NBLog::Writer לכל שרשור, כדי להבטיח את בטיחות השרשור, מכיוון שצירי זמן משמיטים את המוטקסים לפי התכנון. אם אתה רוצה שיותר משרשור אחד ישתמש באותו ציר זמן, אתה יכול להגן עם mutex קיים (כמתואר לעיל עבור mLock ). או שאתה יכול להשתמש במעטפת NBLog::LockedWriter במקום NBLog::Writer . עם זאת, זה שולל את היתרון העיקרי של API זה: ההתנהגות הבלתי חוסמת שלו.

ה-API המלא NBLog נמצא ב- frameworks/av/include/media/nbaio/NBLog.h .

הפעל את media.log

media.log מושבת כברירת מחדל. הוא פעיל רק כאשר הנכס ro.test_harness הוא 1 . אתה יכול להפעיל את זה על ידי:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

החיבור אבד במהלך אתחול מחדש, אז:

adb shell
הפקודה ps media תציג כעת שני תהליכים:
  • media.log
  • שרת מדיה

שימו לב למזהה התהליך של mediaserver למועד מאוחר יותר.

הצג את קווי הזמן

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

dumpsys media.log

שים לב שלפי עיצוב קווי זמן הם עצמאיים, ואין אפשרות למזג קווי זמן.

שחזור יומנים לאחר מוות של שרת המדיה

כעת נסה להרוג את תהליך mediaserver : kill -9 # , כאשר # הוא מזהה התהליך שציינת קודם לכן. אתה אמור לראות dump מ- media.log ב- logcat הראשי, המציגה את כל היומנים שהובילו לקריסה.

dumpsys media.log