พร็อพเพอร์ตี้ HAL ของผู้ใช้

สถาปัตยกรรมรถยนต์ปัจจุบันจำนวนมากมีหน่วยควบคุมอิเล็กทรอนิกส์หลายหน่วย (ECU) ภายนอกระบบสาระบันเทิงที่ควบคุมหลักการยศาสตร์ เช่น ที่นั่ง การตั้งค่าและการปรับมิเรอร์ อิงตามฮาร์ดแวร์และพลังงานในปัจจุบัน ECU หลายรุ่นมีการทำงานมากขึ้นก่อนระบบสาระบันเทิงที่ใช้ Android เปิดอยู่ ECU เหล่านี้สามารถเชื่อมต่อกับระบบสาระบันเทิงใน Android ผ่านทาง เลเยอร์แอบสแตรกชันของฮาร์ดแวร์ยานพาหนะ (VHAL)

Android Automotive OS (AAOS) เริ่มตั้งแต่ Android 11 ได้เปิดตัวชุด ใน 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 ไม่ตอบสนอง ลักษณะการทำงานเริ่มต้นจะเป็น ทำงานหลังจากระยะหมดเวลา (5 วินาทีโดยค่าเริ่มต้น) ซึ่งทำให้การเปิดเครื่องล่าช้า หาก HAL ตอบกลับ แต่ระบบ Android ดำเนินการไม่สำเร็จ (ตัวอย่างเช่น หากมีผู้ใช้ถึงจำนวนสูงสุดแล้ว) ระบบจะใช้ลักษณะการทำงานเริ่มต้น

ตัวอย่าง: โดยค่าเริ่มต้น ระบบ Android จะเริ่มต้นใน ผู้ใช้ที่ใช้งานอยู่เมื่อเปิดเครื่อง หากตรวจพบกุญแจรีโมตสำหรับผู้ใช้อีกราย ECU จะแทนที่คุณสมบัติ HAL และในระหว่างการเริ่มต้น ระบบ Android จะสลับไปเริ่ม ในผู้ใช้ที่ระบุ

SWITCH_USER
(อ่าน/เขียน)
ระบบจะเรียกพร็อพเพอร์ตี้นี้เมื่อเปลี่ยนผู้ใช้ Android ที่ทำงานอยู่เบื้องหน้า ระบบ Android หรือ HAL สามารถเรียกพร็อพเพอร์ตี้นี้เพื่อ ขอเปลี่ยนผู้ใช้ เวิร์กโฟลว์ทั้ง 3 แบบ ได้แก่
  • ทันสมัย การเปลี่ยนเริ่มจาก CarUserManager
  • เดิม การเปลี่ยนเริ่มจาก ActivityManager
  • ยานพาหนะ HAL โทรติดต่อเพื่อขอเปลี่ยนผู้ใช้

เวิร์กโฟลว์ Modern ใช้วิธีการคอมมิตแบบ 2 ระยะเพื่อให้แน่ใจว่า ซิงค์ระบบ Android กับ ECU ภายนอกแล้ว เมื่อ Android เริ่มเปลี่ยน

  1. ตรวจสอบ HAL เพื่อดูว่าเปลี่ยนผู้ใช้ได้หรือไม่

    HAL ตอบสนองด้วย SUCCESS หรือ FAILURE ดังนั้น Android รู้ว่าจะต้องดำเนินการต่อหรือไม่

  2. ดำเนินการเปลี่ยนผู้ใช้ Android ให้เสร็จสมบูรณ์

    Android ส่งการตอบกลับ ANDROID_POST_SWITCH ไปยัง HAL เพื่อระบุว่าเปลี่ยนสำเร็จหรือล้มเหลว

HAL ควรรอจนกว่าจะถึงวันที่ ANDROID_POST_SWITCH ตอบสนองต่อการอัปเดตสถานะเพื่อซิงค์ ECU หรืออัปเดต HAL อื่นๆ พร็อพเพอร์ตี้

ตัวอย่าง: ขณะเคลื่อนที่ คนขับจะพยายาม เปลี่ยนผู้ใช้ Android ใน UI สาระบันเทิง แต่เนื่องจากคาร์ซีต ที่เชื่อมโยงกับผู้ใช้ Android ที่นั่งจะย้ายระหว่าง เปลี่ยนผู้ใช้ ดังนั้น ECU ที่ควบคุมที่นั่งจะไม่ยืนยันการเปลี่ยน HAL ตอบสนองด้วยความล้มเหลว และผู้ใช้ Android ไม่ถูกเปลี่ยนผ่าน

เวิร์กโฟลว์แบบเดิมเป็นการโทรทางเดียวที่ส่งหลังจากเปลี่ยนผู้ใช้ (เพื่อไม่ให้ HAL บล็อกสวิตช์) โดยจะเรียกใช้เฉพาะเมื่อเปิดเครื่อง (หลังจาก การเปลี่ยนผู้ใช้ครั้งแรก) หรือสำหรับแอปที่โทร ActivityManager.switchUser() แทนที่จะเป็น CarUserManager.switchUser() ข้อมูลอ้างอิง แอป Settings และ SystemUI กำลังใช้ หาก OEM มีแอปการตั้งค่าของตนเองเพื่อเปลี่ยนผู้ใช้ OEM ควรเปลี่ยนการใช้งาน

