APEX फ़ाइल फ़ॉर्मैट

Android Pony EXpress (APEX) कंटेनर फ़ॉर्मैट को Android 10 में लॉन्च किया गया था. इसका इस्तेमाल, कम लेवल के सिस्टम मॉड्यूल के इंस्टॉल फ़्लो में किया जाता है. इस फ़ॉर्मैट की मदद से, उन सिस्टम कॉम्पोनेंट को अपडेट किया जा सकता है जो स्टैंडर्ड Android ऐप्लिकेशन मॉडल में फ़िट नहीं होते. उदाहरण के लिए, नेटिव सेवाएं और लाइब्रेरी, हार्डवेयर एब्स्ट्रैक्शन लेयर (HALs), रनटाइम (ART), और क्लास लाइब्रेरी.

"APEX" शब्द का इस्तेमाल, APEX फ़ाइल से भी किया जा सकता है.

बैकग्राउंड

Android, पैकेज इंस्टॉलर ऐप्लिकेशन (जैसे, Google Play Store ऐप्लिकेशन) के ज़रिए, स्टैंडर्ड ऐप्लिकेशन मॉडल (जैसे, सेवाएं, गतिविधियां) में फ़िट होने वाले मॉड्यूल के अपडेट के साथ काम करता है. हालांकि, ओएस के निचले लेवल के कॉम्पोनेंट के लिए इसी तरह के मॉडल का इस्तेमाल करने पर, ये समस्याएं आ सकती हैं:

  • APK पर आधारित मॉड्यूल को चालू करने के क्रम में, शुरुआत में इस्तेमाल नहीं किया जा सकता. पैकेज मैनेजर, ऐप्लिकेशन की जानकारी का मुख्य डेटाबेस होता है. इसे सिर्फ़ ऐक्टिविटी मैनेजर से शुरू किया जा सकता है. यह बूट प्रोसेस के आखिरी चरण में तैयार होता है.
  • APK फ़ॉर्मैट (खास तौर पर मेनिफ़ेस्ट) को Android ऐप्लिकेशन के लिए डिज़ाइन किया गया है और सिस्टम मॉड्यूल हमेशा इसके साथ काम नहीं करते.

डिज़ाइन

इस सेक्शन में, APEX फ़ाइल फ़ॉर्मैट और 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 फ़ाइल की पहचान करता है. यह JSON फ़ॉर्मैट में एक ApexManifest प्रोटोकॉल बफ़र है.

AndroidManifest.xml फ़ाइल, APEX फ़ाइल को APK से जुड़े टूल और ADB, PackageManager, और पैकेज इंस्टॉलर ऐप्लिकेशन (जैसे कि Play Store) जैसे इन्फ़्रास्ट्रक्चर का इस्तेमाल करने की अनुमति देती है. उदाहरण के लिए, APEX फ़ाइल में मौजूद बेसिक मेटाडेटा की जांच करने के लिए, aapt जैसे किसी मौजूदा टूल का इस्तेमाल किया जा सकता है. इस फ़ाइल में पैकेज का नाम और वर्शन की जानकारी होती है. आम तौर पर, यह जानकारी apex_manifest.json में भी उपलब्ध होती है.

APEX के साथ काम करने वाले नए कोड और सिस्टम के लिए, AndroidManifest.xml से ज़्यादा apex_manifest.json का सुझाव दिया जाता है. AndroidManifest.xml में टारगेटिंग से जुड़ी ऐसी अतिरिक्त जानकारी हो सकती है जिसका इस्तेमाल, ऐप्लिकेशन पब्लिश करने वाले मौजूदा टूल कर सकते हैं.

apex_payload.img, dm-verity की मदद से बैक अप ली गई ext4 फ़ाइल सिस्टम इमेज है. इमेज को लूपबैक डिवाइस के ज़रिए, रनटाइम पर माउंट किया जाता है. खास तौर पर, हैश ट्री और मेटाडेटा ब्लॉक को libavb लाइब्रेरी का इस्तेमाल करके बनाया जाता है. फ़ाइल सिस्टम पेलोड को पार्स नहीं किया गया है, क्योंकि इमेज को अपनी जगह पर माउंट किया जा सकता है. सामान्य फ़ाइलें, apex_payload.img फ़ाइल में शामिल होती हैं.

apex_pubkey एक सार्वजनिक कुंजी है, जिसका इस्तेमाल फ़ाइल सिस्टम इमेज पर हस्ताक्षर करने के लिए किया जाता है. रनटाइम के दौरान, यह कुंजी पक्का करती है कि डाउनलोड किया गया APEX फ़ंक्शन, उसी इकाई के साथ साइन किया गया है जो पहले से मौजूद पार्टीशन में एक ही APEX पर साइन करता है.

