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

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

ใน Android 11 เป็นต้นไป 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 ที่ระบบเริ่มต้นเมื่ออุปกรณ์เปิดเครื่องหรือกลับมาทำงานอีกครั้งจากการระงับไปยัง RAM (STR) เมื่อได้รับแจ้ง HAL จะต้องตอบกลับด้วยตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้
  • ลักษณะการทำงานเริ่มต้นที่ Android กำหนด (เปลี่ยนไปใช้ผู้ใช้ที่ใช้ล่าสุดหรือสร้างผู้ใช้ใหม่หากเป็นการบูตครั้งแรก)
  • เปลี่ยนเป็นผู้ใช้ที่มีอยู่
  • สร้างผู้ใช้ใหม่ (ซึ่งมีพร็อพเพอร์ตี้ที่ไม่บังคับ เช่น ชื่อ แฟล็ก ภาษาของระบบ และอื่นๆ) แล้วเปลี่ยนไปใช้ผู้ใช้ใหม่ดังกล่าว

หมายเหตุ: หาก HAL ไม่ตอบสนอง ลักษณะการทำงานเริ่มต้นจะดำเนินการหลังจากหมดเวลา (5 วินาทีโดยค่าเริ่มต้น) ซึ่งจะทำให้การบูตล่าช้า หาก HAL ตอบกลับ แต่ระบบ Android ดำเนินการไม่สำเร็จ (เช่น หากมีผู้ใช้ถึงจำนวนสูงสุดแล้ว) ระบบจะใช้ลักษณะการทำงานเริ่มต้น

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

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

เวิร์กโฟลว์สมัยใหม่ใช้แนวทางการคอมมิตแบบ 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() เพื่อสลับผู้ใช้ ระบบจะส่งการเรียกแบบ 1 ทิศทางไปยัง HAL เพื่อแจ้งว่ามีการสลับผู้ใช้

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

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

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

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

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

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

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
}

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)
}

สร้างผู้ใช้

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

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
}