ویژگی های HAL کاربر

بسیاری از معماری‌های فعلی خودرو شامل چندین واحد کنترل الکترونیکی (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 باید با یکی از این گزینه ها پاسخ دهد:
  • رفتار پیش‌فرض تنظیم‌شده توسط Android (تغییر به آخرین کاربر استفاده شده یا ایجاد کاربر جدید در صورتی که این اولین بوت است).
  • به یک کاربر موجود تغییر دهید.
  • یک کاربر جدید ایجاد کنید (با ویژگی های اختیاری نام، پرچم ها، سیستم محلی و غیره) و به آن کاربر جدید بروید.

توجه: اگر HAL پاسخ ندهد، رفتار پیش‌فرض این است که پس از یک بازه زمانی (به طور پیش‌فرض پنج ثانیه) اجرا شود، که بوت را به تأخیر می‌اندازد. اگر HAL پاسخ دهد، اما سیستم Android این عمل را اجرا نکند (به عنوان مثال، اگر به حداکثر تعداد کاربران رسیده باشد)، از رفتار پیش فرض استفاده می شود.

مثال: به طور پیش‌فرض، سیستم اندروید در آخرین کاربر فعال هنگام بوت شروع می‌شود. اگر یک صفحه کلید برای کاربر دیگری شناسایی شود، ECU ویژگی HAL را لغو می‌کند و در حین راه‌اندازی، سیستم Android برای شروع در آن کاربر مشخص شده سوئیچ می‌کند.

SWITCH_USER
(خواندن/نوشتن)
این ویژگی هنگام تعویض کاربر فعال پیش زمینه اندروید فراخوانی می شود. این ویژگی می تواند توسط سیستم اندروید یا HAL برای درخواست سوئیچ کاربر فراخوانی شود. این سه گردش کار عبارتند از:
  • مدرن. سوئیچ از CarUserManager شروع شد.
  • میراث. سوئیچ از ActivityManager شروع شد.
  • وسیله نقلیه توسط HAL برای درخواست سوئیچ کاربر فراخوانی می شود.

گردش کار مدرن از یک رویکرد تعهد دو فازی برای اطمینان از همگام سازی سیستم اندروید و ECU خارجی استفاده می کند. هنگامی که Android سوئیچ را راه اندازی می کند:

  1. برای تعیین اینکه آیا کاربر می تواند تغییر کند، HAL را بررسی کنید.

    HAL با SUCCESS یا FAILURE پاسخ می‌دهد تا Android بداند ادامه دهد یا خیر.

  2. سوئیچ کاربر اندروید را کامل کنید.

    Android یک پاسخ ANDROID_POST_SWITCH به HAL ارسال می کند تا موفقیت یا شکست سوئیچ را نشان دهد.

HAL باید تا پس از پاسخ ANDROID_POST_SWITCH صبر کند تا وضعیت خود را برای همگام سازی ECU یا به روز رسانی سایر ویژگی های HAL به روز کند.

مثال: در حال حرکت، راننده تلاش می‌کند تا کاربران Android را در رابط کاربری اطلاعات سرگرمی تغییر دهد. با این حال، از آنجایی که تنظیمات صندلی ماشین به کاربر اندروید گره خورده است، صندلی در حین سوئیچ کاربر حرکت می کند. بنابراین، ECU که صندلی‌ها را کنترل می‌کند، سوئیچ را تأیید نمی‌کند، HAL با خرابی پاسخ می‌دهد، و کاربر اندرویدی تغییر نمی‌کند.

گردش کار Legacy یک تماس یک طرفه است که پس از تعویض کاربر ارسال می شود (بنابراین HAL نمی تواند سوئیچ را مسدود کند). فقط در هنگام بوت (پس از سوئیچ کاربر اولیه) یا برای برنامه هایی که به جای ActivityManager.switchUser() CarUserManager.switchUser() فراخوانی می کنند، فراخوانی می شود. Settings مرجع و برنامه‌های SystemUI قبلاً از دومی استفاده می‌کنند، اما اگر یک OEM برنامه‌های تنظیمات خود را برای جابه‌جایی کاربران ارائه کند، OEM‌ها باید استفاده را تغییر دهند.

مثال: اگر یک برنامه از ActivityManager.switchUser() برای جابه‌جایی کاربران استفاده کند، یک تماس یک طرفه به HAL ارسال می‌شود تا اطلاع دهد که یک سوئیچ کاربر انجام شده است.

گردش کار Vehicle از HAL سرچشمه می گیرد، نه از سیستم Android:

  1. HAL یک سوئیچ کاربر درخواست می کند.
  2. سیستم سوئیچ کاربر اندروید را تکمیل می کند.
  3. Android یک پاسخ ANDROID_POST_SWITCH به HAL ارسال می کند تا موفقیت یا شکست سوئیچ را نشان دهد.

مثال: باب از جاکلیدی آلیس برای باز کردن ماشین استفاده کرد و HAL با شناسه کاربری آلیس به درخواست INITIAL_USER_INFO پاسخ داد. در مرحله بعد، یک ECU حسگر بیومتریک راننده را باب شناسایی کرد، بنابراین کاربر HAL یک درخواست SWITCH_USER برای تغییر کاربر ارسال کرد.

CREATE_USER
(خواندن/نوشتن)
این ویژگی زمانی که یک کاربر اندروید جدید ایجاد می شود (با استفاده از API CarUserManager.createUser() ) توسط سیستم اندروید فراخوانی می شود.

HAL با SUCCESS یا FAILURE پاسخ می دهد. اگر HAL با خرابی پاسخ دهد، سیستم Android کاربر را حذف می کند.

مثال: یک راننده روی نماد رابط کاربری اطلاعات سرگرمی ضربه می زند تا یک کاربر اندروید جدید ایجاد کند. این یک درخواست به HAL و بقیه زیرسیستم های خودرو ارسال می کند. ECU ها از کاربر تازه ایجاد شده مطلع می شوند. سپس سایر زیرسیستم ها و ECU ها شناسه کاربری داخلی خود را با شناسه کاربری اندروید مرتبط می کنند.

REMOVE_USER
(فقط بنویسید)
سیستم اندروید این ویژگی را پس از حذف یک کاربر اندروید (با متد CarUserManager.removeUser() ) فراخوانی می کند.

این یک تماس یک طرفه است، هیچ پاسخی از HAL انتظار نمی رود.

مثال: یک راننده برای حذف یک کاربر Android موجود در رابط کاربری اطلاعات سرگرمی ضربه می زند. HAL مطلع می شود و سایر زیرسیستم های خودرو و ECU ها از حذف کاربر مطلع می شوند تا بتوانند شناسه کاربری داخلی خود را حذف کنند.

خواص اضافی

موارد زیر ویژگی‌های اضافی هستند که به حالت‌های چرخه عمر کاربر مرتبط نیستند. هر کدام را می توان بدون پشتیبانی از کاربر HAL پیاده سازی کرد.

دارایی HAL توضیحات
USER_IDENTIFICATION_ASSOCIATION
(خواندن/نوشتن)
از این ویژگی برای مرتبط کردن هر کاربر اندرویدی با مکانیزم شناسایی مانند جا کلیدی یا تلفن استفاده کنید. از همین ویژگی برای 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
}

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
}