APEX को नाम देने के लिए दिशा-निर्देश

आगे बढ़ने के दौरान, नए APEXs के नाम एक-दूसरे से अलग होने से रोकने में मदद करने के लिए, नाम रखने से जुड़े इन दिशा-निर्देशों को अपनाएं:

  • com.android.*
    • AOSP APEX के लिए रिज़र्व है. यह किसी कंपनी या डिवाइस के लिए खास नहीं होता.
  • com.<companyname>.*
    • किसी कंपनी के लिए रिज़र्व है. उस कंपनी के कई डिवाइसों का इस्तेमाल किया जा सकता है.
  • com.<companyname>.<devicename>.*
    • किसी खास डिवाइस (या डिवाइसों के सबसेट) के लिए यूनीक APEXs के लिए रिज़र्व किया गया.

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. APEX फ़ाइल से लूपबैक डिवाइस बनाता है.
    3. लूपबैक डिवाइस के सबसे ऊपर एक डिवाइस मैपर ब्लॉक डिवाइस बनाता है.
    4. डिवाइस मैपर ब्लॉक डिवाइस को किसी यूनीक पाथ पर माउंट करता है (उदाहरण के लिए, /apex/name@ver).

जब इंटरनल डेटाबेस में लिस्ट की गई सभी APEX फ़ाइलें माउंट हो जाती हैं, तो APEX मैनेजर, सिस्टम के अन्य कॉम्पोनेंट को बाइंडर सेवा उपलब्ध कराता है. इससे, इंस्टॉल की गई APEX फ़ाइलों के बारे में जानकारी पाने के लिए, क्वेरी की जाती है. उदाहरण के लिए, सिस्टम के दूसरे कॉम्पोनेंट डिवाइस में इंस्टॉल की गई APEX फ़ाइलों की सूची के लिए क्वेरी कर सकते हैं या उस सटीक पाथ से क्वेरी कर सकते हैं जहां किसी खास APEX को माउंट किया गया है. इससे फ़ाइलों को ऐक्सेस किया जा सकता है.

APEX फ़ाइलें, APK फ़ाइलें होती हैं

APEX फ़ाइलें मान्य APK फ़ाइलें हैं, क्योंकि वे ऐसी ज़िप आर्काइव्स (APK सिग्नेचर स्कीम का इस्तेमाल करके) होती हैं जिसमें AndroidManifest.xml फ़ाइल होती है. इससे APEX फ़ाइलों को APK फ़ाइलों के लिए इन्फ़्रास्ट्रक्चर का इस्तेमाल करने में मदद मिलती है. जैसे, पैकेज इंस्टॉलर ऐप्लिकेशन, साइनिंग की सुविधा, और पैकेज मैनेजर.

APEX फ़ाइल में AndroidManifest.xml फ़ाइल बहुत छोटी होती है. इसमें सटीक टारगेटिंग के लिए, पैकेज name, versionCode, और वैकल्पिक targetSdkVersion, minSdkVersion, और maxSdkVersion शामिल होते हैं. इस जानकारी से APEX फ़ाइलों को, पैकेज इंस्टॉलर ऐप्लिकेशन और ADB जैसे मौजूदा चैनलों से डिलीवर करने में मदद मिलती है.

इस्तेमाल किए जा सकने वाले फ़ाइल टाइप

APEX फ़ॉर्मैट इन फ़ाइल टाइप के साथ काम करता है:

  • नेटिव शेयर की गई लिब्स
  • नेटिव एक्ज़ीक्यूटेबल
  • JAR फ़ाइलें
  • डेटा फ़ाइलें
  • कॉन्फ़िगरेशन फ़ाइलें

इसका मतलब यह नहीं है कि APEX इन सभी फ़ाइल टाइप को अपडेट कर सकता है. किसी फ़ाइल टाइप को अपडेट किया जा सकता है या नहीं, यह प्लैटफ़ॉर्म पर निर्भर करता है. साथ ही, यह इस बात पर भी निर्भर करता है कि फ़ाइल टाइप के लिए इंटरफ़ेस की परिभाषाएं कितनी स्थायी हैं.

हस्ताक्षर करने के विकल्प

APEX फ़ाइलों पर दो तरीकों से हस्ताक्षर किए जाते हैं. सबसे पहले, apex_payload.img (खास तौर पर, apex_payload.img में जोड़ा गया vbmeta डिस्क्रिप्टर) फ़ाइल को किसी कुंजी से साइन किया जाता है. इसके बाद, पूरे APEX को APK सिग्नेचर स्कीम v3 का इस्तेमाल करके साइन किया जाता है. इस प्रोसेस में दो अलग-अलग की का इस्तेमाल किया जाता है.

