قد يكون التنقل في عالم Android Automotive واتصاله العميق بأنظمة المركبات متاهة، لكن طبقة تجريد المركبة (VHAL) تعد بجسر هذه الفجوة. بالتعمق في هذه المقالة، ستكشف جوهر Android Automotive، وتفاعله مع أجهزة المركبة، وإمكانات نهج لتطبيق VHAL باستخدام ROS 2. من خلال دراسة حالة، تسلط المقالة الضوء على كيفية تمكن الفرق من موازاة العمل بكفاءة، وتقليل التكلفة، وتحسين جودة المنتج، مع التنقل في تحديات الترجمة المتقاطعة في منظومة Android.

مقدمة إلى أندرويد أوتوموتيف

Android Automotive هو نظام أساسي يعتمد على Android يشغل تطبيقات Android المثبتة مسبقًا لنظام الترفيه والمعلومات داخل السيارة، بالإضافة إلى تطبيقات Android الاختيارية من الأطراف الثانية والثالثة. يعمل مباشرة على الأجهزة المدمجة في السيارة ويمكنه التفاعل فعليًا مع السيارة؛ للقيام بذلك، يتطلب Android Automotive الوصول إلى تفاصيل النظام الأساسي والأجهزة الطرفية والشبكات (مثل CAN).

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

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

Diagram of Android Automotive architecture showing three app layers: system apps, OEM apps, and third-party apps. These connect through Android Framework API and Car API to Android System Services and Car Service, which interact with traditional Android HALs and the Vehicle HAL. Colour coding indicates responsibility: Android, OEM, and third party.

تنفيذ VHAL: الاتصال منخفض المستوى

لربط Car API بالسيارة الفعلية، يجب على مصنّعي المعدات الأصلية (OEMs) تنفيذ VHAL. عادةً ما يتم ذلك باستخدام لغات منخفضة المستوى مثل C أو C++ ومكتبات خاصة بالعتاد لربطها بشبكات المركبات (CAN وLIN وغيرها) أو الأجهزة الطرفية للنظام المتصلة عبر I2C أو SPI.

يجعل هذا النهج النظام مرتبطًا ارتباطًا وثيقًا بالعتاد وأقل قابلية للنقل.

android automotive vhal ros

تنفيذ VHAL: التواصل عالي المستوى

طريقة أخرى لتنفيذ VHAL تتمثل في فصله عن النظام الفيزيائي الأساسي وربط تدفق البيانات ببروتوكول اتصال عالي المستوى، مثل ROS 2 / DDS. وبهذه الطريقة، يمكن فصل التنفيذ الخاص بالعتاد إلى عقد ROS وتوفير بيانات المركبة عبر موضوعات وخدمات ROS. وسيحقق ذلك فوائد عديدة، مثل التقسيم المعياري والتواصل الموحد مع العتاد والعديد من أدوات ROS 2 للمحاكاة والاختبار وتصحيح الأخطاء وتصور البيانات!

فيما يلي مثال على عقدة VHAL التي تتواصل مع نظام OEM IVI عبر ROS Topics/Services.

android automotive vhal ros

دراسة حالة: ربط VHAL بواجهة برمجة تطبيقات السيارة في Android Automotive فوق ROS 2

هناك ثلاثة عوامل تجعل تطوير المنتج ناجحًا:

  • الوقت اللازم للوصول إلى السوق،
  • السعر
  • والجودة.

ويقودنا النهج الثاني الموصوف أعلاه إلى إمكانيات أكبر في تلك العوامل الثلاثة. لتقليل السعر وتسريع تطوير المنتج، قد ترغب الفرق في تنفيذ العمل بالتوازي. لكن لا يمكن تحقيق ذلك إلا إذا لم تكن هناك تبعيات صارمة بين أجزاء النظام. وهنا، بفضل فصل تنفيذ VHAL عن نظام OEM، يمكن لفرق التطوير البدء في العمل فوراً بالتوازي دون انتظار جاهزية نظام OEM للاستخدام والاختبار. قد لا تكون بعض أجزاء نظام OEM موجودة بعد، ولن يعيق ذلك التطوير طالما تم تعريف واجهات بيانات ROS 2 (المواضيع، الخدمات).

كما يُسهم الفصل عن نظام الشركة المصنّعة الأصلية (OEM) في تعزيز الجودة الإجمالية للمنتج، إذ يجعل النظام بأكمله أكثر قابلية للاختبار. ويمكن اختبار تطبيقات Android في مرحلة مبكرة ضمن نظام كامل من منظور التطبيق نفسه، ولكن دون الحاجة إلى تجميع كل مكوّن أساسي. ويمكن ببساطة محاكاة وحدات التحكم الإلكترونية في المركبات (ECUs) كعُقد اختبار ROS 2:

