Sensors AIDL HAL

שכבת ההפשטה של החומרה (HAL) של החיישנים היא הממשק בין מסגרת החיישנים של Android לבין החיישנים של המכשיר, כמו מד תאוצה או ג'ירוסקופ. ה-HAL של החיישנים מגדיר את הפונקציות שצריך להטמיע כדי לאפשר למסגרת לשלוט בחיישנים.

ה-HAL של AIDL של חיישנים זמין ב-Android מגרסה 13 ואילך למכשירים חדשים ולמכשירים משודרגים. שכבת האבסטרקציה של החומרה (HAL) של חיישני AIDL, שמבוססת על Sensors HAL 2.1, משתמשת בממשק AIDL HAL וחושפת את סוגי החיישנים של מעקב הראש ושל IMU עם ציר מוגבל.

ממשק AIDL HAL

המקור העיקרי לתיעוד של Sensors AIDL HAL נמצא בהגדרת ה-HAL בכתובת hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl.

הטמעה של Sensors AIDL HAL

כדי להטמיע את Sensors AIDL HAL, אובייקט צריך להרחיב את הממשק ולהטמיע את כל הפונקציות שמוגדרות ב-hardware/interfaces/sensors/aidl/android/hardware/sensors/ISensors.aidl.ISensors

אתחול ה-HAL

לפני שניתן להשתמש ב-HAL של החיישנים, צריך לאתחל אותו באמצעות מסגרת החיישנים של Android. ה-framework קורא לפונקציה initialize() כדי לספק שלושה פרמטרים ל-HAL של חיישנים: שני מתארים של FMQ ומצביע אחד לאובייקט ISensorsCallback.

שכבת ה-HAL משתמשת בתיאור הראשון כדי ליצור את ה-FMQ של האירוע שמשמש לכתיבת אירועי חיישן למסגרת. ה-HAL משתמש בתיאור השני כדי ליצור את ה-FMQ של Wake Lock שמשמש לסנכרון כשה-HAL משחרר את ה-Wake Lock שלו עבור WAKE_UPאירועי חיישן. שכבת ה-HAL צריכה לשמור מצביע לאובייקט ISensorsCallback כדי שאפשר יהיה להפעיל את פונקציות ההתקשרות חזרה הנדרשות.

הפונקציה initialize() חייבת להיות הפונקציה הראשונה שמופעלת כשמאתחלים את Sensors HAL.

חשיפה של חיישנים זמינים

כדי לקבל רשימה של כל החיישנים הסטטיים הזמינים במכשיר, משתמשים בפונקציה getSensorsList(). הפונקציה הזו מחזירה רשימה של חיישנים, שכל אחד מהם מזוהה באופן ייחודי על ידי ה-handle שלו. ה-handle של חיישן נתון לא יכול להשתנות כשמפעילים מחדש את התהליך שמארח את Sensors HAL. יכול להיות שהכינויים ישתנו אחרי הפעלה מחדש של המכשיר או של שרת המערכת.

אם כמה חיישנים חולקים את אותו סוג חיישן ואת אותה תכונת התעוררות, החיישן הראשון ברשימה נקרא חיישן ברירת המחדל והוא מוחזר לאפליקציות שמשתמשות בפונקציה getDefaultSensor(int sensorType, bool wakeUp).

יציבות של רשימת החיישנים

אחרי הפעלה מחדש של Sensors HAL, אם הנתונים שמוחזרים על ידי getSensorsList() מצביעים על שינוי משמעותי בהשוואה לרשימת החיישנים שאוחזרה לפני ההפעלה מחדש, המסגרת מפעילה מחדש את זמן הריצה של Android. שינויים משמעותיים ברשימת החיישנים כוללים מקרים שבהם חסר חיישן עם נקודת אחיזה נתונה או שהמאפיינים שלו השתנו, או מקרים שבהם נוספו חיישנים חדשים. למרות שהפעלה מחדש של זמן הריצה של Android עלולה לשבש את חוויית המשתמש, היא נדרשת כי מסגרת Android לא יכולה יותר לעמוד בחוזה של Android API, שלפיו חיישנים סטטיים (לא דינמיים) לא משתנים במהלך משך החיים של האפליקציה. יכול להיות שהפעולה הזו גם תמנע ממסגרת Android להקים מחדש בקשות פעילות של חיישנים שבוצעו על ידי אפליקציות. לכן, מומלץ לספקי HAL למנוע שינויים ברשימת החיישנים שאפשר להימנע מהם.

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

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