डिवाइस पर, vbmeta डिस्क्रिप्टर पर हस्ताक्षर करने के लिए इस्तेमाल की गई निजी कुंजी से जुड़ी सार्वजनिक कुंजी इंस्टॉल की जाती है. APEX मैनेजर, इंस्टॉल किए जाने के लिए अनुरोध किए गए APEX की पुष्टि करने के लिए, सार्वजनिक पासकोड का इस्तेमाल करता है. हर APEX को अलग-अलग कुंजियों से साइन किया जाना चाहिए. साथ ही, उसे बिल्ड के समय और रनटाइम, दोनों के समय लागू किया जाना चाहिए.

पहले से मौजूद पार्टीशन में APEX

APEX फ़ाइलें, /system जैसे पहले से मौजूद पार्टीशन में मौजूद हो सकती हैं. डिवाइस का यह partition, पहले से ही dm-verity पर है. इसलिए, APEX फ़ाइलें सीधे तौर पर लूपबैक डिवाइस पर माउंट की जाती हैं.

अगर कोई APEX, पहले से मौजूद पार्टीशन में मौजूद है, तो APEX को अपडेट किया जा सकता है. इसके लिए, एक ही पैकेज के नाम वाला APEX पैकेज दें. साथ ही, यह भी ज़रूरी है कि पैकेज का वर्शन कोड, मौजूदा वर्शन कोड से बड़ा या उसके बराबर हो. नया APEX, /data में सेव होता है. APK की तरह ही, इंस्टॉल किया गया नया वर्शन, पहले से मौजूद वर्शन की जगह ले लेता है. हालांकि, APK के उलट, इंस्टॉल किया गया नया APEX वर्शन, डिवाइस को फिर से चालू करने के बाद ही चालू होता है.

Kernel से जुड़ी ज़रूरी शर्तें

किसी Android डिवाइस पर APEX मेनलाइन मॉड्यूल की सुविधा के लिए, इन Linux कर्नेल सुविधाओं की ज़रूरत है: लूपबैक ड्राइवर और dm-verity. लूपबैक ड्राइवर, फ़ाइल सिस्टम इमेज को APEX मॉड्यूल में माउंट करता है. साथ ही, dm-verity, APEX मॉड्यूल की पुष्टि करता है.

APEX मॉड्यूल का इस्तेमाल करते समय, सिस्टम की परफ़ॉर्मेंस को बेहतर बनाने के लिए, लूपबैक ड्राइवर और dm-verity की परफ़ॉर्मेंस का ध्यान रखना ज़रूरी है.

इस्तेमाल किए जा सकने वाले kernel वर्शन

APEX मेनलाइन मॉड्यूल, कर्नेल के 4.4 या इसके बाद के वर्शन का इस्तेमाल करने वाले डिवाइसों पर काम करते हैं. Android 10 या उसके बाद के वर्शन के साथ लॉन्च होने वाले नए डिवाइसों में, APEX मॉड्यूल की सुविधा के लिए, कर्नेल वर्शन 4.9 या उसके बाद वाले वर्शन का इस्तेमाल करना ज़रूरी है.

ज़रूरी कर्नेल पैच

APEX मॉड्यूल के साथ काम करने के लिए ज़रूरी कर्नेल पैच, Android के सामान्य ट्री में शामिल होते हैं. APEX के साथ काम करने के लिए पैच पाने के लिए, Android कॉमन ट्री के सबसे नए वर्शन का इस्तेमाल करें.

Kernel वर्शन 4.4

यह वर्शन सिर्फ़ उन डिवाइसों के लिए उपलब्ध है जिन्हें Android 9 से Android 10 पर अपग्रेड किया गया है और जिन्हें APEX मॉड्यूल के साथ काम करना है. ज़रूरी पैच पाने के लिए, android-4.4 शाखा से डाउन-मर्ज करने का सुझाव दिया जाता है. कर्नेल वर्शन 4.4 के लिए ज़रूरी अलग-अलग पैच की सूची नीचे दी गई है.

  • अपस्ट्रीम: loop: लॉजिकल ब्लॉक साइज़ बदलने के लिए ioctl जोड़ें (4.4)
  • बैकपोर्ट: ब्लॉक/लूप: hw_secters सेट करें (4.4)
  • UPSTREAM: लूप: compat ioctl में LOOP_SET_ब्लॉक_SIZE जोड़ें (4.4)
  • ANDROID: mnt: next_descendent को ठीक करना (4.4)
  • ANDROID: mnt: remount should propagate to slaves of slaves (4.4)
  • ANDROID: mnt: Propagate remount correctly (4.4)
  • "ANDROID: dm वेरिटी: कम से कम प्रीफ़ेच साइज़ जोड़ें" (4.4) को पहले जैसा करें
  • अपस्ट्रीम: loop: offset या block_size में बदलाव होने पर कैश मेमोरी हटाएं (4.4)

