ב-Android 10 יש ממשקי API אופציונליים לניהול מאגר נתונים זמני של מצלמה HAL3, שמאפשרים להטמיע לוגיקה של ניהול מאגר נתונים זמני כדי להשיג זיכרון שונה והבדלים בין זמן האחזור בהטמעות עם ממשק HAL במצלמה.
ה-HAL של המצלמה דורש N בקשות (כאשר N שווה לעומק צינור עיבוד הנתונים) שיוצבו בתור בצינור עיבוד הנתונים שלו, אבל לרוב הוא לא דורש את כל N הקבוצות של מאגרי הפלט בו-זמנית.
לדוגמה, יכול להיות של-HAL יש שמונה בקשות בתור בצינור עיבוד הנתונים, אבל הוא זקוק למאגרי פלט רק לשתי הבקשות בשלבים האחרונים של צינור עיבוד הנתונים. במכשירים עם Android 9 וגרסאות ישנות יותר, מסגרת המצלמה מקצה מאגרים כשהבקשה נכנסת לתור ב-HAL, כך שיכולות להיות שש קבוצות של מאגרים ב-HAL שלא בשימוש. ב-Android 10, ממשקי ה-API לניהול מאגר הנתונים הזמני של המצלמה HAL3 מאפשרים פענוח של מאגרי הנתונים הזמניים כדי לפנות את שש קבוצות מאגר הנתונים הזמני. הפעולה הזו יכולה לחסוך מאות מגה-בייט בזיכרון במכשירים מתקדמים, והיא גם יכולה להועיל למכשירים עם נפח זיכרון נמוך.
באיור 1 מוצגת תרשים של ממשק ה-HAL של המצלמה במכשירים עם Android מגרסה 9 וגרסאות קודמות. באיור 2 מוצג ממשק ה-HAL של המצלמה ב-Android 10, עם ממשקי ה-API לניהול מאגרי ה-HAL3 של המצלמה.
איור 1. ממשק HAL של מצלמה ב-Android 9 ומטה
איור 2. ממשק HAL של מצלמה ב-Android 10 באמצעות ממשקי ה-API לניהול מאגרים
הטמעה של ממשקי ה-API לניהול מאגר
כדי להטמיע את ממשקי ה-API לניהול מאגרים, ה-HAL של המצלמה צריך:
- מטמיעים HIDL
ICameraDevice@3.5
. - מגדירים את מפתח המאפיינים של המצלמה
android.info.supportedBufferManagementVersion
לערךHIDL_DEVICE_3_5
.
ה-HAL של המצלמה משתמש בשיטות requestStreamBuffers
ו-returnStreamBuffers
ב-ICameraDeviceCallback.hal
כדי לבקש ולשלוח מאגרים. ב-HAL צריך גם להטמיע את השיטה signalStreamFlush
ב-ICameraDeviceSession.hal
כדי לאותת ל-HAL של המצלמה להחזיר מאגרים.
requestStreamBuffers
משתמשים ב-method requestStreamBuffers
כדי לבקש מאגרים ממסגרת המצלמה. כשמשתמשים ב-API לניהול מאגרי נתונים של המצלמה HAL3, בקשות הצילום מהמסגרת של המצלמה לא מכילות מאגרי פלט, כלומר השדה bufferId
ב-StreamBuffer
הוא 0
. לכן, ה-HAL של המצלמה צריך להשתמש ב-requestStreamBuffers
כדי לבקש מאגרים מסגרת המצלמה.
השיטה requestStreamBuffers
מאפשרת למבצע הקריאה לבקש מספר מאגרים מכמה מקורות פלט בקריאה אחת, וכך להפחית את מספר הקריאות ל-HIDL IPC. עם זאת, ככל שמבקשים יותר מאגרים בו-זמנית, הזמן הנדרש לביצוע הקריאות ארוך יותר, ויכול להיות שזה ישפיע לרעה על זמן האחזור הכולל מהבקשה לקבלת התוצאה.
בנוסף, מאחר שהקריאות ל-requestStreamBuffers
עוברות סריאליזציה בשירות המצלמה, מומלץ ש-HAL של המצלמה ישתמש בשרשור ייעודי בעדיפות גבוהה כדי לבקש מאגרים.
אם בקשת מאגר נכשל, ה-HAL של המצלמה צריך להיות מסוגל לטפל כראוי בשגיאות לא קטלניות. ברשימה הבאה מפורטות סיבות נפוצות לכך שבקשות שנשמרות במאגר נכשלות, ואיך צריך לטפל בהן ב-HAL של המצלמה.
- האפליקציה מתנתקת מזרם הפלט: זוהי שגיאה לא קריטית. ה-HAL של המצלמה צריך לשלוח את הערך
ERROR_REQUEST
לכל בקשת צילום שמטרגטת שידור מנותק, ולהיות מוכן לעבד בקשות נוספות באופן רגיל. - זמן קצוב לתפוגה: מצב כזה יכול להתרחש כשאפליקציה עסוקה בעיבוד אינטנסיבי תוך שמירה על מאגרים מסוימים. ה-HAL של המצלמה צריך לשלוח את הערך
ERROR_REQUEST
לבקשות צילום שלא ניתן למלא בגלל שגיאת זמן קצוב, ולהיות מוכן לעבד בקשות הבאות באופן רגיל. - מסגרת המצלמה מכינה הגדרת סטרימינג חדשה:
ה-HAL של המצלמה צריך להמתין עד שהקריאה הבאה ל-
configureStreams
תסתיים, ואז לבצע קריאה חוזרת ל-requestStreamBuffers
. - HAL המצלמה הגיע למגבלת המאגר הזמני (השדה
maxBuffers
): HAL המצלמה צריך להמתין עד שהוא מחזיר לפחות מאגר נתונים זמני אחד של הסטרימינג לפני שהוא קורא שוב ל-requestStreamBuffers
.
returnStreamBuffers
משתמשים ב-method returnStreamBuffers
כדי להחזיר מאגרים נוספים למסגרת המצלמה. בדרך כלל, ה-HAL של המצלמה מחזיר מאגרים למסגרת המצלמה באמצעות השיטה processCaptureResult
, אבל הוא יכול להתייחס רק לבקשות צילום שנשלחו ל-HAL של המצלמה. באמצעות method requestStreamBuffers
, הטמעה של מצלמה עם HAL מאפשרת לשמור יותר מאגרי נתונים זמניים ממה שהתבקש על ידי ה-framework של המצלמה. במקרים כאלה צריך להשתמש בשיטה returnStreamBuffers
. אם הטמעת ה-HAL אף פעם לא שומרת יותר מאגרים מהבקשה, הטמעת ה-HAL של המצלמה לא צריכה להפעיל את השיטה returnStreamBuffers
.
signalStreamFlush
ה-method signalStreamFlush
נקרא על ידי מסגרת המצלמה כדי להודיע ל-HAL של המצלמה להחזיר את כל המאגרים הזמינים. היא נקראת בדרך כלל כשמסגרת המצלמה עומדת להפעיל את configureStreams
, והיא חייבת לרוקן את צינור עיבוד הנתונים של המצלמה. בדומה ל-method returnStreamBuffers
, אם בהטמעה עם ממשק HAL של מצלמה אין יותר מאגרי נתונים זמניים ממה שנדרש, יכול להיות שהשיטה הזו תיושם באופן ריק.
אחרי ש-framework המצלמה קורא ל-signalStreamFlush
, ה-framework מפסיק לשלוח בקשות צילום חדשות ל-HAL של המצלמה עד שכל המאגרים יחזרו ל-framework המצלמה. כשכל המאגרים מוחזרים, הקריאות ל-method requestStreamBuffers
נכשלות ותשתית המצלמה יכולה להמשיך לעבוד במצב נקי. לאחר מכן, ה-framework של המצלמה קורא ל-method configureStreams
או processCaptureRequest
. אם מסגרת המצלמה קוראת לשיטה configureStreams
, ה-HAL של המצלמה יכול להתחיל לבקש מאגרים שוב אחרי שהקריאה ל-configureStreams
תוחזר בהצלחה. אם מסגרת המצלמה קוראת לשיטה processCaptureRequest
, ה-HAL של המצלמה יכול להתחיל לבקש מאגרים במהלך הקריאה ל-processCaptureRequest
.
הסמנטיקה שונה ב-method signalStreamFlush
וב-method flush
. כשמתבצעת קריאה לשיטה flush
, ה-HAL יכול לבטל בקשות הקלטה בהמתנה באמצעות ERROR_REQUEST
כדי לרוקן את צינור עיבוד הנתונים בהקדם האפשרי. כשמתבצעת קריאה לשיטה signalStreamFlush
, ה-HAL צריך לסיים את כל בקשות הצילום בהמתנה באופן תקין ולהחזיר את כל המאגרים למסגרת המצלמה.
הבדל נוסף בין השיטה signalStreamFlush
לשיטות אחרות הוא ש-signalStreamFlush
היא שיטה חד-כיוונית של HIDL. כלומר, מסגרת המצלמה עשויה לבצע קריאה לממשקי API אחרים שחוסמים לפני שה-HAL מקבל את הקריאה signalStreamFlush
. המשמעות היא ש-method signalStreamFlush
ושיטות אחרות (במיוחד method configureStreams
) עשויים להגיע ל-HAL של המצלמה בסדר שונה מהסדר שבו הם הוזמנו במסגרת המצלמה. כדי לטפל בבעיה האסינכרונית, השדה streamConfigCounter
נוסף ל-StreamConfiguration
ונוסף כארגומנט ל-method signalStreamFlush
. הטמעת ה-HAL של המצלמה צריכה להשתמש בארגומנט streamConfigCounter
כדי לקבוע אם קריאה ל-signalStreamFlush
מגיעה מאוחר יותר מקריאה תואמת ל-configureStreams
. דוגמה מופיעה באיור 3.
איור 3. איך ה-HAL של המצלמה צריך לזהות ולטפל בקריאות signalStreamFlush שמגיעות באיחור
שינויים בהתנהגות כשמטמיעים את ממשקי ה-API לניהול מאגר
כשמשתמשים בממשקי ה-API לניהול מאגרים כדי להטמיע את הלוגיקה של ניהול המאגרים, צריך להביא בחשבון את השינויים האפשריים הבאים בהתנהגות של המצלמה והטמעת ה-HAL של המצלמה:
בקשות תיעוד מגיעות ל-HAL של המצלמה מהר יותר ובתדירות גבוהה יותר: בלי ממשקי API לניהול מאגר הנתונים הזמני, ה-framework של המצלמה מבקש מאגר נתונים זמני לכל בקשת צילום לפני שליחת בקשת צילום ל-HAL של המצלמה. כשמשתמשים בממשקי ה-API לניהול מאגרים, מסגרת המצלמה כבר לא צריכה להמתין למאגרים, ולכן היא יכולה לשלוח בקשות צילום ל-HAL של המצלמה מוקדם יותר.
בנוסף, ללא ממשקי API לניהול מאגרים, מסגרת המצלמה מפסיקה לשלוח בקשות צילום אם אחד מזרמי הפלט של בקשת הצילום הגיע למספר המקסימלי של מאגרים ש-HAL יכול להכיל בו-זמנית (הערך הזה מוגדר על ידי HAL המצלמה בשדה
HalStream::maxBuffers
בערך המוחזר של קריאה ל-configureStreams
). כשמשתמשים בממשקי ה-API לניהול מאגרים, התנהגות הצמצום הזו כבר לא קיימת, וההטמעה של HAL המצלמה לא יכולה לקבל קריאות ל-processCaptureRequest
כשיש ב-HAL יותר מדי בקשות צילום בתור.זמן האחזור של שיחות
requestStreamBuffers
משתנה באופן משמעותי: יש הרבה סיבות לכך ששיחתrequestStreamBuffers
עשויה להימשך זמן רב יותר מהממוצע. לדוגמה:- במאגרים הראשונים של שידור חדש שנוצר, השיחות עשויות להימשך זמן רב יותר כי המכשיר צריך להקצות זיכרון.
- זמן האחזור הצפוי גדל ביחס למספר הקבצים הזמניים שמבקשים בכל שיחה.
- האפליקציה שומרת בקטעי זיכרון זמניים (buffers) ועסוקה בעיבוד. כתוצאה מכך, בקשות שנשמרות במאגר עשויות להתעכב או לחרוג מזמן הקצוב בגלל מחסור במאגרים או מעבד (CPU) עמוס.
אסטרטגיות לניהול מאגרי שטחי הפרסום
ממשקי ה-API לניהול מאגר הנתונים הזמני מאפשרים להטמיע סוגים שונים של אסטרטגיות לניהול מאגר הנתונים הזמני. לפניכם מספר דוגמאות:
- תאימות לאחור: HAL מבקש מאגר נתונים זמני לבקשת תיעוד במהלך השיחה
processCaptureRequest
. האסטרטגיה הזו לא חוסכת זיכרון, אבל היא יכולה לשמש כהטמעה הראשונה של ממשקי ה-API לניהול מאגרים, תוך דרישה לשינויים מועטים מאוד בקוד של HAL הקיים של המצלמה. - חיסכון מקסימלי בזיכרון: ה-HAL של המצלמה מבקש מאגרי פלט רק מיד לפני שצריך למלא אותם. האסטרטגיה הזו מאפשרת לחסוך בזיכרון בצורה מקסימלית. החיסרון הפוטנציאלי הוא יותר עיכובים בצינור עיבוד הנתונים של המצלמה כשהבקשות למאגר נמשכות זמן רב מהרגיל.
- במטמון: המצלמה עם HAL שומרת כמה מאגרי נתונים זמניים כדי להקטין את הסיכוי שהיא תושפע מבקשה למאגר נתונים איטי מדי פעם.
ה-HAL של המצלמה יכול להשתמש בשיטות שונות בתרחישים לדוגמה מסוימים. לדוגמה, שימוש בשיטה של חיסכון מקסימלי בזיכרון בתרחישים לדוגמה שבהם נעשה שימוש רב בזיכרון, ושימוש בשיטה של תאימות לאחור בתרחישים לדוגמה אחרים.
הטמעת דגימות ב-HAL של מצלמה חיצונית
HAL של המצלמה החיצונית הוצג ב-Android 9 וניתן למצוא אותו בעץ המקור ב-hardware/interfaces/camera/device/3.5/
.
ב-Android 10, הוא עודכן כך שיכלול את ExternalCameraDeviceSession.cpp
, הטמעה של ה-API לניהול מאגרים. ה-HAL של המצלמה החיצונית מטמיע את האסטרטגיה לחיסכון מקסימלי בזיכרון שמפורטת בקטע אסטרטגיות לניהול מאגרים בכמה מאות שורות של קוד C++.