فروشنده APEX

شما می‌توانید از فرمت فایل APEX برای بسته‌بندی و نصب ماژول‌های سطح پایین‌تر سیستم عامل اندروید استفاده کنید. این فرمت امکان ساخت و نصب مستقل اجزایی مانند سرویس‌ها و کتابخانه‌های بومی، پیاده‌سازی‌های HAL، میان‌افزار، فایل‌های پیکربندی و غیره را فراهم می‌کند.

APEX های Vendor توسط سیستم ساخت به طور خودکار در پارتیشن /vendor نصب می‌شوند و در زمان اجرا توسط apexd درست مانند APEX های موجود در پارتیشن‌های دیگر فعال می‌شوند.

موارد استفاده

ماژولارسازی تصاویر فروشندگان

APEXها، بسته‌بندی و ماژولارسازی طبیعی پیاده‌سازی ویژگی‌ها روی تصاویر فروشندگان را تسهیل می‌کنند.

وقتی تصاویر فروشنده به عنوان ترکیبی از APEX های مستقل ساخته می‌شوند، تولیدکنندگان دستگاه می‌توانند به راحتی پیاده‌سازی‌های خاص فروشنده مورد نظر خود را روی دستگاهشان انتخاب کنند. تولیدکنندگان حتی می‌توانند یک APEX فروشنده جدید ایجاد کنند اگر هیچ یک از APEX های ارائه شده با نیاز آنها مطابقت نداشته باشد، یا یک سخت‌افزار سفارشی کاملاً جدید داشته باشند.

برای مثال، یک تولیدکننده اصلی تجهیزات (OEM) ممکن است تصمیم بگیرد که دستگاه خود را با پیاده‌سازی وای‌فای AOSP با نام APEX، پیاده‌سازی بلوتوث SoC با نام APEX و یک پیاده‌سازی تلفنی سفارشی تولیدکننده اصلی با نام APEX بسازد.

بدون APEX های فروشنده، یک پیاده‌سازی با وابستگی‌های بسیار زیاد بین اجزای فروشنده، نیاز به هماهنگی و ردیابی دقیق دارد. با قرار دادن تمام اجزا (از جمله فایل‌های پیکربندی و کتابخانه‌های اضافی) در APEX ها با رابط‌های کاملاً تعریف شده در هر نقطه از ارتباط بین ویژگی‌ها، اجزای مختلف قابل تعویض می‌شوند.

تکرار توسعه‌دهنده

APEX های فروشنده با بسته بندی کل پیاده سازی یک ویژگی، مانند wifi HAL، در داخل APEX فروشنده، به توسعه دهندگان کمک می کنند تا هنگام توسعه ماژول های فروشنده، سریعتر تکرار کنند. سپس توسعه دهندگان می توانند APEX فروشنده را بسازند و به صورت جداگانه برای آزمایش تغییرات فشار دهند، به جای اینکه کل تصویر فروشنده را دوباره بسازند.

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

بسته‌بندی طبیعی یک ناحیه ویژگی در APEX، فرآیند ساخت، اعمال و آزمایش تغییرات برای آن ناحیه ویژگی را نیز ساده می‌کند. به عنوان مثال، نصب مجدد APEX به طور خودکار هر کتابخانه یا فایل‌های پیکربندی بسته‌بندی شده‌ای را که APEX شامل می‌شود، به‌روزرسانی می‌کند.

ادغام یک بخش ویژه در APEX، اشکال‌زدایی یا بازگشت به حالت اولیه را در صورت مشاهده رفتار نامناسب دستگاه نیز ساده می‌کند. برای مثال، اگر تلفن در یک نسخه جدید به خوبی کار نمی‌کند، توسعه‌دهندگان می‌توانند یک پیاده‌سازی تلفن قدیمی‌تر APEX را روی دستگاه نصب کنند (بدون نیاز به فلش کردن یک نسخه کامل) و ببینند که آیا رفتار خوب بازیابی می‌شود یا خیر.

نمونه گردش کار:

# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w

# Test the device.
... testing ...

# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...

# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...

مثال‌ها

مبانی

برای اطلاعات عمومی APEX، از جمله الزامات دستگاه، جزئیات فرمت فایل و مراحل نصب، به صفحه اصلی فرمت فایل APEX مراجعه کنید.

در Android.bp ، تنظیم vendor: true یک ماژول APEX را به APEX فروشنده تبدیل می‌کند.

apex {
  ..
  vendor: true,
  ..
}

فایل‌های باینری و کتابخانه‌های اشتراکی

یک APEX شامل وابستگی‌های انتقالی درون بار داده APEX است، مگر اینکه رابط‌های پایداری داشته باشند.

رابط‌های بومی پایدار برای وابستگی‌های APEX فروشندگان شامل cc_library با کتابخانه‌های stubs و LLNDK است. این وابستگی‌ها از بسته‌بندی حذف می‌شوند و وابستگی‌ها در مانیفست APEX ثبت می‌شوند. مانیفست توسط linkerconfig پردازش می‌شود تا وابستگی‌های بومی خارجی در زمان اجرا در دسترس باشند.

در قطعه کد زیر، APEX شامل هر دو فایل باینری ( my_service ) و وابستگی‌های ناپایدار آن (فایل‌های *.so ) است.

apex {
  ..
  vendor: true,
  binaries: ["my_service"],
  ..
}

در قطعه کد زیر، APEX شامل کتابخانه اشتراکی my_standalone_lib و هرگونه وابستگی ناپایدار آن (مطابق توضیحات بالا) است.

apex {
  ..
  vendor: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

APEX را کوچکتر کنید

APEX ممکن است بزرگتر شود زیرا وابستگی‌های ناپایدار را در خود جای می‌دهد. ما استفاده از پیوند استاتیک را توصیه می‌کنیم. کتابخانه‌های رایج مانند libc++.so و libbase.so می‌توانند به صورت استاتیک به فایل‌های باینری HAL پیوند داده شوند. ایجاد یک وابستگی برای ارائه یک رابط پایدار می‌تواند گزینه دیگری باشد. این وابستگی در APEX بسته‌بندی نخواهد شد.

پیاده‌سازی‌های HAL

برای تعریف پیاده‌سازی HAL، فایل‌های باینری و کتابخانه‌های مربوطه را درون یک APEX فروشنده، مشابه مثال‌های زیر، ارائه دهید:

برای کپسوله‌سازی کامل پیاده‌سازی HAL، APEX باید هرگونه قطعه VINTF و اسکریپت‌های init مربوطه را نیز مشخص کند.

قطعات VINTF

قطعات VINTF می‌توانند از یک APEX فروشنده، زمانی که قطعات در etc/vintf مربوط به APEX قرار دارند، ارائه شوند.

از ویژگی prebuilts برای جاسازی قطعات VINTF در APEX استفاده کنید.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

API های پرس و جو

وقتی قطعات VINTF به APEX اضافه می‌شوند، از APIهای libbinder_ndk برای دریافت نگاشت‌های رابط‌های HAL و نام‌های APEX استفاده کنید.

  • AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default") : اگر نمونه HAL در APEX تعریف شده باشد، true .
  • AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...) : نام APEX را که نمونه HAL را تعریف می‌کند، برمی‌گرداند.
  • AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...) : از این برای باز کردن یک HAL عبوری استفاده کنید.

اسکریپت‌های اولیه

APEXها می‌توانند اسکریپت‌های init را به دو روش شامل شوند: (الف) یک فایل متنی از پیش ساخته شده در داخل payload APEX، یا (ب) یک اسکریپت init معمولی در /vendor/etc . می‌توانید هر دو را برای یک APEX تنظیم کنید.

اسکریپت Init در APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

اسکریپت‌های Init در APEXهای فروشنده می‌توانند تعاریف service و دستورالعمل‌های on <property or event> داشته باشند.

مطمئن شوید که تعریف service به یک فایل باینری در همان APEX اشاره می‌کند. برای مثال، com.android.foo APEX ممکن است سرویسی با نام foo-service تعریف کند.