kernel के 4.9/4.14/4.19 वर्शन

कर्नेल के वर्शन 4.9/4.14/4.19 के लिए ज़रूरी पैच पाने के लिए, android-common शाखा से डाउन-मर्ज करें.

कर्नेल कॉन्फ़िगरेशन के ज़रूरी विकल्प

नीचे दी गई सूची में, Android 10 में पेश किए गए APEX मॉड्यूल के साथ काम करने के लिए, बेस कॉन्फ़िगरेशन की ज़रूरी शर्तों के बारे में बताया गया है. तारे के निशान (*) वाले आइटम Android 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

Kernel कमांड-लाइन पैरामीटर की ज़रूरी शर्तें

APEX के साथ काम करने के लिए, पक्का करें कि कर्नेल कमांड-लाइन पैरामीटर इन ज़रूरी शर्तों को पूरा करते हों:

  • loop.max_loop को सेट नहीं किया जाना चाहिए
  • loop.max_part की वैल्यू 8 से ज़्यादा नहीं होनी चाहिए

APEX बनाएं

इस सेक्शन में, Android बिल्ड सिस्टम का इस्तेमाल करके APEX फ़ाइल बनाने का तरीका बताया गया है. apex.test नाम के APEX फ़ंक्शन के लिए, Android.bp का उदाहरण यहां दिया गया है.

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 (x86 में अनुवाद किए गए arm के लिए /lib/arm)
एक्ज़ीक्यूटेबल /bin
Java लाइब्रेरी /javalib
पहले से बने /etc

ट्रांसिटिव डिपेंडेंसी

APEX फ़ाइलों में, नेटिव शेयर की गई लाइब्रेरी या एक्सीक्यूटेबल की ट्रांज़िशन डिपेंडेंसी अपने-आप शामिल हो जाती हैं. उदाहरण के लिए, अगर libFoo, libBar पर निर्भर करता है, तो दोनों लाइब्रेरी तब शामिल की जाती हैं, जब native_shared_libs प्रॉपर्टी में सिर्फ़ libFoo शामिल हो.

एक से ज़्यादा एबीआई मैनेज करना

डिवाइस के प्राइमरी और सेकंडरी ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) दोनों के लिए, native_shared_libs प्रॉपर्टी इंस्टॉल करें. अगर कोई APEX, सिर्फ़ एक एबीआई (यानी सिर्फ़ 32 बिट या सिर्फ़ 64 बिट) वाले डिवाइसों को टारगेट करता है, तो उससे जुड़ी एबीआई वाली लाइब्रेरी ही इंस्टॉल की जाती हैं.

यहां बताए गए तरीके से, binaries प्रॉपर्टी को डिवाइस के सिर्फ़ मुख्य एबीआई के लिए इंस्टॉल करें:

  • अगर डिवाइस में सिर्फ़ 32 बिट है, तो बाइनरी का सिर्फ़ 32-बिट वाला वैरिएंट इंस्टॉल होगा.
  • अगर डिवाइस में सिर्फ़ 64 बिट है, तो बाइनरी का सिर्फ़ 64-बिट वाला वैरिएंट इंस्टॉल होगा.

नेटिव लाइब्रेरी और बाइनरी के एबीआई को बेहतर तरीके से कंट्रोल करने के लिए, multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] प्रॉपर्टी का इस्तेमाल करें.

  • first: डिवाइस के मुख्य एबीआई से मेल खाता है. यह बिनेरी के लिए डिफ़ॉल्ट है.
  • lib32: अगर ऐप्लिकेशन काम करता है, तो डिवाइस के 32-बिट एबीआई से मेल खाता है.
  • lib64: डिवाइस के 64-बिट एबीआई से मेल खाता है और यह डिवाइस के साथ काम करता है.
  • prefer32: अगर डिवाइस पर 32-बिट एबीआई काम करता है, तो यह उससे मेल खाता है. अगर 32-बिट एबीआई काम नहीं करता है, तो 64-बिट एबीआई से मैच होता है.
  • both: दोनों एबीआई से मैच करता है. यह native_shared_libraries के लिए डिफ़ॉल्ट सेटिंग है.

