Android एबीआई

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

  • इस्तेमाल किए जा सकने वाले सीपीयू निर्देशों का सेट (और एक्सटेंशन).
  • मेमोरी स्टोर और रनटाइम के दौरान लोड होने की क्षमता. Android हमेशा लिटिल एंडियन.
  • ऐप्लिकेशन और सिस्टम के बीच डेटा पास करने के तरीके, जिनमें शामिल हैं अलाइनमेंट कंस्ट्रेंट और सिस्टम, स्टैक और फ़ंक्शन को कॉल करने पर रजिस्टर होता है.
  • एक्ज़ीक्यूटेबल बाइनरी का फ़ॉर्मैट, जैसे कि प्रोग्राम और शेयर की गई लाइब्रेरी, किस तरह का कॉन्टेंट इस्तेमाल किया जा सकता है. Android हमेशा ELF का इस्तेमाल करता है. ज़्यादा के लिए जानकारी, देखें ELF सिस्टम V ऐप्लिकेशन बाइनरी इंटरफ़ेस.
  • C++ के नामों को आपस में कैसे बांटा जाता है. ज़्यादा जानकारी के लिए, यह देखें जेनेरिक/इटैनियम C++ एबीआई.

यह पेज उन एबीआई की सूची बनाता है जिनके साथ एनडीके काम करता है. साथ ही, इसमें जानकारी भी दी गई है हर एबीआई के काम करने के तरीके के बारे में जानकारी.

एबीआई, प्लैटफ़ॉर्म पर काम करने वाले नेटिव एपीआई के बारे में भी जानकारी दे सकता है. 32-बिट सिस्टम को प्रभावित करने वाली इस तरह की एबीआई समस्याओं की सूची देखें. 32-बिट एबीआई की गड़बड़ियां.

इस्तेमाल किए जा सकने वाले एबीआई

टेबल 1. एबीआई और काम करने वाले निर्देशों के सेट.