android automotive vhal ros

التحقيق

تم تنفيذ جميع عمليات التنفيذ والاختبار في هذه المقالة على ROS 2 Iron وإصدار AOSP 13.0.

كيف تُحيي المشروع؟ يجب تنفيذه بطريقة أو بأخرى. دعنا نستكشف الاحتمالات وأيها يمكن اختياره باعتباره الأنسب.

نفترض أن VHAL سيكون عقدة ROS 2. قد يفكر المرء في تنفيذ عقدة DDS فقط تتواصل عبر موضوع DDS مع نظام OEM. لكن لاحقاً، سنرى أن ROS 2 يوفر التجريد اللازم فوق بروتوكول DDS لإضافة اتصال موجه نحو الخدمات (إلى جانب مجموعة غنية من الأدوات وواجهات برمجة التطبيقات الأخرى).

الترجمة المتقاطعة لـ ROS 2

عادةً ما يأتي ROS 2 مترجمًا مسبقًا لتوزيعة Linux محددة، مثل Ubuntu، ولكن يمكن أيضًا ترجمته من المصادر. ومع ذلك، لا يبدو أن الترجمة المتقاطعة لـ ROS 2 للأنظمة غير المدعومة مهمة سهلة. وفي حالتنا، لا يتوفر دعم لنظام Android.

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

ولأن Android ليس مجرد توزيعة أخرى من GNU/Linux، فإننا لا نحتاج فقط إلى بناء ROS 2 نفسه، بل أيضًا جميع التبعيات. لا يمكننا تثبيتها ببساطة باستخدام مديري حزم النظام، على سبيل المثال باستخدام:

apt install <package>

يتميز Android أيضًا في تطوير تطبيقات المنصة الأصلية. وفي حين يمكن بناء تطبيقات المستخدم / الطرف الثالث باستخدام العديد من أنظمة البناء الخارجية، فإن كود المنصة يُبنى ويُجمّع باستخدام أدوات بناء خاصة بـ Android.

في AOSP، هناك ثلاثة أنظمة بناء:

  • نظام البناء القديم القائم على Make،
  • Soong,
  • ونظام البناء القادم القائم على Bazel.

مع الاستبدال التدريجي لنظام البناء المعتمد على Make بنظام Soong، لن يتم تناوله هنا. كما أن Bazel ليس متاحًا بالكامل بعد لنظام AOSP، لذا سنركز فقط على نظام البناء Soong.

من ناحية أخرى، يستخدم ROS 2 نظام CMake كأساس لنظام البناء، والذي يتم توسيعه بـ ament_cmake و colcon. يعتمد على حزم النظام كتبعيات لبناء قاعدة الشيفرة الخاصة به. وبما أنه يستخدم CMake، فإن توفير تعريف CMake Toolchain للترجمة المتقاطعة يجب أن يكون مباشراً إلى حد كبير. نحتاج فقط إلى استخدام سلسلة الأدوات المتقاطعة المناسبة لـ Android لهدفنا.

كيف تدمج مشروعًا خارجيًا مع Soong؟

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

على سبيل المثال، لتضمين مكتبة ثابتة خارجية، يجب على المطور تعريف وحدة بالإعدادات التالية:

package { } cc_prebuilt_library_static { name: "vendor.spyrosoft.libexample", vendor: true, export_include_dirs: [ "include/libexample" ], srcs: ["prebuilt/arm64/libexample.a"], strip: { none:true, }, }

في المكتبة الثابتة أعلاه، يقع ملف الأرشيف للمكتبة المُجمّعة مسبقًا في prebuilt/arm64/libexample.a، ، وواجهة برمجة التطبيقات العامة الخاصة به الترويسات يتم تصدير الموقع باستخدام export_include_dirs, حتى ترث الوحدات الأخرى المسار المُضمَّن تلقائيًا.

الربط الساكن أم الديناميكي؟

يدعم ROS 2 البناء بالربط الديناميكي والثابت معاً. ولأن كل مكتبة ديناميكية مبنية لـ ROS 2 تتطلب تعريف بناء Soong منفصلاً، يبدو الربط الثابت أكثر ملاءمة. ولبناء حزم ROS 2، يتطلب خيار CMake BUILD_SHARED_LIBS يجب ضبطه علىOFF. يمكن ببساطة إضافته إلى colcon كأحد وسائط CMake:

$ colcon build --cmake-args "BUILD_SHARED_LIBS=OFF" ...

من أين نحصل على سلسلة الأدوات المتقاطعة لنظام Android؟

قد يفكر المرء في استخدام NDK، الذي يدعم استخدام CMake لبناء تطبيقات أصلية. لكن هناك عقبة! نظرًا لأننا نخطط لتنفيذ خدمة منصة – VHAL، فسوف ترتبط بالمكتبات الأصلية للنظام، ولا يمكن استخدام NDK لبنائها. والسبب في ذلك هو إدخالمساحات الأسماء للمكتبات الأصلية. ونتيجة لذلك، إذا استخدمنا NDK، فإن محاولة بناء كود المنصة به من المرجّح أن تنتهي بأخطاء في الرابط. فمكتبات NDK الأصلية غير متوافقة على مستوى ABI مع مكتبات النظام الأصلية.

android automotive vhal ros

اعتبارًا من إصدار AOSP 13.0_r61، توجد سلسلة الأدوات لكود المنصة الأصلي في:

prebuilts/clang/host/linux-x86/clang-r450784d/

ويقع sysroot في:

prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/sysroot

على عكس مجموعة مترجمات GNU، حيث يكون لكل مجموعة من المضيف/الهدف مجموعتها الخاصة من الملفات الثنائية والترويسات والمكتبات وغيرها، فإن Clang/LLVM هو في الأساس مترجم متقاطع (cross-compiler)، مما يعني أن مجموعة واحدة من البرامج يمكنها الترجمة لجميع الأهداف من خلال ضبط -الهدف الخيار.

للحصول على مجموعة الخيارات الخاصة بالمنصة المستهدفة، يمكننا الاستفادة من كون AOSP لم تنتقل بالكامل إلى Soong، ولا تزال بعض الوحدات تعتمد على Make. للحفاظ على التوافق مع Make، تستخدم AOSP أداة تسمى Kati، وهو نسخة مطابقة لـ Make. يتواصل Soong مع Kati من خلال توليد Make Vars ويولّد .mk الملفات في دليل الإخراج out/soong/{Android, late, make_vars}-<product>.mk

الملف out/soong/make_vars-<product-suffix>.mk هو المكان الذي تُخزَّن فيه جميع أعلام وخيارات المترجم. نحتاج فقط إلى تحليل البيانات وإنشاء ملف سلسلة أدوات CMake. لنقم بتنفيذه بلغة Python.

لتحديد الهدف المحدد out/soong/make_vars-<product-suffix>.mk الملف، هناك حاجة إلى 'product-suffix'. لحسن الحظ، يقوم Soong بتخزينه فيout/soong/soong.variables ضمن مفتاح "Make_suffix"، على سبيل المثال،

"Make_suffix": "-aosp_rpi4",

للحصول على مسار ملف make_vars.mk، يمكننا القيام بما يلي:

def get_makefile_path(): with open('out/soong/soong.variables', 'r') as soong_vars: vars = json.load(soong_vars) make_suffix = vars['Make_suffix'] return os.path.abspath(f'out/soong/make_vars{vars['Make_suffix']}.mk')

للحصول على جميع المتغيرات كقائمة قابلة للفهرسة، يمكننا استخدام نمط تعبير نمطي بسيط نسبيًا:

def parse_makefile(file_path): variables = {} variable_assignment_regex = re.compile(r'^([a-zA-Z0-9_]+)\s*:=\s*(.*)$') with open(file_path, 'r') as makefile: for line in makefile: # Remove comments line = line.split('#')[0].strip() # Match the line against the regular expression match = variable_assignment_regex.match(line) if match: variables[match.group(1)] = match.group(2) return variables

بمجرد حصولنا على جميع المعلومات، يمكننا إنشاء ملف CMake Toolchain:

toolchain_file_content = f"""# # بدون هذا العلم لا يستطيع CMake اجتياز فحص تجميع الاختبار set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR ARM) set(CMAKE_SYSTEM_VERSION 31) set(CMAKE_SYSROOT {root_path + find_in('--sysroot ', mk_vars['SOONG_CLANG_HOST_GLOBAL_CFLAGS'])}) set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN {root_path + find_in('--gcc-toolchain=', mk_vars['SOONG_CLANG_HOST_GLOBAL_CFLAGS'])}) set(TOOLCHAIN_TRIPLE {mk_vars['SOONG_CLANG_CONFIG_arm64_TARGET_TRIPLE']}) # تحديد المترجم المتقاطع set(CMAKE_ASM_COMPILER {root_path + mk_vars['SOONG_CLANG']} CACHE STRING "") SET(CMAKE_ASM_COMPILER_TARGET ${{TOOLCHAIN_TRIPLE}}) set(CMAKE_C_COMPILER {root_path + mk_vars['SOONG_CLANG']} CACHE STRING "") set(CMAKE_C_COMPILER_TARGET ${{TOOLCHAIN_TRIPLE}}) set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN ${{CMAKE_ANDROID_STANDALONE_TOOLCHAIN}}) set(CMAKE_CXX_COMPILER {root_path + mk_vars['SOONG_CLANG_CXX']} CACHE STRING "") set(CMAKE_CXX_COMPILER_TARGET ${{TOOLCHAIN_TRIPLE}}) set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN ${{CMAKE_ANDROID_STANDALONE_TOOLCHAIN}}) # تحديد الرابط set(CMAKE_C_LINK_EXECUTABLE {root_path + mk_vars['SOONG_TARGET_LD']} CACHE STRING "") set(CMAKE_CXX_LINK_EXECUTABLE {root_path + mk_vars['SOONG_TARGET_LD']} CACHE STRING "") set(CMAKE_LINKER {root_path + mk_vars['SOONG_TARGET_LD']} CACHE STRING "") set(CMAKE_C_FLAGS_INIT "{mk_vars['SOONG_CLANG_TARGET_GLOBAL_CFLAGS']}" CACHE STRING "") set(CMAKE_CXX_FLAGS_INIT "{mk_vars['SOONG_CLANG_TARGET_GLOBAL_CPPFLAGS']}" CACHE STRING "") set(CMAKE_C_FLAGS_DEBUG "-O0 -g" CACHE INTERNAL "") set(CMAKE_C_FLAGS_RELEASE "-Os -DNDEBUG" CACHE INTERNAL "") set(CMAKE_CXX_FLAGS_DEBUG "${{CMAKE_C_FLAGS_DEBUG}}" CACHE INTERNAL "") set(CMAKE_CXX_FLAGS_RELEASE "${{CMAKE_C_FLAGS_RELEASE}}" CACHE INTERNAL "") set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES {root_path + "bionic/libc/include"} {root_path + "bionic/libc/kernel/uapi"} {root_path + "bionic/libc/kernel/android/scsi"} {root_path + "bionic/libc/kernel/android/uapi"} {root_path + "bionic/libc/kernel/uapi/asm-arm64"} {root_path + "external/libcxx/include"} ) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${{CMAKE_C_STANDARD_INCLUDE_DIRECTORIES}} ${{CMAKE_SYSROOT}}/usr/include/x86_64-linux-gnu/ {root_path + '/synergycar/aosp/external/libcxx/include'} ) add_compile_options(-fPIC) add_compile_definitions(__ANDROID_API__=31 __ANDROID__) add_link_options({mk_vars['SOONG_CLANG_TARGET_GLOBAL_LLDFLAGS']}) link_directories({root_path + "prebuilts/runtime/mainline/runtime/sdk/android/arm/lib/"}) # عدم البحث عن البرامج في أدلة مضيف البناء set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # البحث عن المكتبات والملفات الرأسية في أدلة الهدف set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) """ # كتابة ملف سلسلة أدوات CMake with open('android_toolchain.cmake', 'w') as toolchain_file: toolchain_file.write(toolchain_file_content)

بعض التفاصيل اللازمة لتعريف سلسلة أدوات CMake مدفونة أعمق قليلاً، على سبيل المثال، CMAKE_SYSROOT يجب استخراج المسار من SOONG_CLANG_HOST_GLOBAL_CFLAGS ويجب إضافة بعض الإعدادات الإضافية يدويًا، على سبيل المثال، مكتبة C الخاصة بنظام Android – Bionic تضمين الأدلة أو بعض التعريفات العامة.

للتفاصيل، يُرجى الرجوع إلى النص الكامل، الذي يمكن العثور عليه هنا.

يمكن استخدام ملف سلسلة الأدوات المُنشأ بسهولة مع colcon لبناء ROS 2:

$ colcon build --cmake-args "BUILD_SHARED_LIBS=OFF -DCMAKE_TOOLCHAIN_FILE=aosp_toolchain.cmake"

الملخص

في حين أن المقاربة النظرية للترجمة المتقاطعة لـ ROS 2 لنظام Android واعدة، فإن التطبيق العملي قد يطرح تحديات معينة، لا سيما عند ترجمة جميع الاعتماديات المطلوبة. وبالطبع، هناك العديد من المسارات المحتملة التي يمكن للباحثين والمهندسين سلوكها لتحقيق التوافق الكامل والوظائف الكاملة.

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