java, libraries, और prebuilts प्रॉपर्टी, एबीआई पर निर्भर नहीं करती हैं.

यह उदाहरण ऐसे डिवाइस के लिए है जो 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 मॉड्यूल बनाएं. पासकोड का इस्तेमाल करके APEX को हस्ताक्षर करने के लिए, key प्रॉपर्टी का इस्तेमाल करें. सार्वजनिक पासकोड, avb_pubkey नाम के साथ APEX में अपने-आप शामिल हो जाता है.

# 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 को PRODUCT_DEFAULT_DEV_CERTIFICATE के साथ मौजूद डायरेक्ट्री में मौजूद <name> सर्टिफ़िकेट से हस्ताक्षर किया गया है.
  • :<name>: APEX को उस सर्टिफ़िकेट से साइन किया गया है जिसे <name> नाम के Soong मॉड्यूल से तय किया गया है. सर्टिफ़िकेट मॉड्यूल को इस तरह से परिभाषित किया जा सकता है.
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

अगर apex_manifest.json में supportsRebootlessUpdate को true पर सेट किया गया है और फ़िलहाल इंस्टॉल किए गए APEX को इस्तेमाल नहीं किया गया है (उदाहरण के लिए, इसमें शामिल सभी सेवाएं बंद कर दी गई हैं), तो --force-non-staged फ़्लैग की मदद से, बिना फिर से चालू किए नया APEX इंस्टॉल किया जा सकता है.

adb install --force-non-staged apex_file_name

APEX का इस्तेमाल करना

रीबूट होने के बाद, APEX को /apex/<apex_name>@<version> directory में माउंट किया जाता है. एक ही APEX के कई वर्शन एक साथ माउंट किए जा सकते हैं. माउंट पाथ में, सबसे नए वर्शन वाला पाथ /apex/<apex_name> पर बाइंड-माउंट किया गया है.

क्लाइंट, APEX से फ़ाइलों को पढ़ने या उन्हें एक्ज़ीक्यूट करने के लिए, बाइंड-माउंट किए गए पाथ का इस्तेमाल कर सकते हैं.

आम तौर पर, APEX का इस्तेमाल इस तरह किया जाता है:

  1. डिवाइस शिप होने पर, OEM या ODM, /system/apex में APEX को पहले से लोड करता है.
  2. APEX में मौजूद फ़ाइलों को /apex/<apex_name>/ पाथ से ऐक्सेस किया जाता है.
  3. जब /data/apex में 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
    

सेवा की परिभाषाएं, APEX की सिर्फ़ .rc फ़ाइल में तय की जा सकती हैं. APEX में, ऐक्शन ट्रिगर का इस्तेमाल नहीं किया जा सकता.

अगर APEXes चालू होने से पहले, अपडेट की जा सकने वाली सेवा के तौर पर मार्क की गई सेवा शुरू होती है, तो उसे चालू होने में तब तक देरी होती है, जब तक APEXes को चालू नहीं किया जाता.

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 को खास तौर पर बनाया गया है. इसे लेगसी कर्नेल वाले डिवाइसों पर चालू किया जा सकता है. फ़्लैट किए गए APEX में मौजूद फ़ाइलें, पहले से मौजूद पार्टिशन के तहत सीधे डायरेक्ट्री में इंस्टॉल हो जाती हैं. उदाहरण के लिए, फ़्लैट किए गए APEX में lib/libFoo.so, my.apex में इंस्टॉल किया गया है.

फ़्लैट किए गए APEX को चालू करने के लिए, लूप डिवाइस की ज़रूरत नहीं होती. पूरी डायरेक्ट्री /system/apex/my.apex, सीधे तौर पर /apex/name@ver पर माउंट की जाती है.

नेटवर्क से APEX के अपडेट किए गए वर्शन डाउनलोड करके, फ़्लैट किए गए APEXs अपडेट नहीं किए जा सकते. ऐसा इसलिए, क्योंकि डाउनलोड किए गए APEXes को फ़्लैट नहीं किया जा सकता. फ़्लैट किए गए एपेक्स को सिर्फ़ सामान्य ओटीए की मदद से अपडेट किया जा सकता है.

फ़्लैट किया गया APEX, डिफ़ॉल्ट कॉन्फ़िगरेशन होता है. इसका मतलब है कि सभी APEX डिफ़ॉल्ट रूप से फ़्लैट होते हैं. हालांकि, अगर आपने अपने डिवाइस को APEX अपडेट के साथ काम करने के लिए, फ़्लैट नहीं किए गए APEX बनाने के लिए साफ़ तौर पर कॉन्फ़िगर किया है, तो ऐसा नहीं होगा. इस बारे में ऊपर बताया गया है.

