فرمت فایل APEX

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

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

پیشینه

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

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

طراحی

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

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

فرمت APEX

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

فرمت فایل APEX

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

در سطح بالا، یک فایل APEX یک فایل زیپ است که در آن فایل‌ها به صورت غیرفشرده ذخیره می‌شوند و در مرزهای ۴ کیلوبایتی قرار دارند.

چهار فایل موجود در یک فایل 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 سروکار دارند، apex_manifest.json نسبت به AndroidManifest.xml توصیه می‌شود. 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 (یا 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. یک دستگاه بلوک نگاشت کننده دستگاه را روی دستگاه loopback ایجاد می‌کند.
    4. بلوک نگاشت‌کننده دستگاه را روی یک مسیر منحصر به فرد (مثلاً /apex/ name @ ver ) نصب می‌کند.

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

فایل‌های 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 نسخه ۳ امضا می‌شود. در این فرآیند از دو کلید مختلف استفاده می‌شود.

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

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

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

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

الزامات هسته

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

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

نسخه‌های کرنل پشتیبانی‌شده

ماژول‌های اصلی APEX در دستگاه‌هایی که از نسخه‌های کرنل ۴.۴ یا بالاتر استفاده می‌کنند، پشتیبانی می‌شوند. دستگاه‌های جدیدی که با اندروید ۱۰ یا بالاتر عرضه می‌شوند، برای پشتیبانی از ماژول‌های APEX باید از کرنل نسخه ۴.۹ یا بالاتر استفاده کنند.

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

پچ‌های کرنل مورد نیاز برای پشتیبانی از ماژول‌های APEX در درخت مشترک اندروید (Android common tree) گنجانده شده‌اند. برای دریافت پچ‌هایی که از APEX پشتیبانی می‌کنند، از آخرین نسخه درخت مشترک اندروید استفاده کنید.

نسخه کرنل ۴.۴

این نسخه فقط برای دستگاه‌هایی پشتیبانی می‌شود که از اندروید ۹ به اندروید ۱۰ ارتقا یافته‌اند و می‌خواهند از ماژول‌های APEX پشتیبانی کنند. برای دریافت پچ‌های مورد نیاز، ادغام از شاخه android-4.4 به پایین اکیداً توصیه می‌شود. در زیر لیستی از پچ‌های مورد نیاز برای نسخه هسته ۴.۴ آمده است.

  • آپ‌استریم: حلقه: اضافه کردن ioctl برای تغییر اندازه بلوک منطقی ( ۴.۴ )
  • بک‌پورت: بلوک/حلقه: تنظیم hw_sectors ( 4.4 )
  • آپ‌استریم: حلقه: اضافه کردن LOOP_SET_BLOCK_SIZE در compat ioctl ( 4.4 )
  • اندروید: mnt: رفع مشکل next_descendent ( 4.4 )
  • اندروید: mnt: remount باید به slaveهای slaveها هم منتقل شود ( ۴.۴ )
  • اندروید: mnt: انتشار مجدد به درستی ( ۴.۴ )
  • برگرداندن "ANDROID: dm verity: add minimum prefetch size" ( 4.4 )
  • حلقه‌ی UpStream: اگر offset یا block_size تغییر کنند، کش‌ها را حذف می‌کند ( ۴.۴ )

نسخه‌های کرنل ۴.۹/۴.۱۴/۴.۱۹

برای دریافت وصله‌های مورد نیاز برای نسخه‌های کرنل ۴.۹/۴.۱۴/۴.۱۹، شاخه android-common را به پایین ادغام کنید.

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

لیست زیر الزامات پیکربندی پایه برای پشتیبانی از ماژول‌های APEX که در اندروید ۱۰ معرفی شده‌اند را نشان می‌دهد. مواردی که با ستاره (*) مشخص شده‌اند، الزامات موجود از اندروید ۹ و پایین‌تر هستند.

(*) 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 فهرست شده باشد، این دو کتابخانه نیز شامل می‌شوند.

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

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

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

  • اگر دستگاه فقط ۳۲ بیتی باشد، فقط نوع ۳۲ بیتی فایل باینری نصب می‌شود.
  • اگر دستگاه فقط ۶۴ بیتی باشد، فقط نوع ۶۴ بیتی فایل باینری نصب می‌شود.

برای افزودن کنترل دقیق بر 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 هستند.

این مثال برای دستگاهی است که از 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 توضیح داده شد، تمام کلیدهای آزمایشی باید قبل از انتشار عمومی با کلیدهای انتشار مربوطه جایگزین شوند. سرورهای ساخت OEM می‌توانند ابزار میزبان sign_target_files_apks را ادغام کنند، که هم تصویر سیستم فایل و هم کل فایل APEX را برای تمام فایل‌های APEX موجود در یک آرشیو زیپ target-files دوباره امضا می‌کند.

برای امنیت، رعایت نکات زیر در مدیریت کلید و عملیات امضای نسخه ضروری است:

  • کلیدهای انتشار را در یک محیط امن نگهداری کنید تا دسترسی به آنها محدود شود.

  • یک ACL باید شروع عملیات امضای انتشار را کنترل کند.

  • مصنوعات را تنها پس از آزمایش و تأیید برای انتشار، با کلید انتشار امضا کنید.

  • یک شخص باید اقدامات امضای انتشار را آغاز کند؛ این فرآیند را خودکار نکنید.

  • مصنوعات امضا شده با کلید انتشار باید در یک محیط امن ذخیره شوند.

  • دسترسی به مصنوعات امضا شده با کلید انتشار باید به دلایل تجاری معتبر محدود شود.

  • سرور ساخت OEM باید سابقه هر درخواست امضا را در یک پایگاه داده امضا نگه دارد.

نصب 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 می‌توانند همزمان نصب شوند. در بین مسیرهای نصب، مسیری که مربوط به آخرین نسخه است، در /apex/<apex_name> متصل می‌شود.

کلاینت‌ها می‌توانند از مسیر bind-mounted برای خواندن یا اجرای فایل‌ها از 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 بسیار مهم است.

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 معمولی به‌روزرسانی کرد.

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

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

APEX های فشرده

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

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

فشرده‌سازی، بهینه‌سازی موارد زیر را ارائه نمی‌دهد:

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

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

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

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

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

Diagram shows the format of a compressed APEX file

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

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

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

  • original_apex : با سطح فشرده‌سازی ۹، فشرده‌سازی نشده است. این فایل 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 را آسان‌تر می‌کند.

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

اندروید ۱۲ فقط از فشرده‌سازی فایل زیپ Deflate پشتیبانی می‌کند.

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

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

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

/system/apex/com.android.foo.capex را به عنوان یک APEX فشرده شده که با versionCode 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 به صورت hard-link شده است.
  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، رزرو می‌کند.

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

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

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

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

توزیع‌های لینوکس دارای سیستم‌های مدیریت بسته مانند dpkg و rpm هستند که قدرتمند، بالغ و قوی هستند. با این حال، آنها برای APEX پذیرفته نشدند زیرا نمی‌توانند از بسته‌ها پس از نصب محافظت کنند. تأیید فقط زمانی انجام می‌شود که بسته‌ها نصب می‌شوند. مهاجمان می‌توانند یکپارچگی بسته‌های نصب شده را بدون اینکه متوجه شوند، بشکنند. این یک پسرفت برای اندروید است که در آن تمام اجزای سیستم در سیستم‌های فایل فقط خواندنی ذخیره می‌شدند که یکپارچگی آنها توسط 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 هدایت شوند. تیم اندروید این گزینه را کنار گذاشت زیرا تغییر همه توابعی که مسیرها را می‌پذیرند، غیرممکن است. به عنوان مثال، برخی از برنامه‌ها به طور ایستا Bionic را که توابع را پیاده‌سازی می‌کند، پیوند می‌دهند. در چنین مواردی، آن برنامه‌ها هدایت نمی‌شوند.