فرمت فایل APEX

فرمت کانتینر Android Pony EXpress (APEX) در اندروید 10 معرفی شد و در جریان نصب ماژول‌های سیستم سطح پایین استفاده می‌شود. این فرمت به‌روزرسانی اجزای سیستم را که با مدل استاندارد برنامه Android مطابقت ندارند، تسهیل می‌کند. برخی از مؤلفه‌های نمونه عبارتند از خدمات و کتابخانه‌های بومی، لایه‌های انتزاعی سخت‌افزار ( HALs )، زمان اجرا ( ART )، و کتابخانه‌های کلاس.

اصطلاح "APEX" همچنین می تواند به یک فایل APEX اشاره داشته باشد.

زمینه

اگرچه Android از به‌روزرسانی‌های ماژول‌هایی که در مدل استاندارد برنامه (مثلاً خدمات، فعالیت‌ها) قرار می‌گیرند، از طریق برنامه‌های نصب کننده بسته (مانند برنامه Google Play Store) پشتیبانی می‌کند، استفاده از یک مدل مشابه برای اجزای سیستم‌عامل سطح پایین‌تر دارای اشکالات زیر است:

  • ماژول های مبتنی بر APK را نمی توان در مراحل اولیه راه اندازی استفاده کرد. Package Manager مخزن مرکزی اطلاعات مربوط به برنامه‌ها است و فقط می‌تواند از مدیر فعالیت شروع شود که در مراحل بعدی فرآیند بوت آماده می‌شود.
  • فرمت APK (به ویژه مانیفست) برای برنامه های اندروید طراحی شده است و ماژول های سیستم همیشه مناسب نیستند.

طرح

این بخش طراحی سطح بالای فرمت فایل APEX و مدیر APEX را که سرویسی است که فایل های APEX را مدیریت می کند، توضیح می دهد.

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

فرمت APEX

این فرمت یک فایل APEX است.

فرمت فایل APEX

شکل 1. فرمت فایل APEX

در سطح بالا، یک فایل APEX یک فایل فشرده است که در آن فایل ها به صورت فشرده و در محدوده 4 کیلوبایت ذخیره می شوند.

چهار فایل موجود در یک فایل APEX عبارتند از:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

فایل apex_manifest.json حاوی نام و نسخه بسته است که یک فایل APEX را مشخص می کند. این یک بافر پروتکل ApexManifest در قالب JSON است.

فایل AndroidManifest.xml به فایل APEX اجازه می دهد تا از ابزارها و زیرساخت های مرتبط با APK مانند ADB، PackageManager و برنامه های نصب کننده بسته (مانند Play Store) استفاده کند. به عنوان مثال، فایل APEX می‌تواند از یک ابزار موجود مانند aapt برای بازرسی ابرداده اصلی فایل استفاده کند. فایل حاوی نام بسته و اطلاعات نسخه است. این اطلاعات عموماً در apex_manifest.json نیز موجود است.

apex_manifest.json روی AndroidManifest.xml برای کدها و سیستم‌هایی که با APEX سروکار دارند توصیه می‌شود. AndroidManifest.xml ممکن است حاوی اطلاعات هدف‌گیری اضافی باشد که می‌تواند توسط ابزارهای انتشار برنامه موجود استفاده شود.

apex_payload.img یک تصویر سیستم فایل ext4 است که توسط dm-verity پشتیبانی می شود. تصویر در زمان اجرا از طریق یک دستگاه Loopback نصب می شود. به طور خاص، درخت هش و بلوک ابرداده با استفاده از کتابخانه libavb ایجاد می شوند. بار سیستم فایل تجزیه نشده است (زیرا تصویر باید در جای خود قابل نصب باشد). فایل های معمولی در داخل فایل apex_payload.img گنجانده شده است.

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

دستورالعمل های نامگذاری APEX

