בארכיטקטורות קיימות של כלי רכב יש כמה יחידות בקרה אלקטרוניות (ECU) מחוץ למערכת המידע והבידור ששולטות בארגונומיה, כמו הגדרות מושבים והתאמות מראות. בהתאם לארכיטקטורות הנוכחיות של החומרה והחשמל, יחידות בקרה אלקטרוניות רבות מופעלות לפני שהמערכת מבוססת-Android של המידע והבידור מופעלת. יחידות ה-ECU האלה יכולות לתקשר עם מערכת מידע ובידור מבוססת-Android דרך שכבת הפשטת החומרה של הרכב (VHAL).
החל מגרסה 11 של Android, מערכת ההפעלה Android Automotive OS (AAOS) הציגה קבוצה חדשה של מאפיינים ב-VHAL ליצירה, למעבר, להסרה ולשיוך של אביזרים חיצוניים לצורך זיהוי משתמשים. לדוגמה, המאפיינים החדשים האלה מאפשרים לנהגים לקשור אביזר חיצוני, כמו מפתח פיזי, למשתמש Android. לאחר מכן, כשהנהג מתקרב לרכב, יחידת ה-ECU מתעוררת ומזהה את המפתח האלקטרוני. ה-ECU הזה מציין ל-HAL לאיזה משתמש ב-Android צריך להפעיל את מערכת המולטימדיה, וכך מפחית את הזמן שהנהג צריך להמתין עד שהמשתמש ב-Android ייטען.
הפעלת User HAL
צריך להפעיל באופן מפורש את מאפייני ה-HAL של המשתמש, על ידי וידוא שהנכס android.car.user_hal_enabled
של המערכת מוגדר ל-true
.
(אפשר לעשות זאת בקובץ car.mk
, כדי שלא יהיה צורך להגדיר אותו באופן ידני). כדי לבדוק אם user_hal_enabled=true
מופעל, מוסיפים את UserHalService
:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
אפשר גם לבדוק את user_hal_enabled
באמצעות adb shell
getprop android.car.user_hal_enabled
או adb logcat
CarServiceHelper *:s
. אם הנכס מושבת, תוצג הודעה כמו זו כשהפונקציה system_server
תתחיל:
I CarServiceHelper: Not using User HAL
כדי להפעיל את user_hal_enabled
באופן ידני, מגדירים את מאפיין המערכת android.car.user_hal_enabled
ומפעילים מחדש את system_server
:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
הפלט של logcat
נראה כך:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
מאפייני HAL של משתמשים
מאפיינים של מחזור החיים של המשתמש
המאפיינים הבאים מספקים את פרטי ה-HAL למצבים של מחזור החיים של המשתמש, שמאפשרים סנכרון של מחזור החיים של המשתמש בין מערכת Android לבין ECU חיצוני. המאפיינים האלה משתמשים בפרוטוקול של בקשה ותגובה, שבו מערכת Android שולחת בקשה על ידי הגדרת ערך של מאפיין, וה-HAL משיב על ידי פרסום אירוע של שינוי במאפיין.
הערה: כשיש תמיכה ב-HAL של משתמשים, צריך להטמיע את כל המאפיינים הבאים.
נכס HAL | תיאור |
---|---|
INITIAL_USER_INFO (קריאה/כתיבה) |
מערכת Android מפעילה את המאפיין הזה כדי לקבוע איזה משתמש Android
המערכת מפעילה כשמאתחלים את המכשיר או ממשיכים לפעול מ'השעיה ל-RAM' (STR). כשמפעילים אותו, ה-HAL חייב להגיב באחת מהאפשרויות הבאות:
הערה: אם ה-HAL לא מגיב, ברירת המחדל היא להפעיל אותו אחרי פרק זמן קצוב לתפוגה (חמש שניות כברירת מחדל), מה שמאט את האתחול. אם ה-HAL משיב, אבל מערכת Android לא מצליחה לבצע את הפעולה (לדוגמה, אם מספר המשתמשים המקסימלי הגיע), המערכת משתמשת בהתנהגות ברירת המחדל. דוגמה: כברירת מחדל, מערכת Android מתחילה במשתמש הפעיל האחרון בזמן ההפעלה. אם מזוהה שלט מפתחות של משתמש אחר, ה-ECU מבטל את מאפיין ה-HAL, ובמהלך ההפעלה מערכת Android עוברת להפעלה של המשתמש שצוין. |
SWITCH_USER (קריאה/כתיבה) |
המאפיין הזה נקרא כשמשנים את המשתמש הפעיל בחזית ב-Android.
מערכת Android או HAL יכולות להפעיל את הנכס כדי לבקש החלפת משתמש. שלושת תהליכי העבודה הם:
בתהליך העבודה המודרני משתמש בגישת התחייבות דו-שלבית כדי להבטיח סנכרון של מערכת Android ושל ה-ECU החיצוני. כשמערכת Android מפעילה את המעבר:
ה-HAL צריך להמתין עד לקבלת התגובה דוגמה: בזמן הנסיעה, הנהג מנסה לעבור בין משתמשי Android בממשק המשתמש של מערכת הבידור. עם זאת, מאחר שההגדרות של מושב הרכב קשורות למשתמש ב-Android, המושב זז במהלך המעבר בין משתמשים. כך, בקרת ה-ECU לא מאשרת את המעבר, ה-HAL מגיבה ככשל ומשתמש Android לא עובר.
תהליך העבודה הקודם הוא שיחה חד-כיוונית שנשלחת אחרי שהמשתמש עובר (כך ש-HAL לא יכול לחסום את המעבר). הוא נקרא רק בזמן האתחול (אחרי המעבר הראשוני של המשתמש) או באפליקציות שמפעילות את
דוגמה: אם אפליקציה משתמשת ב- תהליך העבודה של הרכב מגיע מ-HAL ולא ממערכת Android:
דוגמה: בועז השתמש בשלט הרכב של עינת כדי לפתוח את הרכב, וה-HAL השיב לבקשה |
CREATE_USER (קריאה/כתיבה) |
המערכת של Android קוראת למאפיין הזה כשיוצרים משתמש חדש ב-Android (באמצעות ה-API CarUserManager.createUser() ).
ה-HAL משיב עם דוגמה: נהג מקש על סמל בממשק המשתמש של מערכת הבידור כדי ליצור משתמש חדש ב-Android. הבקשה נשלחת ל-HAL ולשאר המערכות המשניות ברכב. יחידות ה-ECU מקבלות הודעה על המשתמש החדש שנוצר. לאחר מכן, מערכות משנה ו-ECU אחרים משייכים את מזהה המשתמש הפנימי שלהם למזהה המשתמש ב-Android. |
REMOVE_USER (כתיבה בלבד) |
מערכת Android קוראת למאפיין הזה אחרי שמשתמש ב-Android מבוטל (באמצעות השיטה CarUserManager.removeUser() ).
זוהי קריאה חד-כיוונית, ולא צפויה תגובה מ-HAL. דוגמה: נהג מקייש כדי להסיר משתמש Android קיים בממשק המשתמש של מערכת הבידור ברכב. ה-HAL מודיע על הסרת המשתמש, וכן מערכות משנה אחרות ברכב ומערכות בקרה אלקטרוניות (ECU) כדי שיוכלו להסיר את מזהה המשתמש הפנימי שלו. |
נכסים נוספים
אלה מאפיינים נוספים שלא קשורים למצבים במחזור החיים של המשתמש. אפשר להטמיע כל אחת מהן בלי לתמוך ב-HAL של המשתמש.
נכס HAL | תיאור |
---|---|
USER_IDENTIFICATION_ASSOCIATION (קריאה/כתיבה) |
אפשר להשתמש במאפיין הזה כדי לשייך כל משתמש ב-Android למנגנון זיהוי, כמו שלט מפתחות או טלפון. צריך להשתמש בנכס הזה כדי ליצור שיוכים מסוג get או set .
דוגמה: נהג מקשקש על סמל בממשק המשתמש של מערכת המולטימדיה כדי לשייך את השלט הרחוק המשמש לפתיחת הרכב ( |
ספריות עזר
לכל האובייקטים שמופיעים בהודעות הבקשה ובתשובה (כמו UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
וכן הלאה) יש ייצוג ברמה גבוהה באמצעות struct
+C, אבל ההסרה צריכה להיות שטוח לאובייקטים רגילים VehiclePropValue
(ראו דוגמאות בהמשך). כדי להקל על הפיתוח, ב-AOSP יש ספריית עזר ב-C++ שממירה באופן אוטומטי את User HAL structs
ל-VehiclePropValue
(ולהפך).
דוגמאות
INITIAL_USER_INFO
דוגמה לבקשה (באתחול הראשון)
VehiclePropValue { // flattened from InitialUserInfoRequest prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID [1] = 1 // InitialUserInfoRequestType.FIRST_BOOT [2] = 0 // user id of current user [3] = 1 // flags of current user (SYSTEM) [4] = 1 // number of existing users [5] = 0 // existingUser[0].id [6] = 1 // existingUser[0].flags }
דוגמה לתשובה (יצירת משתמש עם הרשאת אדמין)
VehiclePropValue { // flattened from InitialUserInfoResponse prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID (must match request) [1] = 2 // InitialUserInfoResponseAction.CREATE [2] = -10000 // user id (not used on CREATE) [3] = 8 // user flags (ADMIN) prop.values.stringValue: "en-US||Car Owner" // User locale and user name }
SWITCH_USER
השם בפועל של הכיתות והמאפיינים שונה במקצת, אבל תהליך העבודה הכללי זהה, כפי שמוצג באיור:
איור 1. תהליך העבודה של מאפייני HAL של משתמשים.
דוגמה לבקשה למודרניזציה של תהליך עבודה
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896585 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID [1] = 2 // SwitchUserMessageType::ANDROID_SWITCH ("modern") [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
דוגמה לתגובה של תהליך עבודה מודרני
VehiclePropValue { // flattened from SwitchUserResponse prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // SwitchUserMessageType::VEHICLE_RESPONSE [2] = 1 // SwitchUserStatus::SUCCESS }
דוגמה לתגובה בתהליך עבודה מודרני אחרי המעבר
התגובה הזו מתקבלת בדרך כלל כשמתבצע מעבר מוצלח ב-Android:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
תגובה מודרנית לתהליך עבודה לאחר המעבר
התגובה הזו מתקבלת בדרך כלל כשמתרחשת אחת מהבעיות הבאות במתג Android:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
דוגמה לבקשה לתהליך עבודה מדור קודם
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 2 // Request ID [1] = 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH [2,3] = 10,8 // target user id (10) and flags (ADMIN) [4,5] = 0,1 // current user id (0) and flags (SYSTEM) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
דוגמה לבקשה לגבי תהליך עבודה של רכב
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must be negative) [1] = 4 // SwitchUserMessageType::VEHICLE_REQUEST [2] = 11 // target user id }
תגובה של תהליך עבודה מדור קודם אחרי המעבר
התגובה הזו בדרך כלל מתרחשת כשמתג Android מצליח:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must match from vehicle request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
CREATE_USER
דוגמה לבקשה
VehiclePropValue { // flattened from CreateUserRequest prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,6 // Android id of the created user and flags (id=11, flags=GUEST, EPHEMERAL) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 3 // number of existing users (0, 10, 11) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [10,11] = 11,6 // newUser[2] (id=11, flags=GUEST,EPHEMERAL) }
דוגמה לתגובה
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
דוגמה לבקשה
VehiclePropValue { // flattened from RemoveUserRequest prop: 299896586 // REMOVE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,0 // Android id of the removed user and flags (none in this case) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 2 // number of existing users (0, 10) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) }
USER_IDENTIFICATION_ASSOCIATION
דוגמה להגדרה (מפתחות רכב שמשויך למשתמש 10)
VehiclePropValue { // flattened from UserIdentificationSetRequest prop: 299896587 // USER_IDENTIFICATION_ASSOCIATION prop.values.int32Values: [0] = 43 // Request ID [1,2] = 10,0 // Android id (10) and flags (none in this case) [3] = 1 // number of associations being set [4] = 1 // 1st type: UserIdentificationAssociationType::KEY_FOB [5] = 1 // 1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER }