คุณสมบัติผู้ใช้ HAL

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

เริ่มตั้งแต่ Android 11 เป็นต้นไป Android Automotive OS (AAOS) ได้เปิดตัวชุดคุณสมบัติใหม่บน VHAL สำหรับการสร้าง สลับ การนำออก และเชื่อมโยงอุปกรณ์เสริมภายนอกเพื่อระบุผู้ใช้ ตัวอย่างเช่น คุณสมบัติใหม่เหล่านี้ช่วยให้ผู้ขับขี่สามารถ จับคู่ อุปกรณ์เสริมภายนอก เช่น พวงกุญแจ เข้ากับผู้ใช้ Android ได้ จากนั้น เมื่อคนขับเข้าใกล้ตัวรถ ECU จะตื่นขึ้นมาและตรวจพบกุญแจรีโมท ECU นี้ระบุ HAL ว่าผู้ใช้ Android คนใดที่ระบบสาระบันเทิงควรเริ่มการบูต ซึ่งจะช่วยลดเวลาที่คนขับรอให้ผู้ใช้ Android โหลด

เปิดใช้งานผู้ใช้ 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 เชลล์ 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 ตอบสนองโดยการออกเหตุการณ์การเปลี่ยนแปลงคุณสมบัติ

หมายเหตุ: เมื่อรองรับ User HAL จะต้องปรับใช้คุณสมบัติต่อไปนี้ ทั้งหมด

ฮาล พร็อพเพอร์ตี้ คำอธิบาย
INITIAL_USER_INFO
(อ่านเขียน)
ระบบ Android เรียกคุณสมบัตินี้เพื่อกำหนดว่าผู้ใช้ Android คนใดที่ระบบจะเริ่มทำงานเมื่ออุปกรณ์บูทหรือกลับมาทำงานต่อจาก Suspend-to-RAM (STR) เมื่อถูกเรียก HAL จะต้องตอบกลับด้วยตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้:
  • ลักษณะการทำงานเริ่มต้นที่กำหนดโดย Android (สลับไปยังผู้ใช้ที่ใช้ครั้งล่าสุดหรือสร้างผู้ใช้ใหม่หากนี่เป็นการบูตครั้งแรก)
  • สลับไปยังผู้ใช้ที่มีอยู่
  • สร้างผู้ใช้ใหม่ (ด้วยคุณสมบัติทางเลือกของชื่อ แฟล็ก ภาษาของระบบ และอื่นๆ) และสลับไปยังผู้ใช้ใหม่นั้น

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

ตัวอย่างเช่น ตามค่าเริ่มต้น ระบบ Android จะเริ่มทำงานใน User ที่ใช้งานล่าสุดเมื่อบูต หากตรวจพบกุญแจสำหรับผู้ใช้รายอื่น 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 ใน 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 ใช้กุญแจรีโมทของ Alice เพื่อเปิดรถ และ HAL ตอบกลับคำขอ INITIAL_USER_INFO ด้วย ID ผู้ใช้ของ Alice ถัดไป ECU เซ็นเซอร์ไบโอเมตริกซ์ระบุว่าคนขับคือ Bob ดังนั้นผู้ใช้ HAL จึงส่งคำขอ SWITCH_USER เพื่อเปลี่ยนผู้ใช้

CREATE_USER
(อ่านเขียน)
ระบบ Android เรียกคุณสมบัตินี้เมื่อมีการสร้างผู้ใช้ Android ใหม่ (โดยใช้ CarUserManager.createUser() API)

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

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

REMOVE_USER
(เขียนเท่านั้น)
ระบบ Android เรียกคุณสมบัตินี้หลังจากที่ผู้ใช้ Android ถูกลบออก (ด้วย CarUserManager.removeUser() API)

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

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

คุณสมบัติเพิ่มเติม

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

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

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

ห้องสมุดผู้ช่วย

ออบเจ็กต์ทั้งหมดที่ใช้ในข้อความคำขอและตอบกลับ (เช่น UserInfo , InitialUserInfoRequest , InitialUSerInfoResponse และอื่นๆ) มีการแสดงระดับสูงโดยใช้ C++ struct แต่การลบจะต้องถูก ทำให้เรียบลง ในออบเจ็กต์ VehiclePropValue มาตรฐาน (ดูตัวอย่างด้านล่าง) เพื่อความสะดวกในการพัฒนา ไลบรารีตัวช่วย C++ จึงมีอยู่ใน AOSP เพื่อแปลง structs User HAL ให้เป็น 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
}

ตัวอย่างการตอบกลับ (สร้าง Admin User)

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

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

ตั้งค่าตัวอย่าง (ปุ่มกดที่เกี่ยวข้องกับผู้ใช้ 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
}