برای کمک به جلوگیری از تداخل نام‌گذاری بین APEXهای جدید با پیشرفت پلتفرم، از دستورالعمل‌های نام‌گذاری زیر استفاده کنید:

  • com.android.*
    • برای AOSP APEX رزرو شده است. منحصر به هیچ شرکت یا دستگاهی نیست.
  • com.<companyname>.*
    • برای یک شرکت رزرو شده است. به طور بالقوه توسط چندین دستگاه از آن شرکت استفاده می شود.
  • com.<companyname>.<devicename>.*
    • برای APEX های منحصر به فرد یک دستگاه خاص (یا زیر مجموعه ای از دستگاه ها) رزرو شده است.

مدیر APEX

مدیر APEX (یا apexd ) یک فرآیند بومی مستقل است که مسئول تأیید، نصب و حذف فایل‌های APEX است. این فرآیند راه اندازی شده و در اوایل توالی بوت آماده است. فایل‌های APEX معمولاً در دستگاه /system/apex از قبل نصب می‌شوند. اگر به‌روزرسانی در دسترس نباشد، مدیر APEX به‌طور پیش‌فرض از این بسته‌ها استفاده می‌کند.

توالی به روز رسانی یک APEX از کلاس PackageManager استفاده می کند و به شرح زیر است.

  1. یک فایل APEX از طریق یک برنامه نصب کننده بسته، ADB یا منبع دیگر دانلود می شود.
  2. مدیر بسته مراحل نصب را شروع می کند. پس از تشخیص این که فایل یک APEX است، مدیر بسته کنترل را به مدیر APEX منتقل می کند.
  3. مدیر APEX فایل APEX را تأیید می کند.
  4. اگر فایل APEX تأیید شود، پایگاه داده داخلی مدیر APEX به روز می شود تا نشان دهد که فایل APEX در بوت بعدی فعال می شود.
  5. درخواست کننده نصب پس از تأیید موفقیت آمیز بسته، یک پخش را دریافت می کند.
  6. برای ادامه نصب، سیستم باید راه اندازی مجدد شود.
  7. در راه‌اندازی بعدی، مدیر APEX شروع به کار می‌کند، پایگاه داده داخلی را می‌خواند و برای هر فایل APEX فهرست‌شده کارهای زیر را انجام می‌دهد:

    1. فایل APEX را تأیید می کند.
    2. یک دستگاه Loopback از فایل APEX ایجاد می کند.
    3. یک دستگاه بلوک نقشه‌بردار دستگاه در بالای دستگاه حلقه بک ایجاد می‌کند.
    4. دستگاه بلوک نقشه‌بردار دستگاه را روی یک مسیر منحصربه‌فرد نصب می‌کند (به عنوان مثال /apex/ name @ ver ).

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

فایل های APEX فایل های APK هستند

فایل‌های APEX فایل‌های APK معتبر هستند زیرا بایگانی‌های فشرده امضا شده (با استفاده از طرح امضای APK) حاوی فایل AndroidManifest.xml هستند. این به فایل‌های APEX اجازه می‌دهد از زیرساخت فایل‌های APK مانند برنامه نصب بسته، ابزار امضا و مدیر بسته استفاده کنند.

فایل AndroidManifest.xml داخل یک فایل APEX بسیار کم است و شامل name بسته، versionCode ، و targetSdkVersion اختیاری، minSdkVersion و maxSdkVersion برای هدف‌یابی دقیق است. این اطلاعات به فایل های APEX اجازه می دهد تا از طریق کانال های موجود مانند برنامه های نصب بسته و ADB تحویل داده شوند.

انواع فایل پشتیبانی می شود

فرمت APEX این نوع فایل ها را پشتیبانی می کند:

  • لیب های مشترک بومی
  • فایل های اجرایی بومی
  • فایل های JAR
  • فایل های داده
  • فایل های پیکربندی

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

گزینه های امضا

فایل های APEX به دو صورت امضا می شوند. ابتدا فایل apex_payload.img (مخصوصاً توصیفگر vbmeta که به apex_payload.img ضمیمه شده است) با یک کلید امضا می شود. سپس، کل APEX با استفاده از طرح امضای APK v3 امضا می شود. در این فرآیند از دو کلید مختلف استفاده می شود.

