خصائص HAL للمستخدم

تحتوي العديد من هياكل المركبات الحالية على وحدات تحكم إلكترونية متعددة (ECUs) خارج نظام المعلومات والترفيه والتي تتحكم في بيئة العمل، مثل إعدادات المقعد وتعديلات المرآة. استنادًا إلى بنيات الأجهزة والطاقة الحالية، يتم تشغيل العديد من وحدات التحكم الإلكترونية قبل تشغيل نظام المعلومات والترفيه المستند إلى نظام Android. يمكن لوحدات التحكم الإلكترونية هذه التفاعل مع نظام المعلومات والترفيه المستند إلى Android من خلال طبقة تجريد أجهزة السيارة (VHAL) .

بدءًا من Android 11، قدم نظام التشغيل Android Automotive OS (AAOS) مجموعة جديدة من الخصائص على VHAL لإنشاء الملحقات الخارجية وتبديلها وإزالتها وربطها لتحديد المستخدمين. على سبيل المثال، تتيح هذه الخصائص الجديدة للسائق إمكانية ربط ملحق خارجي، مثل سلسلة المفاتيح، بمستخدم Android الخاص به. وبعد ذلك، عندما يقترب السائق من السيارة، تستيقظ وحدة التحكم الإلكترونية وتكتشف سلسلة المفاتيح. تشير وحدة التحكم الإلكترونية هذه إلى 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 ووحدة التحكم الإلكترونية الخارجية. تستخدم هذه الخصائص بروتوكول الطلب والاستجابة، حيث يقوم نظام Android بتقديم طلب عن طريق تعيين قيمة خاصية ويستجيب HAL عن طريق إصدار حدث تغيير الخاصية.

ملاحظة: عندما يتم دعم HAL للمستخدم، يجب تنفيذ كافة الخصائص التالية.

ملكية هال وصف
INITIAL_USER_INFO
(قراءة و كتابة)
يتم استدعاء هذه الخاصية بواسطة نظام Android لتحديد مستخدم Android الذي سيبدأ النظام عند تشغيل الجهاز أو استئناف تشغيله من Suspend-to-RAM (STR). عند الاتصال، يجب أن تستجيب HAL بأحد الخيارات التالية:
  • السلوك الافتراضي الذي يحدده Android (التبديل إلى آخر مستخدم مستخدم أو إنشاء مستخدم جديد إذا كان هذا هو التمهيد الأول).
  • التبديل إلى مستخدم موجود.
  • قم بإنشاء مستخدم جديد (مع الخصائص الاختيارية للاسم، والأعلام، ولغة النظام، وما إلى ذلك) وقم بالتبديل إلى هذا المستخدم الجديد.

ملاحظة: إذا لم يستجب HAL، فإن السلوك الافتراضي هو التنفيذ بعد فترة مهلة (خمس (5) ثوانٍ افتراضيًا)، مما يؤدي إلى تأخير التمهيد. إذا استجابت HAL، ولكن فشل نظام Android في تنفيذ الإجراء (على سبيل المثال، إذا تم الوصول إلى الحد الأقصى لعدد المستخدمين)، فسيتم استخدام السلوك الافتراضي.

على سبيل المثال، افتراضيًا، يبدأ نظام Android في آخر مستخدم نشط عند التمهيد. إذا تم اكتشاف سلسلة مفاتيح لمستخدم مختلف، فإن وحدة التحكم الإلكترونية تتجاوز خاصية HAL، وأثناء بدء التشغيل، يقوم نظام Android بالتبديل للبدء في ذلك المستخدم المحدد.

SWITCH_USER
(قراءة و كتابة)
يتم استدعاء هذه الخاصية عند تبديل مستخدم Android النشط في المقدمة. يمكن استدعاء الخاصية إما بواسطة نظام Android أو بواسطة HAL لطلب تبديل المستخدم. سير العمل الثلاثة هي:
  • حديث. بدأ التبديل من CarUserManager .
  • إرث. بدأ التبديل من ActivityManager .
  • عربة. يتم استدعاؤه بواسطة HAL لطلب تبديل المستخدم.

يستخدم سير العمل الحديث أسلوب الالتزام على مرحلتين لضمان مزامنة نظام Android ووحدة التحكم الإلكترونية الخارجية. عندما يبدأ Android التبديل:

  1. تحقق من HAL لتحديد ما إذا كان يمكن تبديل المستخدم.

    يستجيب HAL SUCCESS أو FAILURE ، حتى يعرف Android ما إذا كان يجب المتابعة أم لا.

  2. أكمل تبديل مستخدم Android.

    يرسل Android استجابة ANDROID_POST_SWITCH إلى HAL للإشارة إلى نجاح التبديل أو فشله.

يجب أن ينتظر HAL حتى بعد استجابة ANDROID_POST_SWITCH لتحديث حالته لمزامنة وحدات التحكم الإلكترونية أو تحديث خصائص HAL الأخرى.