ABI समर्थित निर्देश सेट नोट
armeabi-v7a
  • Armeabi
  • थंब-2
  • नियॉन
  • ARMv5/v6 डिवाइसों के साथ काम नहीं करता.
    arm64-v8a
  • एएर्च64
  • सिर्फ़ Armv8.0.
    x86
  • x86 (IA-32)
  • एमएमएक्स
  • एसएसई/2/3
  • एसएसएसई3
  • MOVBE या SSE4 के लिए कोई समर्थन नहीं है.
    x86_64
  • x86-64
  • एमएमएक्स
  • एसएसई/2/3
  • एसएसएसई3
  • एसएसई4.1, 4.2
  • पीओपीसीएनटी
  • फ़ुल x86-64-v1, लेकिन सिर्फ़ x86-64-v2 के बीच का हिस्सा (सीएमपी या LAHF-SAHF नहीं).

    ध्यान दें: अब तक एनडीके (NDK) इस्तेमाल किया जा सकने वाला ARMv5 इस्तेमाल किया जा रहा था (armeabi), और 32-बिट और 64-बिट MIPS के साथ काम करते हैं, लेकिन इन एबीआई के लिए काम नहीं करता एनडीके r17.

    Armeabi-v7a

    यह एबीआई, 32-बिट ARM सीपीयू के लिए है. इसमें थंब-2 और नियॉन शामिल हैं.

    एबीआई के उन हिस्सों की जानकारी के लिए जो Android के लिए खास नहीं हैं, देखें ARM आर्किटेक्चर के लिए ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई)

    जब तक इस्तेमाल नहीं किया जाता, तब तक एनडीके के बिल्ड सिस्टम थंब-2 कोड को डिफ़ॉल्ट रूप से जनरेट करते हैं इसके लिए, आपके Android.mk में मौजूद LOCAL_ARM_MODE CMake को कॉन्फ़िगर करते समय ndk-build या ANDROID_ARM_MODE का इस्तेमाल करें.

    Neon के इतिहास के बारे में ज़्यादा जानकारी के लिए, Neon Support देखें.

    ऐतिहासिक वजहों से, यह एबीआई, -mfloat-abi=softfp का इस्तेमाल करता है, जिससे सभी float पूर्णांक रजिस्टर में दी जाने वाली वैल्यू और पास की जाने वाली सभी double वैल्यू फ़ंक्शन कॉल करते समय पूर्णांक रजिस्टर जोड़े में. नाम के बावजूद, यह सिर्फ़ फ़्लोटिंग पॉइंट कॉलिंग कन्वेंशन पर असर डालता है: कंपाइलर अब भी अंकगणित के लिए हार्डवेयर फ़्लोटिंग पॉइंट निर्देशों का इस्तेमाल करें.

    यह एबीआई, 64-बिट long double (double की तरह IEEE बाइनरी64) का इस्तेमाल करता है.

    आर्म64-v8a

    यह एबीआई, 64-बिट ARM सीपीयू के लिए है.

    देखें आर्म्स आर्किटेक्चर के बारे में जानें एबीआई के उन हिस्सों की पूरी जानकारी पाएं जो Android के लिए नहीं हैं. ग्रुप में पोर्ट करने से जुड़ी कुछ सलाह भी दी है 64-बिट Android डेवलपमेंट.

    Neon Intrinsics का इस्तेमाल किया जा सकता है C और C++ कोड में भी लिखा जा सकता है. कॉन्टेंट बनाने Armv8-A के लिए नियॉन प्रोग्रामर की गाइड इससे सामान्य तौर पर, नियॉन इंट्रिंसिक्स और नियॉन प्रोग्रामिंग के बारे में ज़्यादा जानकारी मिलती है.

    Android पर, प्लैटफ़ॉर्म के हिसाब से x18 रजिस्टर, शैडोकॉलस्टैक और उसे आपके कोड से छुआ नहीं जाना चाहिए. Clang के मौजूदा वर्शन इस पर डिफ़ॉल्ट रूप से सेट हैं का इस्तेमाल करके Android पर -ffixed-x18 विकल्प का इस्तेमाल किया जा सकता है. असेंबलर (या बहुत पुराना कंपाइलर) के लिए आपको इस बारे में चिंता करने की ज़रूरत नहीं है.

    यह एबीआई, 128-बिट long double (आईईईई बाइनरी128) का इस्तेमाल करता है.

    x86

    यह एबीआई, निर्देश सेट के साथ काम करने वाले सीपीयू के लिए है. आम तौर पर, इसे "x86" कहा जाता है, "i386" या "IA-32".

    Android के एबीआई में, बुनियादी निर्देशों के सेट साथ ही MMX, एसएसई, SSE2, SSE3, और SSSE3 एक्सटेंशन.

    एबीआई में कोई अन्य वैकल्पिक IA-32 निर्देश सेट शामिल नहीं है एक्सटेंशन, जैसे कि MOVBE या SSE4 का कोई भी वैरिएंट. आप तब तक इन एक्सटेंशन का इस्तेमाल कर सकते हैं, जब तक कि आप रनटाइम की सुविधा की जांच के ज़रिए उन्हें चालू करें और उन डिवाइसों के लिए फ़ॉलबैक मुहैया कराएं जिन पर यह सुविधा काम नहीं करती है.

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

    ज़्यादा जानकारी के लिए, ये दस्तावेज़ देखें:

    यह एबीआई, 64-बिट long double (IEEE बाइनरी64) का इस्तेमाल double की तरह करता है, न कि ज़्यादा सामान्य 80-बिट Intel-बिट long double).

    x86_64

    यह एबीआई, निर्देश सेट का इस्तेमाल करने वाले सीपीयू के लिए है. आम तौर पर, इन्हें "x86-64".

    Android के एबीआई में, बुनियादी निर्देशों के सेट साथ ही एमएमएक्स, एसएसई, SSE2, SSE3, एसएसएसई3, SSE4.1, SSE4.2 और POPCNT निर्देश को कॉपी कर सकते हैं.

    एबीआई में कोई अन्य वैकल्पिक x86-64 निर्देश सेट शामिल नहीं है MOVBE, SHA जैसे एक्सटेंशन या AVX का कोई भी वैरिएंट. आप तब तक इन एक्सटेंशन का इस्तेमाल कर सकते हैं, जब तक कि आप रनटाइम की सुविधा के ज़रिए उन्हें चालू करें और उन डिवाइसों के लिए फ़ॉलबैक मुहैया कराएं जिन पर यह सुविधा काम नहीं करती है.

    ज़्यादा जानकारी के लिए, ये दस्तावेज़ देखें:

    यह एबीआई, 128-बिट long double (आईईईई बाइनरी128) का इस्तेमाल करता है.

    किसी खास एबीआई के लिए कोड जनरेट करना

    ग्रेडल

    Gradle (चाहे उसका इस्तेमाल Android Studio से किया जा रहा हो या कमांड लाइन से) डिफ़ॉल्ट रूप से, बंद नहीं होने वाले सभी एबीआई. एबीआई के उस सेट को प्रतिबंधित करने के लिए जिसे आपकी ऐप्लिकेशन समर्थन करता है, तो abiFilters का उपयोग करें. उदाहरण के लिए, 64-बिट एबीआई, अपने build.gradle में यह कॉन्फ़िगरेशन सेट करें:

    android {
        defaultConfig {
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
    }
    

    एनडीके-बिल्ड

    डिफ़ॉल्ट रूप से, सभी बंद एबीआई के लिए ndk-build बिल्ड. आप खास एबीआई के लिए, APP_ABI को अपनी Application.mk फ़ाइल में सेट करके. कॉन्टेंट बनाने नीचे दिया गया स्निपेट APP_ABI के इस्तेमाल के कुछ उदाहरण दिखाता है:

    APP_ABI := arm64-v8a  # Target only arm64-v8a
    APP_ABI := all  # Target all ABIs, including those that are deprecated.
    APP_ABI := armeabi-v7a x86_64  # Target only armeabi-v7a and x86_64.
    

    APP_ABI के लिए तय की जा सकने वाली वैल्यू के बारे में ज़्यादा जानने के लिए, देखें Application.mk.

    सीमेक

    CMake की मदद से, एक बार में एक ही एबीआई के लिए बनाया जा सकता है और आपको एबीआई की जानकारी भी देनी होगी साफ़ तौर पर बताया गया है. आप ऐसा ANDROID_ABI वैरिएबल की मदद से कर सकते हैं, जो कि कमांड लाइन पर दिया गया हो (इसे आपकी CMakeLists.txt में सेट नहीं किया जा सकता). इसके लिए उदाहरण:

    $ cmake -DANDROID_ABI=arm64-v8a ...
    $ cmake -DANDROID_ABI=armeabi-v7a ...
    $ cmake -DANDROID_ABI=x86 ...
    $ cmake -DANDROID_ABI=x86_64 ...
    

    एनडीके के साथ बनाने के लिए सीमेक को भेजे जाने वाले दूसरे फ़्लैग के लिए, देखें CMake गाइड पढ़ें.

    बिल्ड सिस्टम का डिफ़ॉल्ट तरीका हर एबीआई के लिए बाइनरी शामिल करना है जिसे fat APK भी कहते हैं. फ़ैट APK काफ़ी बड़ा होता है से ज़्यादा होनी चाहिए, जिसमें एक एबीआई की बाइनरी ही हो; ट्रेडऑफ़ बढ़ रहा है ज़्यादा वर्शन के साथ काम करता है, लेकिन बड़े APK की वजह से. यह बहुत दिलचस्प है हमारा सुझाव है कि आप इन कामों के लिए, ऐप्लिकेशन बंडल या APK स्प्लिट का इस्तेमाल करें डिवाइस का ज़्यादा से ज़्यादा इस्तेमाल करते हुए, अपने APK का साइज़ कम करें साथ काम करता है.

    इंस्टॉलेशन के समय, पैकेज मैनेजर सबसे सही विकल्प को ही अनपैक करता है टारगेट डिवाइस के लिए मशीन कोड. विवरण के लिए, इसका स्वचालित एक्सट्रैक्शन देखें इंस्टॉल के समय नेटिव कोड.

    Android प्लैटफ़ॉर्म पर एबीआई को मैनेज करना

    इस सेक्शन में बताया गया है कि Android प्लैटफ़ॉर्म, नेटिव विज्ञापनों को कैसे मैनेज करता है APK में कोड बदलने की सुविधा मिलती है.

    ऐप्लिकेशन पैकेज में नेटिव कोड

    Play Store और पैकेज मैनेजर, दोनों को एनडीके से जनरेट किए गए कॉन्टेंट की उम्मीद होती है APK के अंदर फ़ाइल पाथ पर लाइब्रेरी, जो नीचे दिए गए पैटर्न से मेल खाते हैं:

    /lib/<abi>/lib<name>.so
    

    यहां, <abi>, काम करने वाले एबीआई की सूची में शामिल एबीआई के नामों में से एक है, और <name> लाइब्रेरी का नाम है, जैसा कि आपने इसे LOCAL_MODULE के लिए परिभाषित किया था Android.mk फ़ाइल में वैरिएबल. से APK फ़ाइलें सिर्फ़ ज़िप फ़ाइलें हैं, उन्हें खोलना और पुष्टि करना आसान नहीं है कि लाइब्रेरी होती हैं, जहां वे मौजूद होती हैं.

    अगर सिस्टम को नेटिव शेयर की गई लाइब्रेरी नहीं मिलती हैं, जहां इसकी उम्मीद की जाती है, तो यह इस्तेमाल नहीं कर सकता उन्हें. ऐसे मामले में, ऐप्लिकेशन को खुद लाइब्रेरी को dlopen() करें.

    फ़ैट APK में, हर लाइब्रेरी एक डायरेक्ट्री के अंदर होती है जिसका नाम किसी दूसरे एबीआई से मेल खाता है. उदाहरण के लिए, किसी फ़ैट APK में ये चीज़ें शामिल हो सकती हैं:

    /lib/armeabi/libfoo.so
    /lib/armeabi-v7a/libfoo.so
    /lib/arm64-v8a/libfoo.so
    /lib/x86/libfoo.so
    /lib/x86_64/libfoo.so
    

    ध्यान दें: 4.0.3 या इससे पहले के वर्शन वाले ARMv7 पर आधारित Android डिवाइस armeabi-v7a के बजाय, armeabi डायरेक्ट्री से नेटिव लाइब्रेरी इंस्टॉल करें डायरेक्ट्री, अगर दोनों डायरेक्ट्री मौजूद हैं, तो वह भी शामिल हो सकती है. ऐसा इसलिए है, क्योंकि /lib/armeabi/ इसके बाद है APK में मौजूद /lib/armeabi-v7a/. इस समस्या को 4.0.4 से ठीक कर दिया गया है.

    Android प्लैटफ़ॉर्म एबीआई की सुविधा

    Android सिस्टम को रनटाइम के दौरान पता चल जाता है कि वह कौनसे एबीआई के साथ काम करता है, क्योंकि बिल्ड से जुड़े खास सिस्टम प्रॉपर्टी से पता चलता है:

    • डिवाइस का मुख्य एबीआई, जो इसमें इस्तेमाल किए गए मशीन कोड से जुड़ा होता है लागू करता है.
    • विकल्प के तौर पर, दूसरे एबीआई के साथ काम करने वाले दूसरे एबीआई, जो सिस्टम की इमेज से मेल खाते हैं भी समर्थन करता है.

    इस तरीके से यह पक्का होता है कि सिस्टम, इंस्टॉल करते समय पैकेज को ठीक तरह से सेट अप नहीं करना चाहिए.

    सबसे अच्छी परफ़ॉर्मेंस के लिए, आपको सीधे मुख्य एबीआई के लिए कंपाइल करना चाहिए. उदाहरण के लिए, सामान्य ARMv5TE-आधारित डिवाइस में सिर्फ़ मुख्य एबीआई तय होगा: armeabi. इसके उलट, आम तौर पर, ARMv7 पर आधारित डिवाइस, मुख्य एबीआई को armeabi-v7a और दूसरे डिवाइस के तौर पर दिखाता है एक को armeabi के तौर पर इस्तेमाल करना, क्योंकि यह उनमें से हर एक के लिए जनरेट की गई ऐप्लिकेशन वाली स्थानीय बाइनरी चला सकता है.

    64-बिट वाले डिवाइसों पर भी 32-बिट वाले वैरिएंट काम करते हैं. आर्म64-v8a डिवाइसों का इस्तेमाल करना उदाहरण के लिए, डिवाइस armeabi और armeabi-v7a कोड को भी चला सकता है. ध्यान दें, हालांकि, आपका ऐप्लिकेशन 64-बिट वाले डिवाइस पर बेहतर प्रदर्शन करेगा, Areabi-v7a को चलाने वाले डिवाइस पर निर्भर होने के बजाय Arm64-v8a को लक्षित करता है आपके ऐप्लिकेशन का वर्शन.

    x86 पर आधारित कई डिवाइस, armeabi-v7a और armeabi एनडीके बाइनरी भी चला सकते हैं. इसके लिए ऐसे डिवाइसों का मुख्य एबीआई, x86 होगा और दूसरा armeabi-v7a होगा.

    किसी खास एबीआई के लिए, अनइंस्टॉल न किए जा सकने वाले APK को इंस्टॉल किया जा सकता है. यह टेस्ट करने में काम आता है. इस निर्देश का इस्तेमाल करें:

    adb install --abi abi-identifier path_to_apk
    

    इंस्टॉल के समय, नेटिव कोड को अपने-आप एक्सट्रैक्ट करने की सुविधा

    ऐप्लिकेशन इंस्टॉल करते समय, पैकेज मैनेजर सेवा APK को स्कैन करती है और इस फ़ॉर्म की शेयर की गई लाइब्रेरी:

    lib/<primary-abi>/lib<name>.so
    

    अगर कोई नहीं मिलता है और आपने एक दूसरा एबीआई तय किया है, तो सेवा इसकी शेयर की गई लाइब्रेरी को स्कैन करती है फ़ॉर्म:

    lib/<secondary-abi>/lib<name>.so
    

    जब उसे ऐसी लाइब्रेरी मिलती हैं जिसे वह खोज रहा है, तो पैकेज मैनेजर उसे कॉपी कर लेता है उन्हें ऐप्लिकेशन की स्थानीय लाइब्रेरी डायरेक्ट्री के तहत, /lib/lib<name>.so में भेजा जाएगा (<nativeLibraryDir>/). नीचे दिए गए स्निपेट, nativeLibraryDir को फिर से हासिल करते हैं:

    Kotlin

    import android.content.pm.PackageInfo
    import android.content.pm.ApplicationInfo
    import android.content.pm.PackageManager
    ...
    val ainfo = this.applicationContext.packageManager.getApplicationInfo(
            "com.domain.app",
            PackageManager.GET_SHARED_LIBRARY_FILES
    )
    Log.v(TAG, "native library dir ${ainfo.nativeLibraryDir}")
    

    Java

    import android.content.pm.PackageInfo;
    import android.content.pm.ApplicationInfo;
    import android.content.pm.PackageManager;
    ...
    ApplicationInfo ainfo = this.getApplicationContext().getPackageManager().getApplicationInfo
    (
        "com.domain.app",
        PackageManager.GET_SHARED_LIBRARY_FILES
    );
    Log.v( TAG, "native library dir " + ainfo.nativeLibraryDir );
    

    अगर कोई भी शेयर की गई-ऑब्जेक्ट फ़ाइल नहीं है, तो ऐप्लिकेशन बनाता और इंस्टॉल होता है, लेकिन रनटाइम.

    ARMv9: C/C++ के लिए PAC और BTI चालू करना

    PAC/BTI चालू करने से कुछ अटैक वेक्टर से सुरक्षा मिलेगी. PAC किसी फ़ंक्शन के पैरामीटर में क्रिप्टोग्राफ़िक तरीके से हस्ताक्षर करके, रिटर्न पतों को सुरक्षित रखता है प्रोलॉग और यह जांचना कि सामान लौटाने का पता अब भी सही तरीके से साइन इन है एपिलॉग. बीटीआई, आपके कोड में आर्बिट्रेरी लोकेशन पर जाने से रोकता है. इसे इस्तेमाल करने के लिए, कि हर ब्रांच टारगेट एक खास निर्देश है, जो सिर्फ़ आपको प्रोसेसर को वहां ले जाने में कोई समस्या नहीं है.

    Android, PAC/BTI के निर्देशों का इस्तेमाल करता है. ये निर्देश ऐसे पुराने प्रोसेसर पर कुछ नहीं करते जो नए निर्देश लागू नहीं होते. सिर्फ़ ARMv9 डिवाइसों में PAC/BTI होगा सुरक्षा, लेकिन आप उसी कोड को ARMv8 डिवाइसों पर भी चला सकते हैं: अलग-अलग तरह के काम करने की सुविधा मिलती है. ARMv9 डिवाइसों पर भी, सिर्फ़ PAC/BTI लागू होता है 64-बिट कोड पर सेट कर सकते हैं.

    PAC/BTI को चालू करने से, कोड का साइज़ थोड़ा बढ़ जाएगा. आम तौर पर, यह 1% होता है.

    Arm's का आर्किटेक्चर सीखें - उसकी सुरक्षा करना मुश्किल सॉफ़्टवेयर (PDF) ताकि अटैक वेक्टर पीएसी/बीटीआई टारगेट के बारे में ज़्यादा जानकारी मिल सके. साथ ही, सुरक्षा सुविधाएं काम करती हैं.

    बिल्ड में बदलाव करें

    एनडीके-बिल्ड

    अपने Android.mk के हर मॉड्यूल में LOCAL_BRANCH_PROTECTION := standard सेट करें.

    सीमेक

    target_compile_options($TARGET PRIVATE -mbranch-protection=standard) का इस्तेमाल करें अपने CMakeLists.txt में हर टारगेट के लिए, लागू करें.

    अन्य बिल्ड सिस्टम

    -mbranch-protection=standard का इस्तेमाल करके अपना कोड कंपाइल करें. यह फ़्लैग सिर्फ़ काम करता है आर्म64-v8a एबीआई के लिए कंपाइल करते समय इन मामलों में आपको इस फ़्लैग का इस्तेमाल करने की ज़रूरत नहीं है लिंक करना.

    समस्या का हल

    हमें PAC/BTI के लिए कंपाइलर सहायता से जुड़ी किसी समस्या की जानकारी नहीं है, लेकिन:

    • ध्यान रखें कि लिंक करते समय बीटीआई और गैर-बीटीआई कोड को मिलाना न हो, क्योंकि से नतीजे मिलेंगे जिससे ऐसी लाइब्रेरी में नतीजे मिलेंगे जिसमें BTI सुरक्षा चालू नहीं है. Google Analytics 4 पर माइग्रेट करने के लिए, llvm-readelf यह देखने के लिए कि आपकी नतीजे वाली लाइब्रेरी में बीटीआई नोट है या नहीं.
    $ llvm-readelf --notes LIBRARY.so
    [...]
    Displaying notes found in: .note.gnu.property
      Owner                Data size    Description
      GNU                  0x00000010   NT_GNU_PROPERTY_TYPE_0 (property note)
        Properties:    aarch64 feature: BTI, PAC
    [...]
    $
    
    • OpenSSL के पुराने वर्शन (1.1.1i से पहले के वर्शन) में हाथ से लिखे हुए असेंबलर में गड़बड़ी होती है जिसके कारण PAC विफल हो जाता. मौजूदा OpenGL पर अपग्रेड करें.

    • कुछ ऐप्लिकेशन के डीआरएम सिस्टम के पुराने वर्शन, PAC/BTI का उल्लंघन करने वाला कोड जनरेट करते हैं ज़रूरतें. अगर ऐप्लिकेशन के डीआरएम का इस्तेमाल किया जा रहा है और PAC/BTI को चालू करते समय समस्याएं दिखती हैं, ठीक कर दिया गया वर्शन पाने के लिए अपने डीआरएम वेंडर से संपर्क करें.