در سمت دستگاه، یک کلید عمومی مربوط به کلید خصوصی مورد استفاده برای امضای توصیفگر vbmeta نصب شده است. مدیر APEX از کلید عمومی برای تأیید APEXهایی که درخواست نصب شده اند استفاده می کند. هر APEX باید با کلیدهای مختلف امضا شود و هم در زمان ساخت و هم در زمان اجرا اجرا می شود.

APEX در پارتیشن های داخلی

فایل های APEX را می توان در پارتیشن های داخلی مانند /system قرار داد. پارتیشن در حال حاضر بیش از dm-verity است، بنابراین فایل‌های APEX مستقیماً روی دستگاه Loopback نصب می‌شوند.

اگر یک APEX در یک پارتیشن داخلی وجود داشته باشد، APEX را می توان با ارائه یک بسته APEX با همان نام بسته و بزرگتر یا مساوی کد نسخه به روز کرد. APEX جدید در /data ذخیره می‌شود و مانند APK‌ها، نسخه تازه نصب‌شده، نسخه‌ای را که از قبل در پارتیشن داخلی وجود دارد، سایه می‌اندازد. اما برخلاف APK ها، نسخه تازه نصب شده APEX تنها پس از راه اندازی مجدد فعال می شود.

الزامات هسته

برای پشتیبانی از ماژول‌های خط اصلی APEX در دستگاه Android، ویژگی‌های هسته لینوکس زیر مورد نیاز است: درایور حلقه بک و dm-verity. درایور Loopback تصویر سیستم فایل را در یک ماژول APEX نصب می کند و dm-verity ماژول APEX را تأیید می کند.

عملکرد درایور حلقه بک و dm-verity در دستیابی به عملکرد خوب سیستم هنگام استفاده از ماژول های APEX مهم است.

نسخه های هسته پشتیبانی شده

ماژول های خط اصلی APEX در دستگاه هایی با استفاده از نسخه هسته 4.4 یا بالاتر پشتیبانی می شوند. دستگاه‌های جدیدی که با Android 10 یا بالاتر راه‌اندازی می‌شوند باید از هسته نسخه 4.9 یا بالاتر برای پشتیبانی از ماژول‌های APEX استفاده کنند.

وصله های هسته مورد نیاز

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

نسخه کرنل 4.4

این نسخه فقط برای دستگاه هایی پشتیبانی می شود که از اندروید 9 به اندروید 10 ارتقا یافته اند و می خواهند از ماژول های APEX پشتیبانی کنند. برای دریافت وصله های مورد نیاز، ادغام کردن از شاخه android-4.4 به شدت توصیه می شود. در زیر لیستی از وصله های فردی مورد نیاز برای هسته نسخه 4.4 آمده است.

  • UPSTREAM: حلقه: اضافه کردن ioctl برای تغییر اندازه بلوک منطقی ( 4.4 )
  • BACKPORT: بلوک/حلقه: تنظیم hw_sectors ( 4.4 )
  • UPSTREAM: حلقه: اضافه کردن LOOP_SET_BLOCK_SIZE در compat ioctl ( 4.4 )
  • ANDROID: mnt: رفع next_descendent ( 4.4 )
  • ANDROID: mnt: remount باید در Slaves of Slaves منتشر شود ( 4.4 )
  • ANDROID: mnt: نصب مجدد را به درستی منتشر کنید ( 4.4 )
  • برگرداندن "ANDROID: dm verity: اضافه کردن حداقل اندازه واکشی اولیه" ( 4.4 )
  • UPSTREAM: حلقه: در صورت تغییر offset یا block_size، حافظه های پنهان را رها کنید ( 4.4 )

نسخه های هسته 4.9/4.14/4.19

برای دریافت وصله های مورد نیاز برای نسخه های هسته 4.9/4.14/4.19، از شاخه android-common به پایین ادغام شوید.

گزینه های پیکربندی هسته مورد نیاز