على سبيل المثال، أثناء الحركة، يحاول السائق تبديل مستخدمي Android في واجهة مستخدم نظام المعلومات والترفيه. ومع ذلك، نظرًا لأن إعدادات مقعد السيارة مرتبطة بمستخدم Android، فإن المقعد سيتحرك أثناء تبديل المستخدم. ومن ثم، فإن وحدة التحكم الإلكترونية في المقاعد لا تؤكد التبديل، ويستجيب HAL بفشل، ولا يتم تبديل مستخدم Android.

سير العمل القديم عبارة عن مكالمة أحادية الاتجاه يتم إرسالها بعد تبديل المستخدم (وبالتالي لا يمكن لـ HAL حظر التبديل). يتم استدعاؤه فقط عند التمهيد (بعد تبديل المستخدم الأولي) أو للتطبيقات التي تستدعي ActivityManager.switchUser() بدلاً من CarUserManager.switchUser() . تستخدم Settings المرجعية وتطبيقات SystemUI بالفعل الأخير، ولكن إذا كانت الشركة المصنعة للمعدات الأصلية توفر تطبيقات الإعدادات الخاصة بها لتبديل المستخدمين، فيجب على الشركات المصنعة للمعدات الأصلية تغيير الاستخدام.

على سبيل المثال، إذا كان أحد التطبيقات يستخدم ActivityManager.switchUser() لتبديل المستخدمين، فسيتم إرسال مكالمة أحادية الاتجاه إلى HAL لإبلاغه بحدوث تبديل المستخدم.

ينشأ سير عمل المركبة من HAL، وليس من نظام Android:

  1. يطلب HAL تبديل المستخدم.
  2. يكمل النظام تبديل مستخدم Android.
  3. يرسل Android استجابة ANDROID_POST_SWITCH إلى HAL للإشارة إلى نجاح التبديل أو فشله.

على سبيل المثال ، استخدم بوب سلسلة المفاتيح الخاصة بـ Alice لفتح السيارة وقام HAL بالرد على طلب INITIAL_USER_INFO باستخدام معرف المستخدم الخاص بـ Alice. بعد ذلك، حدد جهاز استشعار البيومترية ECU السائق على أنه بوب، لذلك أرسل المستخدم HAL طلب SWITCH_USER لتبديل المستخدمين.

CREATE_USER
(قراءة و كتابة)
يتم استدعاء هذه الخاصية بواسطة نظام Android عند إنشاء مستخدم Android جديد (باستخدام CarUserManager.createUser() API).

يستجيب HAL SUCCESS أو FAILURE . إذا استجابت HAL بالفشل، فسيقوم نظام Android بإزالة المستخدم.

على سبيل المثال، ينقر السائق على أيقونة واجهة مستخدم نظام المعلومات والترفيه لإنشاء مستخدم Android جديد. يؤدي هذا إلى إرسال طلب إلى HAL وبقية الأنظمة الفرعية للمركبة. يتم إبلاغ وحدات التحكم الإلكترونية بالمستخدم الذي تم إنشاؤه حديثًا. تقوم الأنظمة الفرعية ووحدات التحكم الإلكترونية الأخرى بعد ذلك بربط معرف المستخدم الداخلي الخاص بها بمعرف مستخدم Android.

REMOVE_USER
(للكتابة فقط)
يستدعي نظام Android هذه الخاصية بعد إزالة مستخدم Android (باستخدام واجهة برمجة تطبيقات CarUserManager.removeUser() ).

هذه مكالمة أحادية الاتجاه — لا يُتوقع أي رد من HAL.

على سبيل المثال، يقوم السائق بالنقر لإزالة مستخدم Android موجود في واجهة مستخدم نظام المعلومات والترفيه. يتم إبلاغ HAL ويتم إبلاغ الأنظمة الفرعية للمركبة ووحدات التحكم الإلكترونية الأخرى بإزالة المستخدم حتى يتمكنوا من إزالة معرف المستخدم الداخلي الخاص بهم.

خصائص إضافية

فيما يلي خصائص إضافية، لا علاقة لها بحالات دورة حياة المستخدم. يمكن تنفيذ كل منها دون دعم HAL للمستخدم.

ملكية هال وصف
USER_IDENTIFICATION_ASSOCIATION
(قراءة و كتابة)
استخدم هذه الخاصية لربط أي مستخدم Android بآلية تحديد الهوية، مثل سلسلة المفاتيح أو الهاتف. استخدم هذه الخاصية نفسها get الارتباطات أو set .

على سبيل المثال، ينقر السائق على أيقونة واجهة مستخدم نظام المعلومات والترفيه لربط سلسلة المفاتيح المستخدمة لفتح السيارة (KEY_123) بمستخدم Android النشط الحالي (USER_11).

المكتبات المساعدة

جميع الكائنات المستخدمة في رسائل الطلب والاستجابة (مثل UserInfo و InitialUserInfoRequest و InitialUSerInfoResponse وما إلى ذلك) لها تمثيل عالي المستوى باستخدام struct C++، ولكن يجب تسوية الإزالة في كائنات VehiclePropValue القياسية (انظر الأمثلة أدناه). لسهولة التطوير، يتم توفير مكتبة مساعد C++ في AOSP لتحويل structs 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
}

مثال على الاستجابة (إنشاء مستخدم إداري)

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
}