ตัวอย่าง: หากแอปใช้ ActivityManager.switchUser() ถึง เปลี่ยนผู้ใช้ จากนั้นระบบจะส่งการโทรทางเดียวไปยัง HAL เพื่อแจ้งว่าผู้ใช้ ได้เริ่มทำงานแล้ว

เวิร์กโฟลว์ของยานพาหนะจะเริ่มจาก HAL ไม่ใช่จากระบบ Android

  1. HAL จะขอเปลี่ยนผู้ใช้
  2. ระบบทำการสลับผู้ใช้ Android เสร็จสมบูรณ์
  3. Android จะส่งการตอบสนองของ ANDROID_POST_SWITCH ไปยัง HAL เพื่อระบุว่า เปลี่ยนสำเร็จหรือล้มเหลว

ตัวอย่าง: Bob ใช้กุญแจรีโมตของอลิซเพื่อเปิดรถ และ HAL ได้ตอบกลับคำขอ INITIAL_USER_INFO ด้วย รหัสผู้ใช้ของ Alice ถัดไป ECU เซ็นเซอร์ไบโอเมตริกระบุว่าคนขับคือ Bob HAL ของผู้ใช้ได้ส่งคำขอ SWITCH_USER เพื่อเปลี่ยนผู้ใช้

CREATE_USER
(อ่าน/เขียน)
ระบบ Android จะเรียกพร็อพเพอร์ตี้นี้เมื่อผู้ใช้ Android รายใหม่ ที่สร้าง (โดยใช้ API ของ CarUserManager.createUser())

HAL จะตอบสนองด้วย SUCCESS หรือ FAILURE หาก HAL ตอบสนองในกรณีที่ล้มเหลว ระบบ Android จะนำผู้ใช้ออก

ตัวอย่าง: คนขับแตะไอคอน UI สาระบันเทิงเพื่อ สร้างผู้ใช้ Android ใหม่ การดำเนินการนี้จะส่งคำขอไปยัง HAL และส่วนที่เหลือ ของระบบย่อยของยานพาหนะ ECU จะแจ้งผู้ใช้ที่สร้างใหม่ อื่นๆ ระบบย่อยและ ECU จะเชื่อมโยงรหัสผู้ใช้ภายในกับ Android User ID

REMOVE_USER
(เขียนเท่านั้น)
ระบบ Android เรียกใช้พร็อพเพอร์ตี้นี้หลังจากผู้ใช้ Android คือ ถูกนำออกแล้ว (โดยใช้เมธอด CarUserManager.removeUser())

วิธีนี้เป็นการโทรทางเดียว โดยคาดว่าจะไม่มีการตอบกลับจาก HAL

ตัวอย่าง: คนขับแตะเพื่อนําโฆษณาเดิมออก ผู้ใช้ Android ใน UI สาระบันเทิง มีข้อมูล HAL และ ระบบย่อยของยานพาหนะและ ECU ได้รับแจ้งเกี่ยวกับการนำผู้ใช้ออก สามารถนำรหัสผู้ใช้ภายในออกได้

พร็อพเพอร์ตี้เพิ่มเติม

ต่อไปนี้เป็นพร็อพเพอร์ตี้เพิ่มเติมที่ไม่เกี่ยวข้องกับสถานะวงจรของผู้ใช้ แต่ละวิธีสามารถติดตั้งใช้งานได้โดยไม่ต้องสนับสนุน HAL ของผู้ใช้

คุณสมบัติ HAL คำอธิบาย
USER_IDENTIFICATION_ASSOCIATION
(อ่าน/เขียน)
ใช้พร็อพเพอร์ตี้นี้เพื่อเชื่อมโยงผู้ใช้ Android กับการระบุตัวตน เช่น กุญแจรีโมตหรือโทรศัพท์ ใช้พร็อพเพอร์ตี้เดียวกันนี้เพื่อ การเชื่อมโยง get หรือ set

ตัวอย่าง: คนขับแตะไอคอน UI สาระบันเทิงเพื่อเชื่อมโยง กุญแจรีโมตที่ใช้เปิดรถ (KEY_123) ให้ผู้ใช้ Android ที่ใช้งานอยู่ (USER_11).

ไลบรารีตัวช่วย

ออบเจ็กต์ทั้งหมดที่ใช้ในคำขอและข้อความตอบกลับ (เช่น UserInfo InitialUserInfoRequest InitialUSerInfoResponse และอื่นๆ) มีระดับตัวแทนระดับสูง โดยใช้ C++ struct แต่การนำออกจะต้องแยกเป็น ออบเจ็กต์ VehiclePropValue มาตรฐาน (ดูตัวอย่างด้านล่าง) เพื่อความสะดวก ของการพัฒนา C++ ไลบรารีตัวช่วยจะมีอยู่ใน AOSP เพื่อแปลง HAL ของผู้ใช้โดยอัตโนมัติ structs ลงใน VehiclePropValue (และในทางกลับกัน)

ตัวอย่าง

ข้อมูลผู้ใช้เริ่มต้น

ตัวอย่างคำขอ (เมื่อเปิดเครื่องครั้งแรก)

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
}

ตัวอย่างการตอบสนองหลังการเปลี่ยนสำหรับเวิร์กโฟลว์ที่ทันสมัย

การตอบสนองนี้มักเกิดขึ้นเมื่อการเปลี่ยน 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)
}

สร้างผู้ใช้

ตัวอย่างคำขอ

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
}

นำผู้ใช้ออก

ตัวอย่างคำขอ

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
}