لیست زیر الزامات پیکربندی پایه برای پشتیبانی از ماژول های APEX را که در اندروید 10 معرفی شده اند نشان می دهد. موارد دارای ستاره (*) نیازمندی های موجود از اندروید 9 و پایین تر هستند.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

الزامات پارامتر خط فرمان هسته

برای پشتیبانی از APEX، اطمینان حاصل کنید که پارامترهای خط فرمان هسته شرایط زیر را برآورده می کنند:

  • loop.max_loop نباید تنظیم شود
  • loop.max_part باید <= 8 باشد

یک APEX بسازید

در این بخش نحوه ساخت APEX با استفاده از سیستم ساخت اندروید توضیح داده شده است. در زیر نمونه ای از Android.bp برای APEX به نام apex.test آمده است.

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

مثال apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

file_contexts مثال:

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

انواع فایل ها و مکان ها در APEX

نوع فایل مکان در APEX
کتابخانه های مشترک /lib و /lib64 ( /lib/arm برای بازوی ترجمه شده در x86)
اجرایی ها /bin
کتابخانه های جاوا /javalib
از پیش ساخته شده است /etc

وابستگی های گذرا

فایل‌های APEX به‌طور خودکار شامل وابستگی‌های انتقالی لیب‌های به اشتراک‌گذاشته‌شده یا فایل‌های اجرایی می‌شوند. به عنوان مثال، اگر libFoo به libBar بستگی دارد، زمانی که فقط libFoo در ویژگی native_shared_libs فهرست شده باشد، دو lib اضافه می‌شوند.

چندین ABI را مدیریت کنید

ویژگی native_shared_libs را برای رابط‌های باینری برنامه اولیه و ثانویه (ABI) دستگاه نصب کنید. اگر یک APEX دستگاه هایی با یک ABI منفرد (یعنی فقط 32 بیت یا فقط 64 بیت) را هدف قرار دهد، فقط کتابخانه هایی با ABI مربوطه نصب می شوند.

ویژگی binaries را فقط برای ABI اولیه دستگاه نصب کنید که در زیر توضیح داده شده است:

  • اگر دستگاه فقط 32 بیتی باشد، فقط نوع 32 بیتی باینری نصب شده است.
  • اگر دستگاه فقط 64 بیتی باشد، فقط نوع 64 بیتی باینری نصب شده است.

برای افزودن کنترل دقیق بر روی ABIهای کتابخانه‌های بومی و باینری‌ها، از ویژگی‌های multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] استفاده کنید.

  • first : با ABI اولیه دستگاه مطابقت دارد. این پیش فرض برای باینری ها است.
  • lib32 : در صورت پشتیبانی با ABI 32 بیتی دستگاه مطابقت دارد.
  • lib64 : با ABI 64 بیتی دستگاه که پشتیبانی می کند مطابقت دارد.
  • prefer32 : در صورت پشتیبانی با ABI 32 بیتی دستگاه مطابقت دارد. اگر ABI 32 بیتی پشتیبانی نمی شود، با ABI 64 بیتی مطابقت دارد.
  • both : با هر دو ABI مطابقت دارد. این پیش فرض برای native_shared_libraries است.

ویژگی‌های java ، libraries و prebuilts ABI-agnostic هستند.

این مثال برای دستگاهی است که از 32/64 پشتیبانی می کند و 32 را ترجیح نمی دهد:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

امضای vbmeta

هر APEX را با کلیدهای مختلف امضا کنید. هنگامی که یک کلید جدید مورد نیاز است، یک جفت کلید عمومی-خصوصی ایجاد کنید و یک ماژول apex_key بسازید. از ویژگی key برای امضای APEX با استفاده از کلید استفاده کنید. کلید عمومی به طور خودکار در APEX با نام avb_pubkey قرار می گیرد.

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

در مثال بالا، نام کلید عمومی ( foo ) به شناسه کلید تبدیل می شود. شناسه کلید مورد استفاده برای امضای APEX در APEX نوشته شده است. در زمان اجرا، apexd APEX را با استفاده از یک کلید عمومی با همان شناسه در دستگاه تأیید می کند.

