ארכיטקטורות קיימות של כלי רכב כוללות כמה יחידות בקרה אלקטרוניות (ECU) מחוץ למערכת המידע והבידור השולטת בארגונומיה, כמו מושבים ההגדרות והתאמות שיקוף. מבוסס על החומרה והחשמל הנוכחיים של הארכיטקטורה, רבים מה-ECU מופעלים לפני מערכת המידע והבידור שמבוססת על Android מופעלת. יחידות ה-ECU האלה יכולות להתממשק עם מידע ובידור מבוסס Android באמצעות שכבה של הפשטה של חומרת רכב (VHAL).
החל מ-Android 11, הושקה גרסה חדשה של Android Automotive OS (AAOS) נכסים ב-VHAL ליצירה, שינוי, הסרה ושיוך אביזרים חיצוניים לזיהוי משתמשים. לדוגמה, הנכסים החדשים האלה מאפשרים נהג יכול לקשור אביזר חיצוני, כמו מפתח אלקטרוני, למשתמש Android שלו. כשהנהג מתקרב לרכב, מפתח ה-ECU מתעורר ומזהה את המפתח הפיזי. ה-ECU הזה מציין ל-HAL לאיזה משתמש Android המידע והבידור צריך להפעיל אתחול, שמפחיתה את זמן ההמתנה של הנהג למכשיר ה-Android משתמש לטעינה.
הפעלת 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
וכן הלאה) יש ייצוג ברמה גבוהה
משתמשים ב-C++ struct
, אבל צריך להטמיע את ההסרה
אובייקטים רגילים מסוג VehiclePropValue
(ראו את הדוגמאות בהמשך). בקלות
של פיתוח,
C++
ספריית העזרה זמינה ב-AOSP כדי להמיר באופן אוטומטי את ממשק המשתמש 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
דוגמה להגדרה (Key fob שמשויך למשתמש 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 }