APEX फ़ाइल फ़ॉर्मैट का इस्तेमाल करके, कम लेवल के Android OS मॉड्यूल को पैकेज और इंस्टॉल किया जा सकता है. इससे नेटिव सेवाओं और लाइब्रेरी, एचएएल लागू करने, फ़र्मवेयर, कॉन्फ़िगरेशन फ़ाइलों वगैरह जैसे कॉम्पोनेंट को अलग से बनाने और इंस्टॉल करने की सुविधा मिलती है.
वेंडर के APEX, बिल्ड सिस्टम की मदद से /vendor
पार्टिशन में अपने-आप इंस्टॉल हो जाते हैं. साथ ही, दूसरे
पार्टिशन में मौजूद APEX की तरह ही, apexd
की मदद से रनटाइम पर चालू हो जाते हैं.
इस्तेमाल के उदाहरण
वेंडर इमेज को मॉड्यूलर बनाना
APEX, वेंडर इमेज पर सुविधाओं को लागू करने के लिए, बंडल करने और मॉड्यूलर बनाने की सुविधा देते हैं.
जब वेंडर इमेज, अलग-अलग वेंडर के बनाए गए APEX के कॉम्बिनेशन के तौर पर बनाई जाती हैं, तो डिवाइस बनाने वाली कंपनियां अपने डिवाइस पर वेंडर के उन खास वर्शन को आसानी से चुन सकती हैं जो उन्हें चाहिए. अगर दिए गए कोई भी एपीईक्स उनकी ज़रूरत के मुताबिक नहीं है या उनके पास बिल्कुल नया कस्टम हार्डवेयर है, तो मैन्युफ़ैक्चरर नया वेंडर एपीईक्स भी बना सकते हैं.
उदाहरण के लिए, कोई OEM अपने डिवाइस को AOSP वाई-फ़ाई लागू करने वाले APEX, SoC ब्लूटूथ लागू करने वाले APEX, और कस्टम OEM टेलीफ़ोनी लागू करने वाले APEX के साथ कंपोज कर सकता है.
वेंडर एपीईक्स के बिना, वेंडर कॉम्पोनेंट के बीच इतनी सारी डिपेंडेंसी के साथ लागू करने के लिए, सावधानी से समन्वय और ट्रैकिंग की ज़रूरत होती है. सभी कॉम्पोनेंट (इनमें कॉन्फ़िगरेशन फ़ाइलें और अतिरिक्त लाइब्रेरी शामिल हैं) को APEX में रैप करके, अलग-अलग कॉम्पोनेंट को एक-दूसरे से बदला जा सकता है. ऐसा, अलग-अलग सुविधाओं के बीच होने वाले किसी भी तरह के कम्यूनिकेशन के दौरान, साफ़ तौर पर तय किए गए इंटरफ़ेस की मदद से किया जा सकता है.
डेवलपर के लिए इटरेटेशन
वेंडर APEX, वेंडर मॉड्यूल को डेवलप करते समय डेवलपर को तेज़ी से बदलाव करने में मदद करते हैं. ऐसा वेंडर 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
जैसी सामान्य लाइब्रेरी को, एचएएल बाइनरी से स्टैटिक तौर पर लिंक किया जा सकता है. एक और विकल्प यह है कि आप किसी स्थिर इंटरफ़ेस को उपलब्ध कराने के लिए, डिपेंडेंसी बनाएं. डिपेंडेंसी को APEX में बंडल नहीं किया जाएगा.
एचएएल लागू करना
एचएएल लागू करने के लिए, वेंडर एपीईक्स में उससे जुड़ी बाइनरी और लाइब्रेरी दें. इन लाइब्रेरी और बाइनरी को इन उदाहरणों की तरह दें:
एचएएल को पूरी तरह से लागू करने के लिए, APEX को काम के सभी VINTF फ़्रैगमेंट और init स्क्रिप्ट की जानकारी भी देनी चाहिए.
VINTF फ़्रैगमेंट
जब फ़्रैगमेंट, APEX के etc/vintf
में मौजूद होते हैं, तो वेंडर APEX से VINTF फ़्रैगमेंट दिखाए जा सकते हैं.
APEX में VINTF फ़्रैगमेंट एम्बेड करने के लिए, prebuilts
प्रॉपर्टी का इस्तेमाल करें.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
क्वेरी एपीआई
जब APEX में VINTF फ़्रैगमेंट जोड़े जाते हैं, तो एचएएल इंटरफ़ेस और APEX के नामों की मैपिंग पाने के लिए, libbinder_ndk
एपीआई का इस्तेमाल करें.
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
अगर एचएएल इंस्टेंस को APEX में तय किया गया है.AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: एपीएक्स का नाम पाता है, जो एचएएल इंस्टेंस की जानकारी देता है.AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: पासथ्रू एचएएल खोलने के लिए, इसका इस्तेमाल करें.
Init स्क्रिप्ट
APEX में इनिट स्क्रिप्ट को दो तरीकों से शामिल किया जा सकता है: (A) APEX पेलोड में पहले से बनी टेक्स्ट फ़ाइल या (B) /vendor/etc
में रेगुलर इनिट स्क्रिप्ट. एक ही APEX के लिए, दोनों को सेट किया जा सकता है.
APEX में init स्क्रिप्ट:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
वेंडर APEX में मौजूद init स्क्रिप्ट में service
परिभाषाएं और
on <property or event>
निर्देश हो सकते हैं.
पक्का करें कि service
डेफ़िनिशन, एक ही APEX में बाइनरी पर ले जाती हो.
उदाहरण के लिए, com.android.foo
APEX, foo-service
नाम की सेवा तय कर सकता है.
on foo-service /apex/com.android.foo/bin/foo
...
on
निर्देशों का इस्तेमाल करते समय सावधानी बरतें. APEX में init स्क्रिप्ट को पार्स और लागू करने के लिए, APEX को चालू करना ज़रूरी है. इसलिए, कुछ इवेंट या प्रॉपर्टी का इस्तेमाल नहीं किया जा सकता. apex.all.ready=true
का इस्तेमाल करके, कार्रवाइयों को जल्द से जल्द ट्रिगर करें.
बूटस्ट्रैप APEX में 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 की <apex name>/etc/firmware
डायरेक्ट्री में इंस्टॉल किए जाते हैं. ueventd
, फ़र्मवेयर मॉड्यूल ढूंढने के लिए /apex/*/etc/firmware
डायरेक्ट्री को स्कैन करता है.
APEX के file_contexts
को फ़र्मवेयर पेलोड की सभी एंट्री को सही तरीके से लेबल करना चाहिए, ताकि यह पक्का किया जा सके कि रनटाइम के दौरान 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
..
}
APEX के file_contexts
को किसी भी कर्नेल मॉड्यूल पेलोड एंट्री को सही तरीके से लेबल करना चाहिए. उदाहरण के लिए:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
कर्नेल मॉड्यूल साफ़ तौर पर इंस्टॉल होने चाहिए. वेंडर पार्टीशन में मौजूद, यहां दी गई उदाहरण वाली init स्क्रिप्ट में, 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 में पहले से बने कॉन्फ़िगरेशन
बूटस्ट्रैप वेंडर APEX
एपीईएक्स चालू होने से पहले, keymint
जैसी कुछ एचएएल सेवाएं उपलब्ध होनी चाहिए. आम तौर पर, ये एचएएल अपनी सेवा की परिभाषा में, early_hal
को init स्क्रिप्ट में सेट करते हैं. animation
क्लास का एक और उदाहरण, जो आम तौर पर post-fs-data
इवेंट से पहले शुरू होती है. जब ऐसी शुरुआती एचएएल सेवा को वेंडर एपीईएक्स में पैकेज किया जाता है, तो उसके एपीईएक्स मेनिफ़ेस्ट में एपेक्स "vendorBootstrap": true
बनाएं, ताकि इसे पहले चालू किया जा सके. ध्यान दें कि /vendor/apex
जैसी पहले से बनी जगह से ही, बूटस्ट्रैप APEX को चालू किया जा सकता है, /data/apex
से नहीं.
सिस्टम प्रॉपर्टी
ये सिस्टम प्रॉपर्टी हैं, जिन्हें वेंडर के APEX को काम करने में मदद करने के लिए फ़्रेमवर्क पढ़ता है:
input_device.config_file.apex=<apex name>
- सेट होने पर, इनपुट कॉन्फ़िगरेशन फ़ाइलों (*.idc
,*.kl
, और*.kcm
) को APEX की/etc/usr
डायरेक्ट्री से खोजा जाता है.ro.vulkan.apex=<apex name>
- सेट होने पर, Vulkan ड्राइवर को APEX से लोड किया जाता है. Vulkan ड्राइवर का इस्तेमाल, शुरुआती एचएएल (हार्डवेयर लेवल एपीआई) करते हैं. इसलिए, APEX को बूटस्ट्रैप APEX बनाएं और लिंकर नेमस्पेस को दिखने के लिए कॉन्फ़िगर करें.
setprop
कमांड का इस्तेमाल करके, init स्क्रिप्ट में सिस्टम प्रॉपर्टी सेट करें.
अन्य सुविधाएं
बूटअप के समय APEX चुनना
उदाहरण:
वेंडर APEX को बूट के दौरान चालू किया जा सकता है. हालांकि, ऐसा करना ज़रूरी नहीं है.
अगर आपने सिस्टम प्रॉपर्टी ro.vendor.apex.<apex name>
का इस्तेमाल करके कोई फ़ाइल नाम तय किया है, तो उस फ़ाइल नाम से मैच करने वाला सिर्फ़ APEX, उस <apex name>
के लिए चालू होगा.
अगर यह सिस्टम प्रॉपर्टी none
पर सेट है, तो <apex name>
वाले APEX को अनदेखा कर दिया जाता है (चालू नहीं किया जाता). इस सुविधा का इस्तेमाल करके, एक ही नाम वाले APEX की कई कॉपी इंस्टॉल की जा सकती हैं. अगर एक ही APEX के कई वर्शन हैं, तो उनमें एक ही पासकोड होना चाहिए.
इस्तेमाल के उदाहरण:
- वाईफ़ाई एचएएल वेंडर APEX के तीन वर्शन इंस्टॉल करें: क्यूए टीमें एक वर्शन का इस्तेमाल करके, मैन्युअल या ऑटोमेटेड टेस्टिंग कर सकती हैं. इसके बाद, दूसरे वर्शन में रीबूट करके टेस्ट फिर से चलाएं और फिर फ़ाइनल नतीजों की तुलना करें.
- कैमरा HAL वेंडर APEX के दो वर्शन इंस्टॉल करें, मौजूदा और प्रयोग के तौर पर उपलब्ध: डॉगफ़ूड करने वाले लोग, किसी अतिरिक्त फ़ाइल को डाउनलोड और इंस्टॉल किए बिना, प्रयोग के तौर पर उपलब्ध वर्शन का इस्तेमाल कर सकते हैं. इससे वे आसानी से वापस बदलाव कर सकते हैं.
बूटअप के दौरान, apexd
सही APEX वर्शन को चालू करने के लिए, किसी खास फ़ॉर्मैट के हिसाब से sysprops ढूंढता है.
प्रॉपर्टी की-वर्ड के लिए ये फ़ॉर्मैट इस्तेमाल किए जा सकते हैं:
- Bootconfig
- इसका इस्तेमाल,
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,
..
}
डिफ़ॉल्ट वर्शन को भी BoardConfig.mk
में, bootconfig का इस्तेमाल करके कॉन्फ़िगर किया जाना चाहिए:
# 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
डिवाइस के बूट होने के बाद, पहले से सेट 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
निर्देशों की मदद से, तो एक से ज़्यादा इंस्टॉल किए गए APEX के लिए bootconfig प्रॉपर्टी में बदलाव करने पर, बूटअप के समय चालू होने वाले वर्शन में भी बदलाव होता है.
Cuttlefish पर आधारित वर्चुअल रेफ़रंस डिवाइसों के लिए, लॉन्च करते समय सीधे तौर पर bootconfig प्रॉपर्टी सेट करने के लिए, --extra_bootconfig_args
कमांड का इस्तेमाल किया जा सकता है. उदाहरण के लिए:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";