امضای APEX

APEX ها را به همان روشی که APK ها را امضا می کنید، امضا کنید. دوبار APEX را امضا کنید. یک بار برای سیستم فایل کوچک (فایل apex_payload.img ) و یک بار برای کل فایل.

برای امضای APEX در سطح فایل، ویژگی certificate را به یکی از این سه روش تنظیم کنید:

  • تنظیم نشده: اگر مقداری تنظیم نشده باشد، APEX با گواهی واقع در PRODUCT_DEFAULT_DEV_CERTIFICATE امضا می شود. اگر هیچ پرچمی تنظیم نشده باشد، مسیر پیش‌فرض build/target/product/security/testkey است.
  • <name> : APEX با گواهی <name> در فهرستی مشابه PRODUCT_DEFAULT_DEV_CERTIFICATE امضا شده است.
  • :<name> : APEX با گواهی امضا شده است که توسط ماژول Soong به نام <name> تعریف شده است. ماژول گواهی را می توان به صورت زیر تعریف کرد.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

یک APEX نصب کنید

برای نصب APEX، از ADB استفاده کنید.

adb install apex_file_name
adb reboot

اگر supportsRebootlessUpdate در apex_manifest.json روی true تنظیم شده باشد و APEX فعلی نصب شده استفاده نشده باشد (به عنوان مثال، هر سرویسی که در آن وجود دارد متوقف شده است)، می توان یک APEX جدید بدون راه اندازی مجدد با پرچم --force-non-staged نصب کرد. .

adb install --force-non-staged apex_file_name

از APEX استفاده کنید

پس از راه اندازی مجدد، APEX در پوشه /apex/<apex_name>@<version> نصب می شود. چندین نسخه از یک APEX را می توان به طور همزمان نصب کرد. در بین مسیرهای mount، مسیری که مطابق با آخرین نسخه است در /apex/<apex_name> به صورت bind-mount شده است.

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

APEX ها معمولاً به شرح زیر استفاده می شوند:

  1. یک OEM یا ODM یک APEX را در /system/apex در هنگام ارسال دستگاه از قبل بارگذاری می کند.
  2. فایل های موجود در APEX از طریق مسیر /apex/<apex_name>/ قابل دسترسی هستند.
  3. هنگامی که نسخه به روز شده APEX در /data/apex نصب می شود، مسیر پس از راه اندازی مجدد به APEX جدید اشاره می کند.

یک سرویس را با APEX به روز کنید

برای به روز رسانی یک سرویس با استفاده از APEX:

  1. سرویس را در پارتیشن سیستم به عنوان قابل به روز رسانی علامت گذاری کنید. گزینه updatable به تعریف سرویس اضافه کنید.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. یک فایل .rc جدید برای سرویس به روز شده ایجاد کنید. از گزینه override برای تعریف مجدد سرویس موجود استفاده کنید.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

تعاریف سرویس را فقط می توان در فایل .rc یک APEX تعریف کرد. محرک های اقدام در APEX ها پشتیبانی نمی شوند.

اگر سرویسی که به‌عنوان قابل به‌روزرسانی علامت‌گذاری شده است، قبل از فعال شدن APEX شروع به کار کند، شروع به تأخیر می‌افتد تا فعال‌سازی APEXها کامل شود.

سیستم را برای پشتیبانی از به روز رسانی های APEX پیکربندی کنید

برای پشتیبانی از به روز رسانی فایل APEX، ویژگی سیستم زیر را روی true تنظیم کنید.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

یا فقط

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

APEX صاف

برای دستگاه های قدیمی، گاهی اوقات به روز رسانی هسته قدیمی برای پشتیبانی کامل از APEX غیرممکن یا غیرممکن است. برای مثال، ممکن است هسته بدون CONFIG_BLK_DEV_LOOP=Y ساخته شده باشد، که برای نصب تصویر سیستم فایل در داخل APEX بسیار مهم است.

Flattened APEX یک APEX مخصوص ساخته شده است که می تواند در دستگاه هایی با هسته قدیمی فعال شود. فایل‌های موجود در یک APEX مسطح مستقیماً در یک فهرست زیر پارتیشن داخلی نصب می‌شوند. برای مثال، lib/libFoo.so در یک APEX مسطح my.apex به /system/apex/my.apex/lib/libFoo.so نصب می‌شود.

فعال کردن یک APEX مسطح، دستگاه حلقه را شامل نمی شود. کل دایرکتوری /system/apex/my.apex مستقیماً به /apex/name@ver متصل می‌شود.

APEX های مسطح را نمی توان با دانلود نسخه های به روز شده APEX ها از شبکه به روز کرد زیرا APEX های دانلود شده را نمی توان مسطح کرد. APEX های مسطح را می توان فقط از طریق یک OTA معمولی به روز کرد.

Flattened APEX پیکربندی پیش فرض است. این بدان معنی است که تمام APEX ها به طور پیش فرض مسطح هستند، مگر اینکه دستگاه خود را به صراحت پیکربندی کنید تا APEX های غیر مسطح را برای پشتیبانی از به روز رسانی های APEX (همانطور که در بالا توضیح داده شد) بسازید.

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

APEX های فشرده

اندروید 12 و نسخه‌های جدیدتر دارای فشرده‌سازی APEX برای کاهش تأثیر ذخیره‌سازی بسته‌های APEX قابل به‌روزرسانی هستند. پس از نصب به‌روزرسانی برای APEX، اگرچه نسخه از پیش نصب شده آن دیگر استفاده نمی‌شود، اما همچنان همان مقدار فضا را اشغال می‌کند. آن فضای اشغال شده در دسترس نیست.

فشرده سازی APEX این تأثیر ذخیره سازی را با استفاده از مجموعه ای بسیار فشرده از فایل های APEX روی پارتیشن های فقط خواندنی (مانند پارتیشن /system ) به حداقل می رساند. اندروید 12 به بعد از الگوریتم فشرده سازی زیپ DEFLATE استفاده می کند.

فشرده سازی برای موارد زیر بهینه سازی نمی کند:

  • APEX های بوت استرپ که باید خیلی زود در دنباله بوت نصب شوند.

  • APEX های غیرقابل به روز رسانی فشرده سازی تنها زمانی مفید است که نسخه به روز شده APEX روی پارتیشن /data نصب شده باشد. لیست کاملی از APEX های قابل به روز رسانی در صفحه اجزای سیستم مدولار موجود است.

  • APEXهای لیب مشترک پویا. از آنجایی که apexd همیشه هر دو نسخه از این APEX ها را (از پیش نصب شده و ارتقا یافته) فعال می کند، فشرده سازی آنها ارزش افزوده ای ندارد.

فرمت فایل APEX فشرده

این فرمت یک فایل APEX فشرده است.

Diagram shows the format of a compressed APEX file

شکل 2. فرمت فایل APEX فشرده

در سطح بالا، یک فایل APEX فشرده یک فایل فشرده حاوی فایل apex اصلی به صورت خالی با سطح فشرده‌سازی 9 و با فایل‌های دیگر ذخیره‌شده غیرفشرده است.

چهار فایل شامل یک فایل APEX هستند:

  • original_apex : deflated با سطح فشرده سازی 9 این فایل APEX اصلی و غیرفشرده است.
  • apex_manifest.pb : فقط ذخیره می شود
  • AndroidManifest.xml : فقط ذخیره می شود
  • apex_pubkey : فقط ذخیره می شود

فایل‌های apex_manifest.pb ، AndroidManifest.xml ، و apex_pubkey کپی‌هایی از فایل‌های مربوطه خود در original_apex هستند.

ساخت APEX فشرده

APEX فشرده را می توان با استفاده از ابزار apex_compression_tool.py واقع در system/apex/tools ساخت.

چندین پارامتر مربوط به فشرده سازی APEX در سیستم ساخت موجود است.

