בארכיטקטורות רבות של רכבים מודרניים יש כמה יחידות בקרה אלקטרוניות (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 המערכת תפעיל כשהמכשיר יופעל או ימשיך מ-Suspend-to-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 }