הגדרת חיישנים

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

חייבת להיות אפשרות להגדיר מחדש את החיישן בכל שלב באמצעות batch() בלי לאבד את נתוני החיישן.

תקופת הדגימה

לפרק הזמן של הדגימה יש משמעות שונה בהתאם לסוג החיישן שמגדירים:

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

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

זמן ההמתנה המקסימלי לדיווח

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

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

לדוגמה, מד תאוצה שמופעל בתדר של 50 Hz עם חביון דיווח מקסימלי של אפס מפעיל הפרעות 50 פעמים בשנייה כשה-SoC פעיל.

אם זמן האחזור המקסימלי של הדיווח גדול מאפס, אין צורך לדווח על אירועים של חיישנים ברגע שהם מזוהים. אפשר לאחסן אירועים באופן זמני ב-FIFO של החומרה ולדווח עליהם בקבוצות, כל עוד אף אירוע לא מתעכב מעבר לזמן האחזור המקסימלי של הדיווח. כל האירועים מאז הקבוצה הקודמת מתועדים ומוחזרים בבת אחת. כך מצמצמים את מספר ההפסקות שנשלחות ל-SoC ומאפשרים ל-SoC לעבור למצב צריכת חשמל נמוכה יותר בזמן שהחיישן אוסף נתונים ומקבץ אותם.

לכל אירוע משויכת חותמת זמן. העיכוב של השעה שבה מדווח על אירוע לא יכול להשפיע על חותמת הזמן של האירוע. חותמת הזמן צריכה להיות מדויקת ולשקף את הזמן שבו האירוע התרחש בפועל, ולא את הזמן שבו הוא דווח.

מידע נוסף על הדרישות לדיווח על אירועים של חיישנים עם זמן חביון מקסימלי לדיווח שאינו אפס זמין במאמר בנושא אצווה.

הפעלת חיישנים

המסגרת מפעילה ומשביתה חיישנים באמצעות הפונקציה activate(). לפני שמפעילים חיישן, המסגרת צריכה להגדיר את החיישן באמצעות batch().

אחרי שחיישן מושבת, אירועים נוספים של החיישן הזה לא יכולים להיכתב ל-FMQ של האירועים.

חיישני הדחה

אם חיישן מוגדר לאגור נתוני חיישנים, אפשר להשתמש ב-flush() כדי לאלץ את המסגרת לנקות את המאגר של אירועי החיישנים באופן מיידי. הפעולה הזו גורמת לכך שאירועי החיישן באצווה עבור נקודת האחיזה של החיישן שצוינה ייכתבו באופן מיידי ל-Event FMQ. מודול ה-HAL של החיישנים צריך לצרף אירוע של השלמת הניקוי לסוף אירועי החיישנים שנכתבים כתוצאה מקריאה ל-flush().

הפעולה מתבצעת באופן אסינכרוני (כלומר, הפונקציה הזו צריכה להחזיר ערך באופן מיידי). אם ההטמעה משתמשת ב-FIFO יחיד לכמה חיישנים, ה-FIFO הזה מתרוקן והאירוע של השלמת הריקון מתווסף רק לחיישן שצוין.

אם לחיישן שצוין אין FIFO (אי אפשר לבצע אחסון זמני), או אם ה-FIFO היה ריק בזמן הקריאה, הפונקציה flush() עדיין צריכה להצליח ולשלוח אירוע של השלמת ניקוי החיישן. הדרישה הזו חלה על כל החיישנים למעט חיישנים חד-פעמיים.

אם קוראים ל-flush() עבור חיישן חד-פעמי, הפונקציה flush() חייבת להחזיר BAD_VALUE ולא ליצור אירוע של סיום הניקוי.

כתיבת אירועי חיישן ל-FMQ

ה-FMQ של האירועים משמש את ה-HAL של החיישנים כדי לדחוף אירועים של חיישנים למסגרת החיישנים של Android.

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

אחרי ש-Sensors HAL כותב את מספר אירועי החיישן הרצוי ל-Event FMQ, הוא צריך להודיע למסגרת שהאירועים מוכנים. כדי לעשות זאת, הוא כותב את הביט EventQueueFlagBits::READ_AND_PROCESS לפונקציה EventFlag::wake של Event FMQ. אפשר ליצור את EventFlag מ-Event FMQ באמצעות EventFlag::createEventFlag והפונקציה getEventFlagWord() של Event FMQ.

‫Sensors AIDL HAL תומך ב-write וב-writeBlocking ב-Event FMQ. ההטמעה שמוגדרת כברירת מחדל מספקת הפניה לשימוש ב-write. אם משתמשים בפונקציה writeBlocking, צריך להגדיר את הדגל readNotification לערך EventQueueFlagBits::EVENTS_READ, שמוגדר על ידי ה-Framework כשהוא קורא אירועים מ-Event FMQ. דגל ההתראה על כתיבה צריך להיות מוגדר לערך EventQueueFlagBits::READ_AND_PROCESS, שמציין למסגרת שאירועים נכתבו ל-FMQ של האירועים.

אירועי WAKE_UP

אירועים מסוג WAKE_UP הם אירועים של חיישנים שגורמים למעבד האפליקציות (AP) להתעורר ולטפל באירוע באופן מיידי. בכל פעם שאירוע WAKE_UP נכתב ל-Event FMQ, ‏ Sensors HAL חייב להבטיח שהמערכת תישאר פעילה עד שהמסגרת תוכל לטפל באירוע. כשמתקבל אירוע WAKE_UP, המסגרת מאבטחת את חסימת מצב השינה שלה, וכך מאפשרת ל-HAL של החיישנים לשחרר את חסימת מצב השינה שלו. כדי לסנכרן כשה-HAL של החיישנים משחרר את חסימת מצב השינה שלו, משתמשים ב-FMQ של חסימת מצב השינה.

שכבת HAL של חיישנים צריכה לקרוא את FMQ של Wake Lock כדי לקבוע את מספר WAKE_UP האירועים שהמסגרת טיפלה בהם. שכבת ה-HAL צריכה לשחרר את חסימת מצב השינה שלה לאירועי WAKE_UP רק אם המספר הכולל של אירועי WAKE_UP שלא טופלו הוא אפס. אחרי הטיפול באירועים של חיישנים, המסגרת סופרת את מספר האירועים שמסומנים כאירועי WAKE_UP וכותבת את המספר הזה בחזרה ל-FMQ של Wake Lock.

המסגרת מגדירה את WakeLockQueueFlagBits::DATA_WRITTEN write notification ב-Wake Lock FMQ בכל פעם שהיא כותבת נתונים ב-Wake Lock FMQ.

חיישנים דינמיים

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

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

באופן דומה, כשחיישן דינמי מנותק, צריך לקרוא לפונקציה onDynamicSensorDisconnected ב-ISensorsCallback כדי שהמסגרת תוכל להסיר חיישן שכבר לא זמין.

ערוץ ישיר

ערוץ ישיר הוא שיטת פעולה שבה אירועי חיישנים נכתבים לזיכרון ספציפי במקום ל-Event FMQ, תוך עקיפת Android Sensors Framework. לקוח שרושם ערוץ ישיר חייב לקרוא את אירועי החיישן ישירות מהזיכרון ששימש ליצירת הערוץ הישיר, ולא יקבל את אירועי החיישן דרך המסגרת. הפונקציה configDirectReport() דומה לפונקציה batch() בפעולה רגילה ומגדירה את ערוץ הדוחות הישירים.

הפונקציות registerDirectChannel() ו-unregisterDirectChannel() יוצרות או משמידות ערוץ ישיר חדש.

מצבי פעולה

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

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

אימות

כדי לאמת את ההטמעה של Sensors HAL, מריצים את בדיקות ה-CTS וה-VTS של החיישן.

בדיקות CTS

בדיקות CTS של חיישנים קיימות גם בבדיקות CTS אוטומטיות וגם באפליקציית CTS Verifier הידנית.

הבדיקות האוטומטיות נמצאות בתיקייה cts/tests/sensor/src/android/hardware/cts. בבדיקות האלה מאמתים את הפונקציונליות הרגילה של החיישנים, כמו הפעלה של חיישנים, עיבוד באצווה ושיעורי אירועים של חיישנים.

