במאמר הזה נתאר כמה טיפים וטריקים לניפוי באגים בנושא אודיו ב-Android.
כיור טי
"כיור טי" תואם לערך תכונת ניפוי באגים של AudioFlinger, שזמינה בגרסאות build בהתאמה אישית בלבד, לשמירת קטע קצר מהאודיו האחרון לניתוח מאוחר יותר. כך ניתן להשוות בין התוכן שהושמע או הוקלט בפועל לעומת מה שציפיתי.
מטעמי פרטיות, tee sink מושבת כברירת מחדל, גם בזמן ההידור וגם בזמן הריצה. כדי להשתמש ב-tee sink, תצטרכו להפעיל אותו על ידי הידור מחדש, וגם הגדרת נכס. חשוב להשבית את התכונה הזו אחרי לבצע ניפוי באגים. אין להשאיר את ה-teesink מופעלים בגרסאות build לסביבת הייצור.
ההוראות בקטע הזה מיועדות ל-Android מגרסה 7.x ואילך. ב-Android
5.x ו-6.x, מחליפים את /data/misc/audioserver
ב-
/data/misc/media
. כמו כן, צריך להשתמש ב-userdebug או
יצירת עניין. אם משתמשים ב-build של ניפוי באגים במשתמש, משביתים את האימות באמצעות:
adb root && adb disable-verity && adb reboot
הגדרה בזמן הידור
cd frameworks/av/services/audioflinger
- עריכה של
Configuration.h
. - ביטול התגובה
#define TEE_SINK
. - בנייה מחדש של
libaudioflinger.so
. adb root
adb remount
- דוחפים או מסנכרנים את
libaudioflinger.so
החדש עם/system/lib
של המכשיר.
הגדרה בזמן ריצה
adb shell getprop | grep ro.debuggable
עליכם לוודא שהפלט יהיה:[ro.debuggable]: [1]
adb shell
ls -ld /data/misc/audioserver
מוודאים שהפלט יהיה:
drwx------ media media ... media
אם הספרייה לא קיימת, יוצרים אותה באופן הבא:
mkdir /data/misc/audioserver
chown media:media /data/misc/audioserver
echo af.tee=# > /data/local.prop
כאשר הערךaf.tee
הוא מספר שמתואר בהמשך.chmod 644 /data/local.prop
reboot
ערכים של נכס af.tee
הערך של af.tee
הוא מספר בין 0 ל-7, מבטא
בסכום של כמה ביטים, אחד לכל פיצ'ר.
אפשר לראות את הקוד בכתובת AudioFlinger::AudioFlinger()
ב-AudioFlinger.cpp
הסבר על כל קטע, אבל בקצרה:
- 1 = קלט
- 2 = פלט FastMixer
- 4 = לכל טראק AudioRecord ו-AudioTrack
עדיין אין מספיק מקום למאגר נתונים זמני או למיקסר רגיל, אבל אפשר לקבל תוצאות דומות באמצעות "4".
בדיקה והשגת נתונים
- מפעילים את בדיקת האודיו.
adb shell dumpsys media.audio_flinger
- צריך לחפש שורה בפלט
dumpsys
, כמו:
tee copied to /data/misc/audioserver/20131010101147_2.wav
זהו קובץ .wav של PCM. - לאחר מכן
adb pull
קבצים של/data/misc/audioserver/*.wav
שעשויים לעניין אותך; שימו לב ששמות קבצים של קובצי dump ספציפיים לטראק לא מופיעים פלטdumpsys
, אבל עדיין נשמרות ב-/data/misc/audioserver
לאחר סגירת המסלול. - לפני שמשתפים את קובצי ה-Dump עם אחרים, כדאי לבדוק אם יש בהם חשש לפרטיות.
הצעות
לקבלת תוצאות מועילות יותר, כדאי לנסות את הרעיונות הבאים:
- כדי לצמצם את ההפרעות בפלט הבדיקה, צריך להשבית את צלילי המגע והקליקים על המקשים.
- להגדיל את כל עוצמת הקול.
- משביתים אפליקציות שמשמיעות צלילים או מקליטים מהמיקרופון, אם הם לא יעניינו את הבדיקה שלך.
- קובצי פיד ספציפיים לטראק נשמרים רק כשהטראק נסגר; ייתכן שיהיה צורך לאלץ סגירה של אפליקציה כדי למחוק את הנתונים הספציפיים למסלול
- מבצעים את הפעולה
dumpsys
מיד לאחר הבדיקה. יש מקום מוגבל להקלטה. - כדי לוודא שלא תאבדו את קובצי ה-Dump, להעלות אותם למארח שלך מדי פעם. רק מספר מוגבל של קובצי dump נשמרים; פריטים ישנים יותר מוסרים לאחר הגעה למגבלה הזו.
שחזור
כפי שצוין למעלה, אין להשאיר את התכונה tee sink. אפשר לשחזר את ה-build ואת המכשיר באופן הבא:
- ביטול השינויים בקוד המקור ל-
Configuration.h
. - בנייה מחדש של
libaudioflinger.so
. - לוחצים או מסנכרנים את
libaudioflinger.so
ששוחזר ל-/system/lib
של המכשיר. adb shell
rm /data/local.prop
rm /data/misc/audioserver/*.wav
reboot
media.log
פקודות מאקרו של ALOGx
ה-API הסטנדרטי של Java לרישום שפות ב-Android SDK הוא android.util.Log.
ה-API התואם של שפת C ב-Android NDK הוא
__android_log_print
הוצהרה ב-<android/log.h>
.
בחלק המקורי של Android framework,
עדיף להשתמש בפקודות מאקרו בשם ALOGE
, ALOGW
,
ALOGI
, ALOGV
וכו'. הן הוצהרו ב-
<utils/Log.h>
, ולצורכי המאמר הזה
אנחנו נתייחס אליהם יחד בתור ALOGx
.
כל ממשקי ה-API האלה קלים לשימוש ומבינים היטב, ולכן הם חודרניים
בכל פלטפורמת Android. באופן ספציפי, mediaserver
שכולל את שרת הצלילים AudioFlinger, משתמש ב-
ALOGx
במידה רבה.
עם זאת, יש מספר מגבלות על ALOGx
ועל חברים:
-
הם חשופים ל'רישום ספאם': מאגר הנתונים הזמני של היומן הוא משאב משותף
כך שהוא יכול לגלוש בקלות עקב רשומות יומן שאינן קשורות, וכתוצאה מכך
מידע חסר. הווריאנט
ALOGV
מושבת ב כברירת מחדל. כמובן שאפילו זה יכול לגרום לרישום ספאם ביומן. אם היא מופעלת. -
הקריאות למערכת הליבה (kernel) הבסיסית עשויות לחסום, מה שעלול להוביל
וכתוצאה מכך, הפרעות במדידה
של אי-דיוקים. זה מתוך
חשש מיוחד לשרשורים קריטיים בזמן, כמו
FastMixer
ו-FastCapture
. - אם יומן מסוים מושבת כדי לצמצם את הספאם של היומנים, כל המידע שהיה מתועד ביומן הזה יאבד. אין אפשרות להפעיל יומן ספציפי באופן רטרואקטיבי, אחרי שיתברר שהיומן יהיה מעניין.
NBLOG, media.log ו-MediaLogService
ממשקי ה-API של NBLOG
וה-media.log
המשויכים
תהליך האימות ו-MediaLogService
ביחד יוצרים מערכת רישום ביומן חדשה יותר למדיה,
שמטרתו לטפל בבעיות שפירטנו למעלה. נשתמש במונח באופן חופשי
'media.log' מתייחס לכל השלוש, אבל נדגיש: NBLOG
היא
API לרישום של C++, media.log
הוא שם של תהליך Linux, וגם MediaLogService
הוא שירות binder של Android לבדיקת היומנים.
"ציר הזמן" של media.log
היא סדרה
של רשומות ביומן שהסדר היחסי שלהן נשמר.
לפי המוסכמה, לכל שרשור צריך להשתמש בציר זמן משלו.
יתרונות
אלה היתרונות של מערכת media.log
:
- היומן הראשי לא נשלח כספאם, אלא אם יש צורך בו.
- אפשר לבדוק אותם גם אם
mediaserver
קורס או נתקע. - ללא חסימה לפי ציר זמן.
- פחות הפרעה לביצועים. (כמובן שאף צורה של רישום ביומן אינה פולשנית לחלוטין).
ארכיטקטורה
בתרשים הבא מוצג הקשר של התהליך mediaserver
והתהליך init
, לפני הכניסה של media.log
:
נקודות חשובות:
init
מזלגות ומנהליםmediaserver
.init
מזהה את המוות שלmediaserver
ומחבר מחדש לפי הצורך.- הרישום ביומן של
ALOGx
לא מוצג.
בתרשים הבא מוצג הקשר החדש בין הרכיבים,
אחרי הוספת media.log
לארכיטקטורה:
שינויים חשובים:
-
לקוחות משתמשים ב-API של
NBLOG
כדי ליצור רשומות ביומן ולצרף אותן של מאגר נתונים זמני בזיכרון משותף. -
אפשר להזין את התוכן של מאגר הנתונים הזמני על
MediaLogService
בכל שלב. -
מאגר הנתונים הזמני מתוכנן כך שכל פגיעה
הזיכרון המשותף לא יקרוס את
MediaLogService
, והוא עדיין יוכל כדי לזרוק כמה שיותר ממאגר הנתונים הזמני שלא מושפע מהשחיתות. - החוצץ המעגלי לא חוסם את הקושי ולא מסתיר אותו בכתיבה וקריאת רשומות חדשות.
- לא נדרשות קריאות למערכת הליבה כדי לכתוב למאגר הנתונים העגול או לקרוא ממנו (מלבד חותמות זמן אופציונליות).
איפה משתמשים
החל מ-Android 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
של השרשור יכול לשמש גם ל-thread עצמו, וגם
באמצעות פעולות של קלסר. NBLog::Writer
אינו מספק
החרגה הדדית מרומזת לכל ציר זמן, לכן חשוב לוודא שכל היומנים
בהקשר שבו נשמר ההשתקה mLock
של השרשור.
אחרי שמוסיפים את היומנים, בונים מחדש את AudioFlinger.
אזהרה:
צריך להגדיר ציר זמן נפרד של NBLog::Writer
לכל שרשור,
כדי לשמור על בטיחות השרשורים, כי צירי הזמן מושמטים מהמושג 'מוטמעים'. אם
אם רוצים שיותר משרשור אחד ישתמש באותו ציר זמן, אפשר להגן באמצעות
mutex קיים (כפי שמתואר למעלה לגבי mLock
). לחלופין אפשר
צריך להשתמש ב-wrapper של 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
לשימוש במועד מאוחר יותר.
הצגת לוחות הזמנים
תמיד אפשר לבקש העלאת נתונים באופן ידני. הפקודה הזו מציגה יומנים מכל צירי הזמן הפעילים והאחרונים, ואז מוחקת אותם:
dumpsys media.log
שימו לב שמעצם טבעו, לוחות זמנים הם בלתי תלויים ואין אפשרות למיזוג צירי זמן.
שחזור יומנים לאחר מות של שרת המדיה
עכשיו אפשר לנסות להרוג את mediaserver
: kill -9 #
, כאשר #
מזהה התהליך שציינת קודם. אמורה להופיע תמונת מצב של media.log
ב-logcat
הראשי, שמוצגים בו כל היומנים שהובילו לקריסה.
dumpsys media.log