वेंडर APEX

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

वेंडर APEXes को बिल्ड सिस्टम से, /vendor पार्टिशन में अपने-आप इंस्टॉल किया जाता है. साथ ही, इन्हें apexd से रनटाइम पर चालू किया जाता है, जैसे कि अन्य पार्टिशन में APEXes.

इस्तेमाल के उदाहरण

वेंडर इमेज को मॉड्यूलर बनाना

APEXes, वेंडर की इमेज पर सुविधाओं को लागू करने के तरीके को नैचुरल तरीके से बंडल करने और मॉड्यूलराइज़ेशन की सुविधा देता है.

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

उदाहरण के लिए, कोई OEM अपने डिवाइस को AOSP वाई-फ़ाई लागू करने वाले APEX, SoC ब्लूटूथ लागू करने वाले APEX, और कस्टम OEM टेलीफ़ोनी लागू करने वाले APEX के साथ कॉम्पोज़ कर सकता है.

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

HAL लागू करना

HAL लागू करने के बारे में बताने के लिए, इन उदाहरणों जैसे वेंडर APEX में उससे जुड़ी बाइनरी और लाइब्रेरी दें:

HAL लागू करने के तरीके को पूरी तरह से इनकैप्सुलेट करने के लिए, 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 फ़्रैगमेंट जोड़े जाते हैं, तो HAL इंटरफ़ेस और APEX नामों की मैपिंग पाने के लिए, libbinder_ndk एपीआई का इस्तेमाल करें.

  • AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default") : true अगर APEX में HAL इंस्टेंस तय किया गया है.
  • AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...) : को APEX नाम मिलता है, जो HAL इंस्टेंस के बारे में बताता है.
  • 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 का नहीं.

फ़र्मवेयर

उदाहरण:

prebuilt_firmware मॉड्यूल टाइप के साथ वेंडर APEX में फ़र्मवेयर को इस तरह से जोड़ें.

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
  ..
}

APEX की <apex name>/etc/firmware डायरेक्ट्री में prebuilt_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

APEXes के चालू होने से पहले, keymint जैसी एचएएल की कुछ सेवाएं उपलब्ध होनी चाहिए. आम तौर पर, ये एचएएल अपनी सेवा की परिभाषा में, early_hal को init स्क्रिप्ट में सेट करते हैं. एक और उदाहरण animation क्लास है, जो आम तौर पर post-fs-data इवेंट से पहले शुरू की जाती है. जब ऐसी शुरुआती एचएएल सेवा को वेंडर APEX में पैकेज किया जाता है, तो एपेक्स "vendorBootstrap": true को उसके APEX मेनिफ़ेस्ट में बनाएं, ताकि उसे पहले चालू किया जा सके. ध्यान दें कि /vendor/apex जैसी पहले से बनी जगह से ही, बूटस्ट्रैप APEX को चालू किया जा सकता है, /data/apex से नहीं.

सिस्टम प्रॉपर्टी

ये सिस्टम प्रॉपर्टी होती हैं, जिन्हें फ़्रेमवर्क, वेंडर APEXes की मदद करने के लिए पढ़ता है:

  • input_device.config_file.apex=<apex name> - सेट किए जाने पर, इनपुट कॉन्फ़िगरेशन फ़ाइलों (*.idc, *.kl, और *.kcm) को APEX की /etc/usr डायरेक्ट्री से खोजा जाता है.
  • ro.vulkan.apex=<apex name> - सेट होने पर, Vulkan ड्राइवर को APEX से लोड किया जाता है. Vulkan ड्राइवर का इस्तेमाल शुरुआती एचएएल में किया जाता है. इसलिए, APEX Bootstrap APEX को बनाएं और उस लिंकर नेमस्पेस को दिखेगा.

setprop कमांड का इस्तेमाल करके, init स्क्रिप्ट में सिस्टम प्रॉपर्टी सेट करें.

डेवलपमेंट की अतिरिक्त सुविधाएं

बूटअप पर APEX चुनाव

उदाहरण:

डेवलपर, एक ही APEX नाम और कुंजी वाले वेंडर APEX के कई वर्शन भी इंस्टॉल कर सकते हैं. इसके बाद, वे यह चुन सकते हैं कि हर बार बूटअप के दौरान कौनसा वर्शन चालू किया जाए. इसके लिए, वे लगातार काम करने वाले sysprops का इस्तेमाल करते हैं. डेवलपर के इस्तेमाल के कुछ मामलों में, adb install का इस्तेमाल करके APEX की नई कॉपी इंस्टॉल करना आसान हो सकता है.

इस्तेमाल के उदाहरण:

  • वाईफ़ाई एचएएल वेंडर APEX के तीन वर्शन इंस्टॉल करें: क्यूए टीमें, एक वर्शन का इस्तेमाल करके मैन्युअल या ऑटोमेटेड टेस्टिंग कर सकती हैं. इसके बाद, दूसरे वर्शन में रीबूट करके टेस्ट फिर से चला सकती हैं और फिर फ़ाइनल नतीजों की तुलना कर सकती हैं.
  • कैमरा HAL वेंडर APEX, मौजूदा और एक्सपेरिमेंट के तौर पर उपलब्ध के दो वर्शन इंस्टॉल करें: डॉगफ़ूडर, अलग से कोई फ़ाइल डाउनलोड और इंस्टॉल किए बिना ही एक्सपेरिमेंटल वर्शन का इस्तेमाल कर सकते हैं, ताकि वे आसानी से उसे दोबारा खरीद सकें.

बूटअप के दौरान, apexd सही APEX वर्शन को चालू करने के लिए, किसी खास फ़ॉर्मैट के हिसाब से sysprops ढूंढता है.

प्रॉपर्टी की-वर्ड के लिए ये फ़ॉर्मैट इस्तेमाल किए जा सकते हैं:

  • Bootconfig
    • इसका इस्तेमाल, BoardConfig.mk में डिफ़ॉल्ट वैल्यू सेट करने के लिए किया जाता है.
    • androidboot.vendor.apex.<apex name>
  • परसिस्टेंट सिस्टमॉप
    • इसका इस्तेमाल, पहले से चालू हो चुके डिवाइस पर सेट की गई डिफ़ॉल्ट वैल्यू को बदलने के लिए किया जाता है.
    • अगर bootconfig मौजूद है, तो इसकी वैल्यू बदल जाती है.
    • persist.vendor.apex.<apex name>

प्रॉपर्टी की वैल्यू, उस APEX फ़ाइल का नाम होना चाहिए जिसे चालू करना है.

// 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";