किसी डिवाइस में, फ़्लैट किए गए और फ़्लैट नहीं किए गए APEX को एक साथ इस्तेमाल नहीं किया जा सकता. किसी डिवाइस में सभी APEX, फ़्लैट किए गए होने चाहिए या सभी फ़्लैट नहीं होने चाहिए. खास तौर पर, ऐसा करना तब ज़रूरी होता है, जब Mainline जैसे प्रोजेक्ट के लिए पहले से साइन किए गए APEX पहले से बनाए गए तरीके की शिपिंग की जाती है. ऐसे APEX जो पहले से साइन नहीं किए गए हैं (यानी, जिन्हें सोर्स से बनाया गया है), भी बिना फ़्लैट वाले होने चाहिए और उन्हें सही कुंजियों के साथ साइन किया जाना चाहिए. डिवाइस को updatable_apex.mk से इनहेरिट किया जाना चाहिए, जैसा कि APEX के साथ किसी सेवा को अपडेट करना में बताया गया है.

कंप्रेस किए गए APEX

Android 12 और इसके बाद वाले वर्शन में, APEX कंप्रेशन की सुविधा मिलती है. इससे अपडेट किए जा सकने वाले APEX पैकेज के स्टोरेज पर पड़ने वाले असर को कम किया जा सकता है. APEX इंस्टॉल किए जाने के बाद, उसके पहले से इंस्टॉल किए गए वर्शन का अब इस्तेमाल नहीं किया जाता, लेकिन यह अब भी उतनी ही जगह लेता है. वह स्पेस उपलब्ध नहीं रहेगा.

APEX कंप्रेस करने की सुविधा, रीड-ओनली वाले पार्टीशन (जैसे कि /system पार्टीशन) पर, APEX फ़ाइलों के ज़्यादा कंप्रेस किए गए सेट का इस्तेमाल करके, स्टोरेज पर पड़ने वाले असर को कम करती है. Android 12 और उसके बाद के वर्शन, DEFLATE zip कंप्रेसन एल्गोरिदम का इस्तेमाल करते हैं.

कंप्रेस करने से, इनके लिए ऑप्टिमाइज़ेशन नहीं मिलता:

  • ऐसे बूटस्ट्रैप APEX जिन्हें बूट सीक्वेंस में बहुत पहले माउंट करना ज़रूरी होता है.

  • अपडेट नहीं किए जा सकने वाले APEX. कंप्रेस करने की सुविधा सिर्फ़ तब फ़ायदेमंद होती है, जब /data पार्टिशन में APEX का अपडेट किया गया वर्शन इंस्टॉल किया गया हो. अपडेट किए जा सकने वाले APEXes की पूरी सूची, मॉड्यूलर सिस्टम कॉम्पोनेंट पेज पर उपलब्ध है.

  • डाइनैमिक शेयर की गई लिब्स APEXes. apexd, ऐसे APEX के दोनों वर्शन (पहले से इंस्टॉल और अपग्रेड किए गए) को हमेशा चालू रखता है. इसलिए, उन्हें कंप्रेस करने से कोई फ़ायदा नहीं होता.

कंप्रेस किया गया APEX फ़ाइल फ़ॉर्मैट

यह कंप्रेस की गई APEX फ़ाइल का फ़ॉर्मैट है.

डायग्राम में, कंप्रेस की गई APEX फ़ाइल का फ़ॉर्मैट दिखाया गया है

दूसरी इमेज. कंप्रेस किया गया APEX फ़ाइल फ़ॉर्मैट

सबसे ऊपर के लेवल पर, कंप्रेस की गई APEX फ़ाइल एक ऐसी ZIP फ़ाइल होती है जिसमें ओरिजनल एपेक्स फ़ाइल, डिफ़्लेटेड फ़ॉर्म में होती है. इसका कंप्रेशन लेवल 9 होता है और दूसरी फ़ाइलों को कंप्रेस किए बिना स्टोर किया जाता है.

चार फ़ाइलें जिनमें एक APEX फ़ाइल शामिल होती है:

  • original_apex: कंप्रेशन लेवल 9 के साथ डिफ़्लेट किया गया यह ओरिजनल, बिना कंप्रेस की गई APEX फ़ाइल है.
  • apex_manifest.pb: सिर्फ़ सेव किया गया
  • AndroidManifest.xml: सिर्फ़ सेव किया गया
  • apex_pubkey: सिर्फ़ सेव किया गया

apex_manifest.pb, AndroidManifest.xml, और apex_pubkey फ़ाइलें, original_apex में मौजूद उनसे जुड़ी फ़ाइलों की कॉपी होती हैं.

