بسیاری از معماریهای فعلی خودرو شامل چندین واحد کنترل الکترونیکی (ECU) در خارج از سیستم اطلاعات سرگرمی هستند که ارگونومی، مانند تنظیمات صندلی و تنظیمات آینه را کنترل میکنند. بر اساس ساختارهای سخت افزاری و قدرت فعلی، بسیاری از ECU ها قبل از روشن شدن سیستم اطلاعات سرگرمی مبتنی بر Android روشن می شوند. این ECU ها می توانند از طریق لایه انتزاعی سخت افزاری خودرو (VHAL) با سیستم اطلاعات سرگرمی مبتنی بر اندروید ارتباط برقرار کنند.
با شروع اندروید 11، سیستم عامل Android Automotive (AAOS) مجموعه جدیدی از ویژگی ها را در VHAL برای ایجاد، تعویض، حذف و مرتبط کردن لوازم جانبی خارجی برای شناسایی کاربران معرفی کرد. برای مثال، این ویژگیهای جدید درایور را قادر میسازد تا یک لوازم جانبی خارجی، مانند جا کلیدی، را به کاربر اندروید خود متصل کند . سپس، هنگامی که راننده به وسیله نقلیه نزدیک می شود، یک ECU از خواب بیدار می شود و فوب کلید را تشخیص می دهد. این ECU به HAL نشان میدهد که سیستم اطلاعات سرگرمی کدام کاربر اندرویدی را باید راهاندازی کند، که زمان انتظار راننده برای بارگیری کاربر اندرویدی خود را کاهش میدهد.
کاربر HAL را فعال کنید
ویژگی های کاربر HAL باید با اطمینان از اینکه ویژگی سیستم android.car.user_hal_enabled
روی true
تنظیم شده است، به صراحت فعال شود. (این کار را می توان در فایل car.mk
نیز انجام داد تا نیازی به تنظیم دستی نباشد.) با ریختن UserHalService
بررسی کنید که user_hal_enabled=true
فعال باشد:
$ 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 خارجی فعال میکند. این ویژگی ها از یک پروتکل درخواست و پاسخ استفاده می کنند که در آن سیستم اندروید با تنظیم مقدار خاصیت درخواست می کند و HAL با صدور یک رویداد تغییر ویژگی پاسخ می دهد.
توجه: هنگامی که کاربر HAL پشتیبانی می شود، تمام ویژگی های زیر باید پیاده سازی شوند.
دارایی HAL | توضیحات |
---|---|
INITIAL_USER_INFO (خواندن/نوشتن) | این ویژگی توسط سیستم Android فراخوانی میشود تا مشخص کند که سیستم از کدام کاربر اندرویدی هنگام بوت شدن یا از سرگیری سیستم از Suspend-to-RAM (STR) شروع میشود. هنگام فراخوانی، HAL باید با یکی از این گزینه ها پاسخ دهد:
توجه: اگر HAL پاسخ ندهد، رفتار پیشفرض این است که پس از یک بازه زمانی (به طور پیشفرض پنج ثانیه) اجرا شود، که بوت را به تأخیر میاندازد. اگر HAL پاسخ دهد، اما سیستم Android این عمل را اجرا نکند (به عنوان مثال، اگر به حداکثر تعداد کاربران رسیده باشد)، از رفتار پیش فرض استفاده می شود. مثال: بهطور پیشفرض، سیستم اندروید در آخرین کاربر فعال در هنگام بوت شروع میشود. اگر یک صفحه کلید برای کاربر دیگری شناسایی شود، ECU ویژگی HAL را لغو میکند و در حین راهاندازی، سیستم Android برای شروع در آن کاربر مشخص شده تغییر میکند. |
SWITCH_USER (خواندن/نوشتن) | این ویژگی هنگام تعویض کاربر فعال پیش زمینه Android فراخوانی می شود. این ویژگی می تواند توسط سیستم اندروید یا HAL برای درخواست سوئیچ کاربر فراخوانی شود. این سه گردش کار عبارتند از:
گردش کار مدرن از یک رویکرد تعهد دو فازی برای اطمینان از همگام سازی سیستم اندروید و ECU خارجی استفاده می کند. هنگامی که Android سوئیچ را راه اندازی می کند:
HAL باید تا پس از پاسخ مثال: در حال حرکت، راننده تلاش میکند تا کاربران Android را در رابط کاربری اطلاعات سرگرمی تغییر دهد. با این حال، از آنجایی که تنظیمات صندلی ماشین به کاربر Android گره خورده است، صندلی در طول سوئیچ کاربر حرکت می کند. بنابراین، ECU که صندلیها را کنترل میکند، سوئیچ را تأیید نمیکند، HAL با خرابی پاسخ میدهد، و کاربر Android تغییر نمیکند. گردش کار Legacy یک تماس یک طرفه است که پس از تعویض کاربر ارسال می شود (بنابراین HAL نمی تواند سوئیچ را مسدود کند). فقط در هنگام بوت (پس از سوئیچ کاربر اولیه) یا برای برنامه هایی که به جای مثال: اگر برنامهای از گردش کار Vehicle از HAL سرچشمه می گیرد، نه از سیستم Android:
مثال: باب از جاکلیدی آلیس برای باز کردن ماشین استفاده کرد و HAL با شناسه کاربری آلیس به درخواست |
CREATE_USER (خواندن/نوشتن) | این ویژگی زمانی که یک کاربر اندروید جدید ایجاد می شود (با استفاده از API CarUserManager.createUser() ) توسط سیستم اندروید فراخوانی می شود. HAL با مثال: یک راننده روی نماد رابط کاربری اطلاعات سرگرمی ضربه می زند تا یک کاربر اندروید جدید ایجاد کند. این یک درخواست به HAL و بقیه زیرسیستم های خودرو ارسال می کند. ECU ها از کاربر تازه ایجاد شده مطلع می شوند. سپس سایر زیرسیستم ها و ECU ها شناسه کاربری داخلی خود را با شناسه کاربری Android مرتبط می کنند. |
REMOVE_USER (فقط بنویسید) | سیستم Android این ویژگی را پس از حذف یک کاربر Android (با متد CarUserManager.removeUser() فراخوانی می کند.این یک تماس یک طرفه است - هیچ پاسخی از HAL انتظار نمی رود. مثال: یک راننده برای حذف یک کاربر Android موجود در رابط کاربری اطلاعات سرگرمی ضربه میزند. HAL مطلع می شود و سایر زیرسیستم های خودرو و ECU ها از حذف کاربر مطلع می شوند تا بتوانند شناسه کاربری داخلی خود را حذف کنند. |
خواص اضافی
موارد زیر ویژگیهای اضافی هستند که به حالتهای چرخه عمر کاربر مرتبط نیستند. هر کدام را می توان بدون پشتیبانی از کاربر HAL پیاده سازی کرد.
دارایی HAL | توضیحات |
---|---|
USER_IDENTIFICATION_ASSOCIATION (خواندن/نوشتن) | از این ویژگی برای مرتبط کردن هر کاربر Android با مکانیزم شناسایی، مانند جا کلیدی یا تلفن استفاده کنید. از همین ویژگی برای get یا set ارتباط استفاده کنید. مثال: راننده روی نماد رابط کاربری اطلاعات سرگرمی ضربه میزند تا کلید مورد استفاده برای باز کردن خودرو ( |
کتابخانه های کمکی
تمام اشیاء مورد استفاده در پیامهای درخواست و پاسخ (مانند 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 }
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 }
نمونه پاسخ مدرن پس از تعویض جریان کار
این پاسخ معمولاً زمانی اتفاق میافتد که سوئیچ اندروید موفق شود:
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 }
پاسخ پس از تعویض جریان کار قدیمی
این پاسخ معمولاً زمانی اتفاق میافتد که سوئیچ اندروید موفق شود:
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 }