מאפייני HAL של משתמש

ארכיטקטורות קיימות של כלי רכב כוללות כמה יחידות בקרה אלקטרוניות (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 צריך להגיב עם אחת מהאפשרויות אפשרויות אלה:
  • התנהגות ברירת המחדל שהוגדרה על ידי Android (מעבר להתנהגות האחרונה שהייתה בשימוש) משתמש או יצירת משתמש חדש, אם זו ההפעלה הראשונה).
  • מעבר למשתמש קיים.
  • יצירת משתמש חדש (עם המאפיינים האופציונליים של שם, דגלים, מערכת המקומי, וכן הלאה) ועוברים למשתמש החדש.

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

דוגמה: כברירת מחדל, מערכת Android מתחילה משתמש פעיל בזמן האתחול. אם מזוהה מפתח פיזי של משתמש אחר, ה-ECU מבטל את מאפיין HAL, ובמהלך ההפעלה, מערכת Android מתחילה להתחיל במשתמש שצוין.

SWITCH_USER
(קריאה/כתיבה)
הנכס הזה מופעל כשמחליפים את משתמש Android הפעיל שפועל בחזית. אפשר לקרוא לנכס באמצעות מערכת Android או באמצעות HAL כדי לבקש החלפת משתמש. שלושת תהליכי העבודה הם:
  • מודרני. ההעברה התחילה מ-CarUserManager.
  • השיטה הקודמת. ההעברה התחילה מ-ActivityManager.
  • רכב. הופעלה על ידי HAL כדי לבקש החלפת משתמש.

תהליך העבודה המודרני משתמש בגישת התחייבות דו-שלבית כדי להבטיח מערכת Android ומכשיר ה-ECU החיצוני מסונכרנים. כאשר Android מתחיל את המעבר:

  1. יש לבדוק את ממשק HAL כדי לקבוע אם ניתן להחליף את המשתמש.

    פלטפורמת HAL מגיבה באמצעות SUCCESS או FAILURE, כך מערכת Android יודעת אם להמשיך או לא.

  2. משלימים את המעבר למשתמש ב-Android.

    Android שולח את תגובת ANDROID_POST_SWITCH אל HAL כדי לציין שההחלפה הצליחה או נכשלה.

הנחיות ה-HAL צריכות להמתין עד אחרי ANDROID_POST_SWITCH תגובה לעדכון המצב שלה כדי לסנכרן ECU או לעדכן HAL אחר נכסים.

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

תהליך העבודה מהדור הקודם הוא שיחה חד-כיוונית שנשלחת אחרי החלפת המשתמש (כך שכלי ה-HAL לא יכול לחסום את המתג). היא נקראת רק בזמן האתחול (לאחר או עבור אפליקציות שמתקשרות ActivityManager.switchUser() במקום CarUserManager.switchUser(). ההפניה האפליקציות Settings ו-SystemUI כבר משתמשות אבל אם יצרן ציוד מקורי מספק אפליקציות הגדרות משלו להחלפת משתמשים, יצרני ציוד מקורי צריכים לשנות את השימוש.

לדוגמה: אם אפליקציה משתמשת ActivityManager.switchUser() אל עובר בין משתמשים, ואז נשלחת קריאה חד-כיוונית ל-HAL כדי ליידע שההחלפה בוצעה.

תהליך העבודה של הרכב מגיע מ-HAL ולא ממערכת Android:

  1. מערכת HAL מבקשת החלפת משתמש.
  2. המערכת משלימה את המעבר בין משתמשי Android.
  3. מערכת Android שולחת תגובת ANDROID_POST_SWITCH ל-HAL כדי לציין הצלחה או כישלון.

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

CREATE_USER
(קריאה/כתיבה)
מערכת Android מפעילה את הנכס הזה כשמשתמש חדש של Android נוצר (באמצעות ה-API CarUserManager.createUser()).

התשובה של HAL היא SUCCESS או FAILURE. אם HAL מגיב עם כשל, מערכת Android מסירה את המשתמש.

לדוגמה: נהג מקיש על סמל של ממשק משתמש של מידע ובידור יוצרים משתמש Android חדש. הפעולה הזו שולחת בקשה ל-HAL ולשאר של תת-מערכות הרכב. ה-ECU מקבל מידע על המשתמש החדש שנוצר. המלצות אחרות מערכות המשנה וה-ECU משייכים את מזהה המשתמש הפנימי שלהם ל-Android מזהה משתמש.

REMOVE_USER
(בכתיבה בלבד)
מערכת Android מפעילה את הנכס הזה אחרי שמשתמש Android הוסר (באמצעות השיטה CarUserManager.removeUser()).

זוהי שיחה חד-כיוונית – לא צפויה תגובה מ-HAL.

דוגמה: נהג מקיש כדי להסיר כביש קיים משתמש Android בממשק המשתמש של המידע והבידור. הוא מבוסס על HAL מערכות המשנה של הרכבים וה-ECU מקבלים מידע על הסרת המשתמש כדי יכולים להסיר את מזהה המשתמש הפנימי שלו.

נכסים נוספים

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

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

דוגמה: נהג מקיש על סמל של ממשק משתמש של מידע ובידור כדי לשייך אותו המפתח הפיזי המשמש לפתיחת הרכב (KEY_123) למשתמש Android הפעיל הנוכחי (USER_11).

ספריות מסייעות

כל האובייקטים שנמצאים בשימוש בהודעות הבקשה ובתשובה (כמו 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
}