مواقع HAL للمستخدم

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

بدءًا من الإصدار 11 من نظام التشغيل Android، قدّم نظام التشغيل Android Automotive (AAOS) مجموعة جديدة من السمات في VHAL لإنشاء الملحقات الخارجية بديلة واستخدامها وإزالتها وربطها لتحديد المستخدمين. فمثلاً، تتيح هذه السمات الجديدة للسائق ربط ملحق خارجي، مثل مفتاح لاسلكي لمستخدم Android، للسائق. بعد ذلك، عندما يقترب السائق من المركبة، يتم تنشيط وحدة التحكّم الإلكترونية (ECU) ورصد المفتاح اللاسلكي. يشير هذا وحدة التحكّم في المحرك إلى HAL الذي يجب أن يبدأ مستخدم Android فيه عملية التشغيل، ما يقلل من الوقت الذي ينتظره السائق لتحميل مستخدم Android.

تفعيل HAL للمستخدم

يجب تفعيل سمات HAL للمستخدمين صراحةً من خلال التأكّد من ضبط سمة system 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 للمستخدم متوافقًا، يجب تنفيذ جميع السمات التالية.

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

ملاحظة: إذا لم يستجِب HAL، يكون السلوك التلقائي هو التنفيذ بعد فترة مهلة (خمس ثوانٍ تلقائيًا)، ما يؤخّر عملية التمهيد. إذا ردّ 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، يتم تحريك المقعد أثناء تبديل المستخدم. وبالتالي، لا يؤكّد وحدة التحكّم في الإشعال (ECU) التي تتحكّم في المقاعد عملية التبديل، ويردّ HAL بخطأ، ولا يتم تبديل مستخدم Android.

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

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

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

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

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

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

تتجاوب قناة HAL مع SUCCESS أو FAILURE. إذا كان الردّ من واجهة برمجة التطبيقات HAL يشير إلى حدوث خطأ، يزيل نظام Android المستخدم.

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

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

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

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

المواقع الإضافية

في ما يلي سمات إضافية غير مرتبطة بحالات رحلة المستخدِم. ويمكن تنفيذ كل منهما بدون توفير واجهة برمجة التطبيقات لمستوى الحِزم للمستخدم.

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

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

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

تتضمّن جميع العناصر المستخدَمة في رسائل الطلب والردّ (مثل 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
}

مثال على الردّ (إنشاء مستخدم مشرف)

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

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
}