ארכיטקטורות רכב נוכחיות רבות מכילות מספר יחידות בקרה אלקטרוניות (ECU) מחוץ למערכת המידע והבידור השולטות בארגונומיה, כגון הגדרות מושבים והתאמת מראה. בהתבסס על ארכיטקטורות החומרה והכוח הנוכחיות, ECUs רבים מופעלים לפני הפעלת מערכת המידע והבידור המבוססת על אנדרואיד. ECUs אלה יכולים להתממשק עם מערכת מידע בידור מבוססת אנדרואיד דרך שכבת חומרת ההפשטה של הרכב (VHAL) .
החל מ-Android 11, Android Automotive OS (AAOS) הציגה קבוצה חדשה של מאפיינים ב-VHAL ליצירה, החלפה, הסרה ושיוך אביזרים חיצוניים לזיהוי משתמשים. לדוגמה, מאפיינים חדשים אלה מאפשרים לנהג לקשור אביזר חיצוני, כגון שלט מפתח, למשתמש האנדרואיד שלו. לאחר מכן, כאשר הנהג מתקרב לרכב, ECU מתעורר ומזהה את שלט המפתח. ECU זה מציין ל-HAL איזה משתמש אנדרואיד צריך להתחיל אתחול המידע-בידור, מה שמפחית את הזמן שנהג ממתין לטעינת משתמש האנדרואיד שלו.
הפעל את המשתמש HAL
יש להפעיל במפורש את מאפייני User 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 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 עבור מצבי מחזור חיים של משתמש, המאפשרים סנכרון של מחזור חיי משתמש בין מערכת אנדרואיד ל-ECU חיצוני. נכסים אלה משתמשים בפרוטוקול בקשה ותגובה, שבו מערכת אנדרואיד מבצעת בקשה על ידי הגדרת ערך מאפיין וה-HAL מגיב על ידי הוצאת אירוע שינוי נכס.
הערה: כאשר User HAL נתמך, יש ליישם את כל המאפיינים הבאים.
נכס HAL | תיאור |
---|---|
INITIAL_USER_INFO (קרוא וכתוב) | מאפיין זה נקרא על ידי מערכת אנדרואיד כדי לקבוע באיזה משתמש אנדרואיד המערכת תפעיל כאשר המכשיר יאתחל או יתחדש מ-Suspend-to-RAM (STR). כאשר נקרא, ה-HAL חייב להגיב באחת מהאפשרויות הבאות:
הערה: אם ה-HAL אינו מגיב, אופן הפעולה המוגדר כברירת מחדל הוא ביצוע לאחר פרק זמן קצוב (חמש (5) שניות כברירת מחדל), אשר מעכב את האתחול. אם ה-HAL אכן עונה, אך מערכת אנדרואיד לא מצליחה לבצע את הפעולה (לדוגמה, אם הושג מספר המשתמשים המקסימלי), נעשה שימוש בהתנהגות ברירת המחדל. לדוגמה, כברירת מחדל, מערכת אנדרואיד מתחילה במשתמש האחרון הפעיל בעת האתחול. אם מזוהה שלט מפתח עבור משתמש אחר, ה-ECU עוקף את מאפיין ה-HAL, ובמהלך ההפעלה, מערכת אנדרואיד עוברת להפעיל באותו משתמש שצוין. |
SWITCH_USER (קרוא וכתוב) | מאפיין זה נקרא בעת החלפת משתמש אנדרואיד פעיל בחזית. ניתן להתקשר לנכס על ידי מערכת אנדרואיד או על ידי HAL כדי לבקש החלפת משתמש. שלושת זרימות העבודה הן:
זרימת העבודה המודרנית משתמשת בגישת התחייבות דו-שלבית כדי להבטיח שמערכת אנדרואיד וה-ECU החיצוני מסונכרנים. כאשר אנדרואיד יוזם את המעבר:
ה-HAL צריך להמתין עד לאחר תגובת לדוגמה, בזמן תנועה, נהג מנסה להחליף משתמשי אנדרואיד בממשק המשתמש של המידע והבידור. עם זאת, מכיוון שהגדרות מושב המכונית קשורות למשתמש אנדרואיד, המושב יזוז במהלך המעבר למשתמש. לפיכך, ECU השולט על המושבים אינו מאשר את המעבר, ה-HAL מגיב בכשל, ומשתמש האנדרואיד אינו מוחלף. זרימת העבודה מדור קודם היא שיחה חד-כיוונית הנשלחת לאחר החלפת המשתמש (כך שה-HAL לא יכול לחסום את המתג). זה נקרא רק באתחול (לאחר המעבר למשתמש הראשוני) או עבור אפליקציות שקוראות ל- לדוגמה, אם אפליקציה משתמשת ב- זרימת העבודה של הרכב מקורה ב-HAL, לא ממערכת אנדרואיד:
לדוגמה , בוב השתמש בשלט המפתח של אליס כדי לפתוח את המכונית וה-HAL השיב לבקשת |
CREATE_USER (קרוא וכתוב) | מאפיין זה נקרא על ידי מערכת אנדרואיד כאשר נוצר משתמש אנדרואיד חדש (באמצעות ה-API של CarUserManager.createUser() ). ה-HAL מגיב עם לדוגמה, נהג מקיש על סמל ממשק המשתמש של מידע בידור כדי ליצור משתמש אנדרואיד חדש. זה שולח בקשה ל-HAL ולשאר תתי-מערכות הרכב. ECUs מודיעים על המשתמש החדש שנוצר. מערכות משנה ו-ECU אחרים משייכים את מזהה המשתמש הפנימי שלהם למזהה המשתמש של Android. |
REMOVE_USER (כתוב בלבד) | מערכת אנדרואיד קוראת למאפיין זה לאחר הסרת משתמש אנדרואיד (עם ה-API של CarUserManager.removeUser() ).מדובר בשיחה חד-כיוונית - לא צפויה תגובה מה-HAL. לדוגמה, נהג מקיש כדי להסיר משתמש אנדרואיד קיים בממשק המשתמש של המידע והבידור. ה-HAL מודיע ותת-מערכות רכב אחרות ו-ECU מודיעים על הסרת המשתמש כדי שיוכלו להסיר את מזהה המשתמש הפנימי שלהם. |
נכסים נוספים
להלן מאפיינים נוספים, שאינם קשורים למצבי מחזור החיים של המשתמש. כל אחד מהם יכול להיות מיושם ללא תמיכה ב-User HAL.
נכס HAL | תיאור |
---|---|
USER_IDENTIFICATION_ASSOCIATION (קרוא וכתוב) | השתמש במאפיין זה כדי לשייך כל משתמש אנדרואיד למנגנון זיהוי, כגון שלט מפתח או טלפון. השתמש באותו מאפיין כדי get או set אסוציאציות.לדוגמה, נהג מקיש על סמל ממשק המשתמש של מידע בידור כדי לשייך את השלט המשמש לפתיחת הרכב (KEY_123) למשתמש הפעיל הנוכחי של Android (USER_11). |
ספריות עוזרים
לכל האובייקטים המשמשים בהודעות הבקשה והתגובה (כגון UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
וכן הלאה) יש ייצוג ברמה גבוהה באמצעות C++ struct
, אך יש לשטח את ההסרה לאובייקטים סטנדרטיים VehiclePropValue
(ראה הדוגמאות למטה). כדי להקל על הפיתוח, ספריית C++ מסייעת מסופקת ב-AOSP כדי להמיר אוטומטית VehiclePropValue
structs
ולהיפך).
דוגמאות
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 }
החלף משתמש
השם האמיתי של המחלקות והמאפיינים שונה במקצת, אך זרימת העבודה הכוללת זהה, כפי שמוצג להלן:
איור 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 }
דוגמה לתגובת זרימת עבודה מודרנית לאחר המעבר
תגובה זו מתרחשת בדרך כלל כאשר מתג אנדרואיד מצליח:
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) }
תגובה מודרנית של זרימת עבודה לאחר המעבר
תגובה זו מתרחשת בדרך כלל כאשר מתג אנדרואיד נכשל:
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 }
תגובה מדור קודם של זרימת עבודה לאחר המעבר
תגובה זו מתרחשת בדרך כלל כאשר מתג אנדרואיד מצליח:
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) }
צור משתמש
בקשה לדוגמא
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 }