ב-Android 10 נוספו ממשקי API אופציונליים לניהול מאגרים של camera 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
כדי לבקש מאגרים (buffers) מסגרת המצלמה.
method 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 המצלמה. באמצעות השיטה requestStreamBuffers
, הטמעת ה-HAL של המצלמה יכולה לשמור יותר מאגרים ממה שביקשה מסגרת המצלמה. במקרים כאלה צריך להשתמש בשיטה returnStreamBuffers
. אם הטמעת ה-HAL אף פעם לא שומרת יותר מאגרים מהבקשה, הטמעת ה-HAL של המצלמה לא צריכה להפעיל את השיטה returnStreamBuffers
.
signalStreamFlush
ה-method signalStreamFlush
נקרא על ידי מסגרת המצלמה כדי להודיע ל-HAL של המצלמה להחזיר את כל המאגרים הזמינים. בדרך כלל, הפונקציה הזו נקראת כשמסגרת המצלמה עומדת לבצע קריאה ל-configureStreams
, וצריך לנקות את צינור עיבוד הנתונים של צילום המצלמה. בדומה לשיטה returnStreamBuffers
, אם הטמעת HAL של המצלמה לא שומרת יותר מאגרים מהנדרש, יכול להיות שתהיה הטמעה ריקה של השיטה הזו.
אחרי ש-Camera Framework מבצע קריאה ל-signalStreamFlush
, ה-framework מפסיק לשלוח בקשות צילום חדשות ל-HAL של המצלמה עד שכל המאגרים יחזרו ל-Camera Framework. כשכל המאגרים מוחזרים, קריאות ה-method requestStreamBuffers
נכשלות ותשתית המצלמה יכולה להמשיך את העבודה במצב נקי. לאחר מכן, מסגרת המצלמה קוראת ל-method configureStreams
או ל-method processCaptureRequest
. אם מסגרת המצלמה קוראת לשיטה configureStreams
, ה-HAL של המצלמה יכול להתחיל לבקש מאגרים שוב אחרי שהקריאה ל-configureStreams
תוחזר בהצלחה. אם מסגרת המצלמה קוראת לשיטה processCaptureRequest
, ה-HAL של המצלמה יכול להתחיל לבקש מאגרים במהלך הקריאה ל-processCaptureRequest
.
הסמנטיקה שונה בין השיטה signalStreamFlush
לבין השיטה flush
. כשמתבצעת קריאה ל-method flush
, ה-HAL יכול לבטל בקשות הקלטה בהמתנה באמצעות ERROR_REQUEST
כדי לרוקן את צינור עיבוד הנתונים בהקדם האפשרי. כשמתבצעת קריאה לשיטה signalStreamFlush
, ה-HAL צריך לסיים את כל בקשות הצילום בהמתנה באופן תקין ולהחזיר את כל המאגרים למסגרת המצלמה.
הבדל נוסף בין השיטה signalStreamFlush
לשיטות אחרות הוא ש-signalStreamFlush
היא שיטה חד-כיוונית של HIDL, כלומר מסגרת המצלמה עשויה לבצע קריאה לממשקי API אחרים שחוסמים לפני שה-HAL מקבל את הקריאה signalStreamFlush
. כלומר, השיטה signalStreamFlush
ושיטות אחרות (במיוחד השיטה configureStreams
) עשויות להגיע ל-HAL של המצלמה בסדר שונה מהסדר שבו הן הוזמנו במסגרת המצלמה. כדי לטפל בבעיה של חוסר התזמון, השדה streamConfigCounter
נוסף ל-StreamConfiguration
ונוסף כארגומנטים לשיטה signalStreamFlush
. הטמעת ה-HAL של המצלמה צריכה להשתמש בארגומנט streamConfigCounter
כדי לקבוע אם קריאה ל-signalStreamFlush
מגיעה מאוחר יותר מקריאה תואמת ל-configureStreams
. דוגמה מופיעה באיור 3.
איור 3. איך ה-HAL של המצלמה צריך לזהות ולטפל בקריאות signalStreamFlush שמגיעות באיחור
שינויים בהתנהגות כשמטמיעים את ממשקי ה-API לניהול מאגר
כשמשתמשים בממשקי ה-API לניהול מאגרים כדי להטמיע את הלוגיקה של ניהול המאגרים, צריך להביא בחשבון את השינויים האפשריים הבאים בהתנהגות של המצלמה והטמעת ה-HAL של המצלמה:
בקשות הצילום מגיעות ל-HAL של המצלמה מהר יותר ובתדירות גבוהה יותר: בלי ממשקי API לניהול מאגרים, מסגרת המצלמה מבקשת מאגרי פלט לכל בקשת צילום לפני שליחת בקשת הצילום ל-HAL של המצלמה. כשמשתמשים בממשקי ה-API לניהול מאגרים, מסגרת המצלמה כבר לא צריכה להמתין למאגרים, ולכן היא יכולה לשלוח בקשות צילום ל-HAL של המצלמה מוקדם יותר.
בנוסף, ללא ממשקי API לניהול מאגרים, מסגרת המצלמה מפסיקה לשלוח בקשות צילום אם אחד מזרמי הפלט של בקשת הצילום הגיע למספר המקסימלי של מאגרים ש-HAL יכול להכיל בו-זמנית (הערך הזה נקבע על ידי HAL המצלמה בשדה
HalStream::maxBuffers
בערך המוחזר של קריאה ל-configureStreams
). כשמשתמשים בממשקי ה-API לניהול מאגרים, התנהגות הצמצום הזו כבר לא קיימת, וההטמעה של HAL המצלמה לא יכולה לקבל קריאות ל-processCaptureRequest
כשיש ב-HAL יותר מדי בקשות צילום בתור.זמן האחזור של שיחות
requestStreamBuffers
משתנה באופן משמעותי: יש הרבה סיבות לכך ששיחתrequestStreamBuffers
עשויה להימשך זמן רב יותר מהממוצע. לדוגמה:- בזמן היצירה של השידורים הראשונים, הקריאות עשויות להימשך זמן רב יותר כי המכשיר צריך להקצות זיכרון.
- זמן האחזור הצפוי גדל בהתאם למספר המאגרים המבוקשים בכל קריאה.
- האפליקציה שומרת נתונים במאגרים ועסוקה בעיבוד. כתוצאה מכך, בקשות שנשמרות במאגר עשויות להתעכב או להגיע לזמן קצוב לתפוגה בגלל מחסור במאגרים או מעבד (CPU) עמוס.
אסטרטגיות לניהול מאגרי שטחי הפרסום
ממשקי ה-API לניהול מאגרים מאפשרים להטמיע סוגים שונים של אסטרטגיות לניהול מאגרים. לפניכם מספר דוגמאות:
- תאימות לאחור: ה-HAL מבקש מאגרים לבקשת צילום במהלך הקריאה ל-
processCaptureRequest
. האסטרטגיה הזו לא חוסכת זיכרון, אבל היא יכולה לשמש כהטמעה הראשונה של ממשקי ה-API לניהול מאגרים, ותצטרכו לבצע מעט מאוד שינויים בקוד של HAL הקיים של המצלמה. - חיסכון מקסימלי בזיכרון: ה-HAL של המצלמה מבקש מאגרי פלט רק מיד לפני שצריך למלא אותם. האסטרטגיה הזו מאפשרת לחסוך בזיכרון בצורה מקסימלית. החיסרון הפוטנציאלי הוא יותר עיכובים בצינור עיבוד הנתונים של המצלמה כשהבקשות למאגר נמשכות זמן רב מהרגיל.
- אחסון במטמון: HAL של המצלמה מאחסן במטמון כמה מאגרי נתונים (buffers) כדי להפחית את הסבירות להשפעה של בקשה איטית מדי פעם למאגר נתונים.
ה-HAL של המצלמה יכול להשתמש בשיטות שונות לתרחישי שימוש מסוימים. לדוגמה, שימוש בשיטה של חיסכון מקסימלי בזיכרון לתרחישי שימוש שבהם נעשה שימוש רב בזיכרון, ושימוש בשיטה של תאימות לאחור לתרחישי שימוש אחרים.
הטמעה לדוגמה ב-HAL של המצלמה החיצונית
HAL של המצלמה החיצונית הוצג ב-Android 9 וניתן למצוא אותו בעץ המקור ב-hardware/interfaces/camera/device/3.5/
.
ב-Android 10, הוא עודכן כך שיכלול את ExternalCameraDeviceSession.cpp
, הטמעה של ה-API לניהול מאגרים. ה-HAL של המצלמה החיצונית מטמיע את האסטרטגיה לחיסכון מקסימלי בזיכרון שמפורטת בקטע אסטרטגיות לניהול מאגרים בכמה מאות שורות של קוד C++.