on foo-service /apex/com.android.foo/bin/foo
  ...

هنگام استفاده از دستورالعمل‌های on مراقب باشید. از آنجایی که اسکریپت‌های init در APEXها پس از فعال شدن APEXها تجزیه و اجرا می‌شوند، برخی از رویدادها یا ویژگی‌ها قابل استفاده نیستند. برای اجرای اقدامات در اسرع وقت apex.all.ready=true استفاده کنید. APEXهای Bootstrap می‌توانند on init استفاده کنند، اما نمی‌توانند on early-init استفاده کنند.

میان‌افزار

مثال:

سیستم عامل را در APEX فروشنده با نوع ماژول prebuilt_firmware به شرح زیر جاسازی کنید.

prebuilt_firmware {
  name: "my.bin",
  src: "path_to_prebuilt_firmware",
  vendor: true,
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.bin"],  // installed inside APEX as /etc/firmware/my.bin
  ..
}

ماژول‌های prebuilt_firmware در دایرکتوری <apex name>/etc/firmware مربوط به APEX نصب می‌شوند. ueventd دایرکتوری‌های /apex/*/etc/firmware را برای یافتن ماژول‌های فریمور اسکن می‌کند.

file_contexts APEX باید هر ورودی payload فریمور را به درستی برچسب گذاری کنند تا اطمینان حاصل شود که این فایل ها توسط ueventd در زمان اجرا قابل دسترسی هستند. معمولاً برچسب vendor_file کافی است. برای مثال:

(/.*)? u:object_r:vendor_file:s0

ماژول‌های هسته

ماژول‌های هسته را به صورت ماژول‌های از پیش ساخته شده، به شرح زیر در APEX فروشنده جاسازی کنید.

prebuilt_etc {
  name: "my.ko",
  src: "my.ko",
  vendor: true,
  sub_dir: "modules"
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.ko"],  // installed inside APEX as /etc/modules/my.ko
  ..
}

file_contexts مربوط به APEX باید هر ورودی payload ماژول هسته را به درستی برچسب گذاری کند. برای مثال:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

ماژول‌های هسته باید به صورت صریح نصب شوند. مثال زیر از اسکریپت init در پارتیشن vendor، نصب از طریق insmod را نشان می‌دهد:

my_init.rc :

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

همپوشانی منابع زمان اجرا

مثال:

با استفاده از ویژگی rros همپوشانی‌های منابع زمان اجرا را در APEX فروشنده جاسازی کنید.

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

سایر فایل‌های پیکربندی

APEX های فروشنده از فایل‌های پیکربندی مختلف دیگری که معمولاً در پارتیشن فروشنده به عنوان فایل‌های از پیش ساخته شده درون APEX های فروشنده یافت می‌شوند، پشتیبانی می‌کنند و موارد بیشتری نیز در حال اضافه شدن هستند.

مثال‌ها:

APEX های فروشنده بوت استرپ

برخی از سرویس‌های HAL مانند keymint باید قبل از فعال شدن APEXها در دسترس باشند. این HALها معمولاً در تعریف سرویس خود در اسکریپت init early_hal تنظیم می‌کنند. مثال دیگر کلاس animation است که معمولاً زودتر از رویداد post-fs-data شروع می‌شود. وقتی چنین سرویس HAL اولیه‌ای در APEX فروشنده بسته‌بندی می‌شود، در مانیفست APEX آن، مقدار "vendorBootstrap": true را برای apex تنظیم کنید تا بتواند زودتر فعال شود. توجه داشته باشید که APEXهای bootstrap فقط از مکان از پیش ساخته شده مانند /vendor/apex قابل فعال شدن هستند، نه از /data/apex .

ویژگی‌های سیستم

اینها ویژگی‌های سیستمی هستند که چارچوب برای پشتیبانی از APEXهای فروشندگان می‌خواند:

  • input_device.config_file.apex=<apex name> - وقتی تنظیم شود، فایل‌های پیکربندی ورودی ( *.idc ، *.kl و *.kcm ) از دایرکتوری /etc/usr مربوط به APEX جستجو می‌شوند.
  • ro.vulkan.apex=<apex name> - وقتی تنظیم شود، درایور Vulkan از APEX بارگذاری می‌شود. از آنجایی که درایور Vulkan توسط HAL های اولیه استفاده می‌شود، APEX Bootstrap APEX را فعال کنید و فضای نام لینکر را قابل مشاهده پیکربندی کنید.

با استفاده از دستور setprop ویژگی‌های سیستم را در اسکریپت‌های init تنظیم کنید.

ویژگی‌های اضافی

انتخاب APEX در هنگام بوت شدن سیستم

مثال:

APEX های Vendor می‌توانند به صورت اختیاری در هنگام بوت فعال شوند. اگر نام فایلی را با استفاده از ویژگی سیستم ro.vendor.apex.<apex name> مشخص کنید، فقط APEX مطابق با نام فایل برای <apex name> خاص فعال می‌شود. APEX با <apex name> اگر این ویژگی سیستم روی none تنظیم شده باشد، نادیده گرفته می‌شود (فعال نمی‌شود). می‌توانید از این ویژگی برای نصب چندین نسخه از APEX با نام یکسان استفاده کنید. اگر چندین نسخه از یک APEX وجود دارد، باید کلید یکسانی را به اشتراک بگذارند.

موارد استفاده مثال:

  • نصب ۳ نسخه از APEX فروشنده wifi HAL: تیم‌های تضمین کیفیت می‌توانند تست دستی یا خودکار را با استفاده از یک نسخه اجرا کنند، سپس سیستم را به نسخه دیگری ریبوت کرده و تست‌ها را دوباره اجرا کنند، سپس نتایج نهایی را مقایسه کنند.
  • دو نسخه از دوربین APEX فروشنده HAL، فعلی و آزمایشی را نصب کنید: علاقه‌مندان به Dogfood می‌توانند بدون دانلود و نصب فایل اضافی از نسخه آزمایشی استفاده کنند، بنابراین می‌توانند به راحتی به نسخه قبلی خود بازگردند.

در طول بوت شدن، apexd به دنبال sysprops با فرمت خاص می‌گردد تا نسخه APEX مناسب را فعال کند.

قالب‌های مورد انتظار برای کلید ویژگی عبارتند از:

  • بوت‌کانفیگ
    • برای تنظیم مقدار پیش‌فرض، در BoardConfig.mk استفاده می‌شود.
    • androidboot.vendor.apex.<apex name>
  • sysprop پایدار
    • برای تغییر مقدار پیش‌فرض، که روی یک دستگاه از قبل بوت شده تنظیم شده است، استفاده می‌شود.
    • در صورت وجود، مقدار bootconfig را لغو می‌کند.
    • persist.vendor.apex.<apex name>

مقدار این ویژگی باید نام فایل APEX باشد که باید فعال شود، یا برای غیرفعال کردن APEX، none وارد کنید.

// Default version.
apex {
  name: "com.oem.camera.hal.my_apex_default",
  vendor: true,
  ..
}

// Non-default version.
apex {
  name: "com.oem.camera.hal.my_apex_experimental",
  vendor: true,
  ..
}

نسخه پیش‌فرض همچنین باید با استفاده از bootconfig در BoardConfig.mk پیکربندی شود:

# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
    androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default

پس از بوت شدن دستگاه، با تنظیم persistent sysprop نسخه فعال شده را تغییر دهید:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

اگر دستگاه از به‌روزرسانی bootconfig پس از فلش کردن پشتیبانی می‌کند (مثلاً از طریق دستورات fastboot oem )، تغییر ویژگی bootconfig برای APEX چند نصبه، نسخه فعال شده در هنگام بوت را نیز تغییر می‌دهد.

برای دستگاه‌های مرجع مجازی مبتنی بر Cuttlefish ، می‌توانید از دستور --extra_bootconfig_args برای تنظیم مستقیم ویژگی bootconfig هنگام راه‌اندازی استفاده کنید. به عنوان مثال:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";