הבדיקות של CTS Verifier נמצאות בנתיב cts/apps/CtsVerifier/src/com/android/cts/verifier/sensors. הבדיקות האלה דורשות הזנה ידנית ממפעיל הבדיקה, והן מבטיחות שהחיישנים ידווחו על ערכים מדויקים.

הצלחה בבדיקות CTS היא קריטית כדי לוודא שהמכשיר שנבדק עומד בכל הדרישות של CDD.

בדיקות VTS

בדיקות VTS עבור חיישני AIDL HAL נמצאות בתיקייה hardware/interfaces/sensors/aidl/vts/. הבדיקות האלה מוודאות שה-HAL של החיישנים מוטמע בצורה תקינה ושהדרישות ב-ISensors.aidl וב-ISensorsCallback.aidl מתקיימות בצורה תקינה.

אתחול ה-HAL

כדי ליצור תורי הודעות מהירים בין המסגרת לבין HAL, צריך לתמוך בפונקציה initialize().

חשיפה של חיישנים זמינים

ב-Sensors AIDL HAL, הפונקציה getSensorsList() חייבת להחזיר את אותו ערך במהלך אתחול יחיד של המכשיר, גם אם מתבצע אתחול מחדש של Sensors HAL. דרישה חדשה של הפונקציה getSensorsList() היא שהיא צריכה להחזיר את אותו ערך במהלך אתחול יחיד של המכשיר, גם אם מתבצעת הפעלה מחדש של Sensors HAL. כך, אם השרת של המערכת מופעל מחדש, המסגרת יכולה לנסות ליצור מחדש את החיבורים לחיישנים. הערך שמוחזר על ידי getSensorsList() יכול להשתנות אחרי שהמכשיר מופעל מחדש.

כתיבת אירועי חיישן ל-FMQ

במקום לחכות לקריאה של poll(), ב-Sensors AIDL HAL, ‏ Sensors HAL חייב לכתוב באופן יזום אירועים של חיישנים ל-Event FMQ בכל פעם שאירועים של חיישנים זמינים. ה-HAL אחראי גם לכתיבת הביטים הנכונים ל-EventFlag כדי לגרום לקריאת FMQ במסגרת.

אירועי WAKE_UP

ב-HAL 1.0 של חיישנים, ה-HAL יכול היה לשחרר את חסימת מצב השינה שלו לכל WAKE_UPאירוע בכל קריאה עוקבת ל-poll() אחרי ש-WAKE_UP פורסם ב-poll(), כי זה הצביע על כך שהמסגרת עיבדה את כל אירועי החיישן וקיבלה חסימת מצב שינה, אם היה צורך בכך. ב-HAL של חיישני AIDL ה-HAL כבר לא מקבל הודעה כשהמסגרת מעבדת אירועים שנכתבו ב-FMQ, ה-FMQ של Wake Lock מאפשר למסגרת לתקשר עם ה-HAL כשהיא מטפלת באירועי WAKE_UP.

ב-Sensors AIDL HAL, חסימת מצב השינה שמאובטחת על ידי Sensors HAL עבור אירועים של WAKE_UP חייבת להתחיל ב-SensorsHAL_WAKEUP.

חיישנים דינמיים

חיישנים דינמיים הוחזרו באמצעות הפונקציה poll() ב-Sensors HAL 1.0. ה-HAL של AIDL חיישנים מחייב קריאה ל-onDynamicSensorsConnected ול-onDynamicSensorsDisconnected ב-ISensorsCallback בכל פעם שמשתנים חיבורים של חיישנים דינמיים. הקריאות החוזרות האלה זמינות כחלק מהמצביע ISensorsCallback שמסופק דרך הפונקציה initialize().

מצבי פעולה

צריכה להיות תמיכה במצב DATA_INJECTION של חיישני WAKE_UP.

תמיכה ב-Multi-HAL

ה-HAL של חיישני AIDL תומך ב-multi-HAL באמצעות מסגרת ה-multi-HAL של חיישנים. פרטים על ההטמעה מופיעים במאמר בנושא העברה מ-Sensors HAL 2.1.