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

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

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

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

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

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

เวิร์กโฟลว์สมัยใหม่ใช้แนวทางการคอมมิตแบบสองเฟสเพื่อให้แน่ใจว่าระบบ Android และ ECU ภายนอกได้รับการซิงโครไนซ์ เมื่อ Android เริ่มสวิตช์:

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

    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 ผู้ใช้ภายในได้

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

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

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

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

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

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

ตัวอย่าง

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
}

เปลี่ยนผู้ใช้

ชื่อจริงของคลาสและคุณสมบัติแตกต่างกันเล็กน้อย แต่เวิร์กโฟลว์โดยรวมเหมือนกัน ดังที่แสดงด้านล่าง:

เวิร์กโฟลว์

รูปที่ 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

ตั้งค่าตัวอย่าง (คีย์ 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
}