ابدأ مشروع الروبوتات التالي الخاص بك مع Spyrosoft

هل تبحث عن شركة يمكنك أن تأتمنها على منتجك؟ هنا يمكنك معرفة المزيد عن نطاقخدمات الروبوتات الاحترافيةوكيف نُحوّل الأفكار إلى واقع.

تُعد طبقة تجريد المركبة (VHAL) جسراً حاسماً بين نظام تشغيل Android Automotive والعتاد المادي للمركبة. وهي تُعرّف مجموعة موحّدة من الخصائص التي يمكن لمصنّعي المعدات الأصلية (OEMs) تنفيذها للتحكم في وظائف محددة بالسيارة، مثل التدفئة والتهوية وتكييف الهواء (HVAC)، أو أقفال الأبواب، أو إعدادات المقاعد. ومن خلال تجريد هذه التفاصيل الخاصة بالعتاد، تتيح VHAL لتطبيقات Android التفاعل بسلاسة مع الشبكات الأساسية للمركبة، مثل شبكة منطقة المتحكم (CAN) أو شبكة الربط المحلية (LIN)، عبر واجهة Car API.

تقليدياً، تنفذ شركات تصنيع المعدات الأصلية (OEMs) طبقة VHAL باستخدام لغات برمجة منخفضة المستوى مثل C أو C++، مما يربط النظام ارتباطاً وثيقاً بعتاد محدد ويقلل من قابلية النقل. في المقابل، فإن التنفيذ عالي المستوى باستخدام نظام تشغيل الروبوت 2 (ROS 2) أو خدمة توزيع البيانات (DDS) يفصل VHAL عن النظام المادي. في هذا النهج، تُفصل الوظائف الخاصة بالعتاد إلى عقد ROS، وتُنقل بيانات المركبة عبر مواضيع وخدمات ROS. تعمل هذه الوحدات على توحيد الاتصال وتزويد المطورين بأدوات قوية للمحاكاة والاختبار وتصور البيانات.

يؤدي فصل VHAL عن نظام الشركة المصنّعة (OEM) باستخدام ROS 2 إلى تسريع تطوير المنتج بشكل كبير وتحسين الجودة الإجمالية. فهو يمكّن فرق الهندسة من موازاة سير عملها؛ حيث يمكن للمطورين البدء في بناء واختبار تطبيقات Android فورًا، دون انتظار تجميع أجهزة OEM الفعلية بالكامل. علاوة على ذلك، يعزز هذا النهج قابلية الاختبار. يمكن بسهولة محاكاة وحدات التحكم الإلكترونية للمركبة (ECUs) كعقد اختبار ROS 2، مما يتيح اختبارًا شاملًا للنظام في مرحلة مبكرة من دورة حياة التطوير، وهو ما يقلل في النهاية من التكاليف ووقت الوصول إلى السوق.

يمثل الترجمة المتقاطعة لـ ROS 2 لنظام Android Automotive تحديات مميزة لأن Android ليس توزيعة GNU/Linux قياسية. لا يمكن للمطورين ببساطة استخدام مديري الحزم النظامية لتثبيت التبعيات. علاوة على ذلك، يعتمد كود منصة Android على أنظمة بناء محددة، وأبرزها Soong، بدلاً من نظام CMake المستخدم في ROS 2. ولدمج ROS 2 بنجاح، يجب على المهندسين إنشاء ملف سلسلة أدوات CMake مخصص يقوم بتحليل أعلام المترجم من بيئة بناء مشروع Android مفتوح المصدر (AOSP). بالإضافة إلى ذلك، ونظراً لقيود مساحة الأسماء للمكتبات الأصلية، يُفضّل عموماً الربط الساكن على الربط الديناميكي لتجنب أخطاء عدم توافق ABI.

نعم، تمثل micro-ROS بديلاً عالي الجدوى لدمج أطر الروبوتات مع الأنظمة غير المدعومة أو محدودة الموارد. وفي حين أن الترجمة المتقاطعة لإطار ROS 2 القياسي لنظام Android ممكنة، إلا أنها تتطلب حلولاً بديلة معقدة فيما يتعلق بالاعتماديات وأنظمة البناء. تقدم micro-ROS نهجًا أكثر تخصيصًا وأناقة مصممًا خصيصًا لوحدات التحكم الدقيقة والأنظمة المدمجة. فهي تبسط عملية الترجمة المتقاطعة عبر منصات مختلفة، مما يجعلها مرشحًا ممتازًا لتطبيقات Android Automotive VHAL المستقبلية.