در Android.bp اینکه آیا یک فایل APEX فشرده است یا خیر توسط ویژگی compressible کنترل می‌شود:

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

پرچم محصول PRODUCT_COMPRESSED_APEX کنترل می کند که آیا تصویر سیستمی که از منبع ساخته شده است باید حاوی فایل های فشرده APEX باشد یا خیر.

برای آزمایش محلی، می‌توانید با تنظیم OVERRIDE_PRODUCT_COMPRESSED_APEX= روی true یک ساخت را مجبور به فشرده‌سازی APEX کنید.

فایل های فشرده APEX تولید شده توسط سیستم ساخت دارای پسوند .capex هستند. پسوند تشخیص بین نسخه های فشرده و غیرفشرده یک فایل APEX را آسان تر می کند.

الگوریتم های فشرده سازی پشتیبانی شده

اندروید 12 فقط از فشرده سازی deflate-zip پشتیبانی می کند.

یک فایل APEX فشرده را در هنگام بوت فعال کنید

قبل از اینکه یک APEX فشرده فعال شود، فایل original_apex داخل آن در پوشه /data/apex/decompressed از حالت فشرده خارج می شود. فایل APEX از حالت فشرده خارج شده به دایرکتوری /data/apex/active پیوند سختی دارد.

مثال زیر را به عنوان تصویری از فرآیندی که در بالا توضیح داده شد در نظر بگیرید.

/system/apex/com.android.foo.capex به عنوان یک APEX فشرده در حال فعال شدن با نسخه 37 در نظر بگیرید.

  1. فایل original_apex داخل /system/apex/com.android.foo.capex به /data/apex/decompressed/com.android.foo@37.apex از حالت فشرده خارج می‌شود.
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex برای تأیید اینکه برچسب SELinux صحیحی دارد انجام می شود.
  3. بررسی‌های تأیید در /data/apex/decompressed/com.android.foo@37.apex انجام می‌شود تا از اعتبار آن اطمینان حاصل شود: apexd کلید عمومی موجود در /data/apex/decompressed/com.android.foo@37.apex را بررسی می‌کند. بررسی کنید که برابر با مجموعه موجود در /system/apex/com.android.foo.capex باشد.
  4. فایل /data/apex/decompressed/com.android.foo@37.apex به دایرکتوری /data/apex/active/com.android.foo@37.apex به سختی پیوند داده شده است.
  5. منطق فعال‌سازی معمولی برای فایل‌های APEX فشرده نشده در /data/apex/active/com.android.foo@37.apex انجام می‌شود.

تعامل با OTA

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

برای پشتیبانی از سیستم OTA، apexd این دو API بایندر را در معرض دید قرار می دهد:

  • calculateSizeForCompressedApex - اندازه مورد نیاز برای فشرده سازی فایل های APEX در یک بسته OTA را محاسبه می کند. این می تواند برای تأیید اینکه دستگاه قبل از بارگیری OTA فضای کافی دارد استفاده شود.
  • reserveSpaceForCompressedApex - فضای روی دیسک را برای استفاده در آینده توسط apexd برای از حالت فشرده‌کردن فایل‌های APEX فشرده داخل بسته OTA ذخیره می‌کند.

در مورد به‌روزرسانی A/B OTA، apexd به عنوان بخشی از روال OTA پس‌نصب، در پس‌زمینه فشرده‌سازی می‌کند. اگر فشرده سازی ناموفق باشد، apexd در طول بوت که به روز رسانی OTA را اعمال می کند، فشرده سازی را انجام می دهد.

گزینه های جایگزین در نظر گرفته شده هنگام توسعه APEX

در اینجا چند گزینه وجود دارد که AOSP هنگام طراحی فرمت فایل APEX در نظر گرفته است و چرا آنها شامل یا حذف می شوند.

سیستم های مدیریت بسته منظم