कंप्रेस किया गया APEX बनाएं

system/apex/tools पर मौजूद apex_compression_tool.py टूल का इस्तेमाल करके, कंप्रेस किया गया APEX बनाया जा सकता है.

बिल्ड सिस्टम में, 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 पर सेट करके बिल्ड को APEXes को कंप्रेस किया जा सकता है.

बिल्ड सिस्टम से जनरेट की गई कंप्रेस की गई APEX फ़ाइलों में .capex एक्सटेंशन होता है. इस एक्सटेंशन की मदद से, APEX फ़ाइल के कंप्रेस किए गए और कंप्रेस नहीं किए गए वर्शन के बीच आसानी से अंतर किया जा सकता है.

काम करने वाले कंप्रेस करने के एल्गोरिदम

Android 12 पर सिर्फ़ deflate-zip कंप्रेशन की सुविधा काम करती है.

बूट के दौरान कंप्रेस की गई APEX फ़ाइल चालू करें

कंप्रेस की गई APEX फ़ाइल को चालू करने से पहले, इसके अंदर मौजूद original_apex फ़ाइल को /data/apex/decompressed डायरेक्ट्री में डीकंप्रेस किया जाता है. इसके बाद, डिकंप्रेस की गई APEX फ़ाइल को /data/apex/active डायरेक्ट्री से हार्ड-लिंक किया जाता है.

इस उदाहरण को ऊपर बताई गई प्रोसेस के उदाहरण के तौर पर देखें.

/system/apex/com.android.foo.capex को versionCode 37 के साथ कंप्रेस किए गए APEX के तौर पर चालू करने के बारे में सोचें.

  1. /system/apex/com.android.foo.capex में मौजूद original_apex फ़ाइल को /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 पर किया जाता है.

ओटीए के साथ इंटरैक्शन

कंप्रेस की गई APEX फ़ाइलों का असर, ओटीए डिलीवरी और ऐप्लिकेशन पर पड़ता है. ओटीए अपडेट में, संपीड़ित APEX फ़ाइल हो सकती है. यह फ़ाइल, डिवाइस पर चालू वर्शन से ज़्यादा वर्शन लेवल की हो सकती है. इसलिए, ओटीए अपडेट लागू करने के लिए, डिवाइस को रीबूट करने से पहले, कुछ खाली जगह को रिज़र्व रखना ज़रूरी है.

ओटीए सिस्टम के साथ काम करने के लिए, apexd ये दो बाइंडर एपीआई एक्सपोज़र करता है:

  • calculateSizeForCompressedApex - किसी OTA पैकेज में APEX फ़ाइलों को डिकंप्रेस करने के लिए ज़रूरी साइज़ का हिसाब लगाता है. इसका इस्तेमाल यह पुष्टि करने के लिए किया जा सकता है कि OTA डाउनलोड किए जाने से पहले डिवाइस में ज़रूरी जगह है या नहीं.
  • reserveSpaceForCompressedApex - OTA पैकेज में कंप्रेस की गई APEX फ़ाइलों को डीकंप्रेस करने के लिए apexd की मदद से डिस्क पर जगह सुरक्षित रखता है.

A/B ओटीए अपडेट के मामले में, पोस्टइंस्टॉल ओटीए रूटीन के हिस्से के तौर पर, apexd बैकग्राउंड में डीकंप्रेस करने की कोशिश करता है. अगर डिकंप्रेस नहीं हो पाता है, तो apexd, ओटीए अपडेट लागू करने के दौरान डिकंप्रेस करता है.

APEX डेवलप करते समय, इन विकल्पों पर विचार किया जाता है

AOSP ने APEX फ़ाइल फ़ॉर्मैट डिज़ाइन करते समय, इन विकल्पों पर विचार किया था. साथ ही, यह भी बताया है कि इन विकल्पों को शामिल या बाहर क्यों किया गया.

सामान्य पैकेज मैनेजमेंट सिस्टम

Linux डिस्ट्रिब्यूशन में dpkg और rpm जैसे पैकेज मैनेजमेंट सिस्टम होते हैं. ये दमदार, ज़्यादा मज़बूत, और मज़बूत हैं. हालांकि, इन्हें APEX के लिए इस्तेमाल नहीं किया गया, क्योंकि ये इंस्टॉल होने के बाद पैकेज को सुरक्षित नहीं रख सकते. पैकेज इंस्टॉल होने के बाद ही पुष्टि की जाती है. हमलावर, डिवाइस में इंस्टॉल किए गए पैकेज की सुरक्षा को नुकसान पहुंचा सकते हैं, क्योंकि उन्हें पता नहीं चलता. यह Android के लिए एक रिग्रेशन है, जहां सिस्टम के सभी कॉम्पोनेंट, सिर्फ़ पढ़ने के लिए उपलब्ध फ़ाइल सिस्टम में सेव किए गए थे. इनकी पूरी सुरक्षा, हर I/O के लिए dm-verity की मदद से की जाती थी. सिस्टम कॉम्पोनेंट में किसी भी तरह का बदलाव करने पर पाबंदी होनी चाहिए या उसे पता लगाया जा सकता हो, ताकि डिवाइस को बूट होने से रोका जा सके.