توزیع های لینوکس دارای سیستم های مدیریت بسته مانند dpkg و rpm هستند که قدرتمند، بالغ و قوی هستند. با این حال، آنها برای APEX پذیرفته نشدند زیرا نمی توانند پس از نصب از بسته ها محافظت کنند. تأیید فقط زمانی انجام می شود که بسته ها در حال نصب هستند. مهاجمان بدون توجه می توانند یکپارچگی بسته های نصب شده را بشکنند. این یک رگرسیون برای Android است که در آن تمام اجزای سیستم در سیستم‌های فایل فقط خواندنی ذخیره می‌شوند که یکپارچگی آن توسط dm-verity برای هر ورودی/خروجی محافظت می‌شود. هرگونه دستکاری در اجزای سیستم یا باید ممنوع باشد، یا قابل تشخیص باشد تا در صورت به خطر افتادن دستگاه بتواند از بوت شدن خودداری کند.

dm-crypt برای یکپارچگی

فایل‌های موجود در یک کانتینر APEX از پارتیشن‌های داخلی (به عنوان مثال، پارتیشن /system ) هستند که توسط dm-verity محافظت می‌شوند، جایی که هرگونه تغییر در فایل‌ها حتی پس از نصب پارتیشن‌ها ممنوع است. برای ارائه همان سطح امنیت به فایل‌ها، همه فایل‌ها در یک APEX در یک تصویر سیستم فایل که با درخت هش و توصیفگر vbmeta جفت شده است، ذخیره می‌شوند. بدون dm-verity، یک APEX در پارتیشن /data در برابر تغییرات ناخواسته ای که پس از تأیید و نصب آن انجام می شود آسیب پذیر است.

در واقع پارتیشن /data نیز توسط لایه های رمزگذاری مانند dm-crypt محافظت می شود. اگرچه این تا حدی محافظت در برابر دستکاری را فراهم می کند، اما هدف اصلی آن حفظ حریم خصوصی است، نه یکپارچگی. هنگامی که یک مهاجم به پارتیشن /data دسترسی پیدا می کند، نمی تواند محافظت بیشتری داشته باشد، و این دوباره در مقایسه با هر جزء سیستمی که در پارتیشن /system است یک رگرسیون است. درخت هش داخل یک فایل APEX همراه با dm-verity همان سطح حفاظت از محتوا را فراهم می کند.

مسیرها را از /system به /apex تغییر دهید

فایل های اجزای سیستم بسته بندی شده در APEX از طریق مسیرهای جدیدی مانند /apex/<name>/lib/libfoo.so قابل دسترسی هستند. هنگامی که فایل ها بخشی از پارتیشن /system بودند، از طریق مسیرهایی مانند /system/lib/libfoo.so قابل دسترسی بودند. مشتری یک فایل APEX (سایر فایل های APEX یا پلتفرم) باید از مسیرهای جدید استفاده کند. ممکن است در نتیجه تغییر مسیر نیاز به به روز رسانی کد موجود داشته باشید.

اگرچه یکی از راه‌های جلوگیری از تغییر مسیر، همپوشانی محتویات فایل در یک فایل APEX بر روی پارتیشن /system است، تیم اندروید تصمیم گرفت که فایل‌ها را روی پارتیشن /system قرار ندهد زیرا این می‌تواند بر روی عملکرد به دلیل تعداد فایل‌هایی که روی هم قرار می‌گیرند، تأثیر بگذارد. احتمالاً حتی یکی پس از دیگری انباشته شده اند) افزایش یافته است.

گزینه دیگر ربودن توابع دسترسی به فایل مانند open ، stat و readlink بود، به طوری که مسیرهایی که با /system شروع می‌شوند به مسیرهای مربوطه خود تحت /apex هدایت شوند. تیم Android این گزینه را رد کرد زیرا تغییر همه عملکردهایی که مسیرها را می‌پذیرند غیرممکن است. به عنوان مثال، برخی از برنامه ها به طور ایستا Bionic را پیوند می دهند که توابع را پیاده سازی می کند. در چنین مواردی، آن برنامه‌ها هدایت نمی‌شوند.