डेटा को सुरक्षित रखने के लिए dm-crypt

APEX कंटेनर में मौजूद फ़ाइलें, पहले से मौजूद ऐसे पार्टीशन (उदाहरण के लिए, /system पार्टीशन) से होती हैं जिन्हें dm-verity की मदद से सुरक्षित किया जाता है. यहां पार्टीशन के माउंट होने के बाद भी, फ़ाइलों में कोई बदलाव नहीं किया जा सकता. फ़ाइलों को उसी लेवल की सुरक्षा देने के लिए, APEX की सभी फ़ाइलों को फ़ाइल सिस्टम की इमेज में सेव किया जाता है. इस इमेज को हैश ट्री और vbmeta डिस्क्रिप्टर के साथ जोड़ा जाता है. dm-verity के बिना, /data सेगमेंट में मौजूद APEX कार्ड में, पुष्टि और इंस्टॉल होने के बाद, अनजाने में होने वाले बदलावों का जोखिम हो सकता है.

असल में, /data पार्टिशन को एन्क्रिप्शन लेयर से भी सुरक्षित किया जाता है. जैसे, dm-crypt. हालांकि, इससे डेटा में छेड़छाड़ होने से कुछ हद तक सुरक्षा मिलती है, लेकिन इसका मुख्य मकसद निजता बनाए रखना है, न कि डेटा की सुरक्षा करना. जब कोई हमलावर /data पार्टीशन का ऐक्सेस हासिल कर लेता है, तो उसके लिए कोई और सुरक्षा नहीं की जा सकती. यह फिर से /system पार्टीशन में मौजूद हर सिस्टम कॉम्पोनेंट की तुलना में एक रिग्रेशन है. dm-verity के साथ-साथ APEX फ़ाइल में मौजूद हैश ट्री, कॉन्टेंट को एक ही लेवल पर सुरक्षित रखता है.

/system से /apex पर पाथ रीडायरेक्ट करना

APEX में पैकेज की गई सिस्टम कॉम्पोनेंट फ़ाइलें, /apex/<name>/lib/libfoo.so जैसे नए पाथ से ऐक्सेस की जा सकती हैं. जब फ़ाइलें /system पार्टिशन का हिस्सा थीं, तब उन्हें /system/lib/libfoo.so जैसे पाथ से ऐक्सेस किया जा सकता था. APEX फ़ाइल (दूसरी APEX फ़ाइलें या प्लैटफ़ॉर्म) के क्लाइंट को, नए पाथ का इस्तेमाल करना होगा. पाथ में बदलाव होने की वजह से, आपको मौजूदा कोड को अपडेट करना पड़ सकता है.

हालांकि, पाथ में होने वाले बदलाव से बचने का एक तरीका यह है कि APEX फ़ाइल में मौजूद फ़ाइल के कॉन्टेंट को /system पार्टीशन पर ओवरले किया जाए, लेकिन Android टीम ने /system पार्टिशन में फ़ाइलों को ओवरले नहीं करने का फ़ैसला किया. इसकी वजह यह है कि ओवरलैप होने वाली फ़ाइलों की संख्या (शायद एक के बाद एक स्टैक होने पर) की वजह से परफ़ॉर्मेंस पर असर पड़ सकता है.

फ़ाइल ऐक्सेस करने वाले फ़ंक्शन, जैसे कि open, stat, और readlink को हाइजैक करने का भी विकल्प था. इससे, /system से शुरू होने वाले पाथ को /apex में मौजूद उनके संबंधित पाथ पर रीडायरेक्ट किया जा सकता था. Android टीम ने इस विकल्प को खारिज कर दिया क्योंकि यह पाथ स्वीकार करने वाले सभी फ़ंक्शन में बदलाव नहीं कर सका. उदाहरण के लिए, कुछ ऐप्लिकेशन बायोनिक को स्टैटिक रूप से लिंक करते हैं, जो फ़ंक्शन लागू करता है. ऐसे मामलों में, उन ऐप्लिकेशन को रीडायरेक्ट नहीं किया जाता.