स्थिर एआईडीएल

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

  • इंटरफ़ेस को बिल्ड सिस्टम में aidl_interfaces के साथ तय किया जाता है.
  • इंटरफ़ेस में सिर्फ़ स्ट्रक्चर्ड डेटा हो सकता है. पसंद के टाइप के बारे में बताने वाले पार्सल, एआईडीएल की परिभाषा के आधार पर अपने-आप बन जाते हैं. साथ ही, वे अपने-आप मार्शल और अनमार्शल हो जाते हैं.
  • इंटरफ़ेस को स्टेबल (पुराने वर्शन के साथ काम करने वाले) के तौर पर बताया जा सकता है. ऐसा होने पर, उनके एपीआई को ट्रैक किया जाता है और एआईडीएल इंटरफ़ेस के बगल में मौजूद फ़ाइल में उसका वर्शन बनाया जाता है.

स्ट्रक्चर्ड बनाम स्टेबल एआईडीएल

स्ट्रक्चर्ड एआईडीएल का मतलब ऐसे टाइप से है जिन्हें पूरी तरह से एआईडीएल में बताया गया है. उदाहरण के लिए, पार्स किए जा सकने वाले एलान (कस्टम पार्स किया जा सकने वाला एलान) स्ट्रक्चर्ड एआईडीएल नहीं है. एआईडीएल में तय किए गए फ़ील्ड वाले पार्स किए जा सकने वाले पार्सल को स्ट्रक्चर्ड पार्सल कहा जाता है.

स्टेबल एआईडीएल को स्ट्रक्चर्ड एआईडीएल की ज़रूरत होती है, ताकि बिल्ड सिस्टम और कंपाइलर यह समझ सकें कि पार्स किए जा सकने वाले कोड में किए गए बदलाव पुराने सिस्टम के साथ काम करते हैं या नहीं. हालांकि, सभी स्ट्रक्चर्ड इंटरफ़ेस स्टेबल नहीं होते. स्थिर रहने के लिए, इंटरफ़ेस में सिर्फ़ स्ट्रक्चर्ड टाइप का इस्तेमाल होना चाहिए. साथ ही, इसमें नीचे दी गई वर्शन की सुविधाओं का भी इस्तेमाल होना चाहिए. इसके उलट, अगर किसी इंटरफ़ेस को बनाने के लिए मुख्य बिल्ड सिस्टम का इस्तेमाल किया गया है या unstable:true सेट है, तो वह स्थिर नहीं होता.

AIDL इंटरफ़ेस तय करना

aidl_interface की परिभाषा इस तरह दिखती है:

aidl_interface {
    name: "my-aidl",
    srcs: ["srcs/aidl/**/*.aidl"],
    local_include_dir: "srcs/aidl",
    imports: ["other-aidl"],
    versions_with_info: [
        {
            version: "1",
            imports: ["other-aidl-V1"],
        },
        {
            version: "2",
            imports: ["other-aidl-V3"],
        }
    ],
    stability: "vintf",
    backend: {
        java: {
            enabled: true,
            platform_apis: true,
        },
        cpp: {
            enabled: true,
        },
        ndk: {
            enabled: true,
        },
        rust: {
            enabled: true,
        },
    },

}
  • name: एआईडीएल इंटरफ़ेस मॉड्यूल का नाम, जो किसी एआईडीएल इंटरफ़ेस की खास तौर पर पहचान करता है.
  • srcs: इंटरफ़ेस बनाने वाली AIDL सोर्स फ़ाइलों की सूची. com.acme पैकेज में बताए गए AIDL टाइप Foo का पाथ, <base_path>/com/acme/Foo.aidl पर होना चाहिए. यहां <base_path>, Android.bp वाली डायरेक्ट्री से जुड़ी कोई भी डायरेक्ट्री हो सकती है. ऊपर दिए गए उदाहरण में, <base_path>, srcs/aidl है.
  • local_include_dir: वह पाथ जहां से पैकेज का नाम शुरू होता है. यह ऊपर बताए गए <base_path> के मुताबिक है.
  • imports: aidl_interface मॉड्यूल की सूची जिनका यह इस्तेमाल किया जाता है. अगर आपके किसी AIDL इंटरफ़ेस में ऐसे इंटरफ़ेस का इस्तेमाल किया जाता है जिसे दूसरे aidl_interface से पार्स किया जा सकता है, तो उसका नाम यहां डालें. नए वर्शन के बारे में बताने के लिए, यह नाम हो सकता है. इसके अलावा, किसी खास वर्शन के बारे में बताने के लिए, वर्शन के सफ़िक्स (जैसे कि -V1) वाला नाम भी हो सकता है. यह तय करने की सुविधा कि Android 12 और इसके बाद के वर्शन
  • versions: इंटरफ़ेस के पिछले वर्शन जो api_dir में फ़्रीज़ किए गए हैं और Android 11 की शुरुआत से, versions को aidl_api/name में फ़्रीज़ किया गया है. अगर किसी इंटरफ़ेस का कोई फ़्रोज़न वर्शन नहीं है, तो इसे बताना नहीं चाहिए. साथ ही, इसके काम करने के तरीके की जांच भी नहीं की जाएगी. इस फ़ील्ड को 13 और उससे आगे के वर्शन के लिए, versions_with_info से बदल दिया गया है.
  • versions_with_info: टुपल की सूची, जिसमें हर एक में फ़्रीज़ किए गए वर्शन का नाम होता है. साथ ही, एक सूची भी होती है, जिसमें aidl_interface के इस वर्शन से इंपोर्ट किए गए अन्य aidl_interface मॉड्यूल के वर्शन की जानकारी होती है. AIDL इंटरफ़ेस IFACE के वर्शन V की परिभाषा aidl_api/IFACE/V पर दी गई है. यह फ़ील्ड Android 13 में आया था. इसे सीधे Android.bp में नहीं बदलना चाहिए था. *-update-api या *-freeze-api को चालू करके, इस फ़ील्ड को जोड़ा या अपडेट किया जाता है. साथ ही, जब कोई उपयोगकर्ता *-update-api या *-freeze-api शुरू करता है, तो versions फ़ील्ड अपने-आप versions_with_info पर माइग्रेट हो जाता है.
  • stability: इस इंटरफ़ेस की स्थिरता का वादा करने के लिए वैकल्पिक फ़्लैग. फ़िलहाल, यह सुविधा सिर्फ़ "vintf" के साथ काम करती है. अगर stability सेट नहीं है, तो बिल्ड सिस्टम यह जांच करता है कि इंटरफ़ेस पुराने सिस्टम के साथ काम करता है या नहीं. ऐसा तब तक होगा, जब तक unstable न सेट किया गया हो. सेट नहीं होने पर, इस कंपाइलेशन कॉन्टेक्स्ट में स्थायित्व वाले इंटरफ़ेस से मेल खाता है (इसलिए, सिस्टम की सभी चीज़ें, system.img और इससे जुड़े पार्टिशन में इंस्टेंस की चीज़ों के लिए या सभी वेंडर चीज़ों, जैसे कि vendor.img और इससे जुड़े पार्टिशन में मौजूद चीज़ें). अगर stability को "vintf" पर सेट किया गया है, तो इसका मतलब है कि स्थिरता प्रॉमिस: जब तक इंटरफ़ेस का इस्तेमाल किया जाता है, तब तक उसे स्थिर रखना चाहिए.
  • gen_trace: ट्रेस करने की सुविधा को चालू या बंद करने के लिए, वैकल्पिक फ़्लैग. Android 14 से, cpp और java बैकएंड के लिए डिफ़ॉल्ट तौर पर true है.
  • host_supported: यह वैकल्पिक फ़्लैग true पर सेट करने से, जनरेट की गई लाइब्रेरी को होस्ट एनवायरमेंट के लिए उपलब्ध कराता है.
  • unstable: वह वैकल्पिक फ़्लैग जिसका इस्तेमाल यह बताने के लिए किया जाता है कि इस इंटरफ़ेस का स्थिर होना ज़रूरी नहीं है. इसे true पर सेट करने पर बिल्ड सिस्टम, इंटरफ़ेस के लिए न तो एपीआई डंप बनाता है और न ही उसे अपडेट करने की ज़रूरत होती है.
  • frozen: जब यह वैकल्पिक फ़्लैग true पर सेट किया जाता है, तो इसका मतलब है कि इंटरफ़ेस के पिछले वर्शन के बाद से इंटरफ़ेस में कोई बदलाव नहीं हुआ है. इससे, ज़्यादा बिल्ड-टाइम चेक की सुविधा मिलती है. अगर इसे false पर सेट किया जाता है, तो इसका मतलब है कि इंटरफ़ेस पर अभी काम चल रहा है और इसमें नए बदलाव किए गए हैं. इसलिए, foo-freeze-api को चलाने पर एक नया वर्शन जनरेट होगा और इसकी वैल्यू अपने-आप true हो जाएगी. Android 14 में पेश किया गया.
  • backend.<type>.enabled: ये फ़्लैग, हर उस बैकएंड को टॉगल करते हैं जिसके लिए एआईडीएल कंपाइलर कोड जनरेट करता है. फ़िलहाल, इन चार बैकएंड का इस्तेमाल किया जा सकता है: Java, C++, NDK, और Rust. डिफ़ॉल्ट रूप से, Java, C++, और NDK बैकएंड चालू होते हैं. अगर इन तीनों में से किसी भी बैकएंड की ज़रूरत नहीं है, तो उसे साफ़ तौर पर बंद करना होगा. Android 15 (एओएसपी एक्सपेरिमेंट के तौर पर उपलब्ध) तक, Rust की सुविधा डिफ़ॉल्ट रूप से बंद रहती है.
  • backend.<type>.apex_available: उन APEX नामों की सूची जिनके लिए जनरेट की गई स्टब लाइब्रेरी उपलब्ध है.
  • backend.[cpp|java].gen_log: वह वैकल्पिक फ़्लैग जो यह कंट्रोल करता है कि लेन-देन की जानकारी इकट्ठा करने के लिए, अतिरिक्त कोड जनरेट करना है या नहीं.
  • backend.[cpp|java].vndk.enabled: इस इंटरफ़ेस को VNDK का हिस्सा बनाने के लिए, वैकल्पिक फ़्लैग. डिफ़ॉल्ट वैल्यू false है.
  • backend.[cpp|ndk].additional_shared_libraries: Android 14 में पेश किया गया यह फ़्लैग, नेटिव लाइब्रेरी में डिपेंडेंसी जोड़ता है. यह फ़्लैग ndk_header और cpp_header के लिए काम का है.
  • backend.java.sdk_version: SDK टूल के उस वर्शन के बारे में बताने के लिए वैकल्पिक फ़्लैग जिसके लिए Java स्टब लाइब्रेरी बनाई गई है. डिफ़ॉल्ट वैल्यू "system_current" है. इसे तब सेट नहीं किया जाना चाहिए, जब backend.java.platform_apis सही हो.
  • backend.java.platform_apis: यह वैकल्पिक फ़्लैग है. इसे तब true पर सेट किया जाना चाहिए, जब जनरेट की गई लाइब्रेरी को SDK टूल के बजाय प्लैटफ़ॉर्म एपीआई के ज़रिए बनाना हो.

वर्शन के हर कॉम्बिनेशन और चालू बैकएंड के लिए, एक स्टब लाइब्रेरी बनाई जाती है. किसी खास बैकएंड के लिए, स्टब लाइब्रेरी के खास वर्शन का हवाला देने का तरीका जानने के लिए, मॉड्यूल का नाम रखने के नियम देखें.

एआईडीएल फ़ाइलें लिखी जा रही हैं

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

// in a file like 'some/package/Thing.aidl'
package some.package;

parcelable SubThing {
    String a = "foo";
    int b;
}

फ़िलहाल, boolean, char, float, double, byte, int, long, और String के लिए डिफ़ॉल्ट तरीका काम करता है. हालांकि, यह ज़रूरी नहीं है. Android 12 में, उपयोगकर्ता की ओर से तय की गई गिनती के लिए डिफ़ॉल्ट सेटिंग भी काम करती है. जब कोई डिफ़ॉल्ट वैल्यू तय नहीं की गई हो, तो 0-लाइक या खाली वैल्यू का इस्तेमाल किया जाता है. बिना किसी डिफ़ॉल्ट वैल्यू वाली इन्यूमरेशन को 0 से शुरू किया जाता है. भले ही, शून्य एन्यूमरेटर न हो.

स्टब लाइब्रेरी का इस्तेमाल करना

अपने मॉड्यूल के लिए डिपेंडेंसी के तौर पर स्टब लाइब्रेरी जोड़ने के बाद, उन्हें अपनी फ़ाइलों में शामिल किया जा सकता है. यहां बिल्ड सिस्टम में स्टब लाइब्रेरी के उदाहरण दिए गए हैं (लेगसी मॉड्यूल की परिभाषाओं के लिए भी Android.mk का इस्तेमाल किया जा सकता है):

cc_... {
    name: ...,
    shared_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // can also be shared_libs if desire is to load a library and share
    // it among multiple users or if you only need access to constants
    static_libs: ["my-module-name-java"],
    ...
}
# or
rust_... {
    name: ...,
    rustlibs: ["my-module-name-rust"],
    ...
}

C++ में उदाहरण:

#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
    // use just like traditional AIDL

Java में उदाहरण:

import some.package.IFoo;
import some.package.Thing;
...
    // use just like traditional AIDL

Rust में उदाहरण:

use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
    // use just like traditional AIDL

वर्शन बनाने के लिए इंटरफ़ेस

foo नाम के साथ किसी मॉड्यूल का एलान करने से बिल्ड सिस्टम में भी एक टारगेट बन जाता है. इसका इस्तेमाल मॉड्यूल के एपीआई को मैनेज करने के लिए किया जा सकता है. foo-freeze-api के बनाए जाने पर, वह Android वर्शन के आधार पर api_dir या aidl_api/name में एक नई API परिभाषा जोड़ता है. साथ ही, एक .hash फ़ाइल जोड़ देता है, जो इंटरफ़ेस के नए फ़्रीज़ किए गए वर्शन को दिखाती है. foo-freeze-api को वर्शन के दूसरे वर्शन और imports को दिखाने के लिए, versions_with_info प्रॉपर्टी को भी अपडेट करता है. दरअसल, versions_with_info में मौजूद imports को imports फ़ील्ड से कॉपी किया जाता है. हालांकि, इंपोर्ट के लिए versions_with_info में imports में नए स्टेबल वर्शन की जानकारी दी गई है, जिसका कोई अश्लील वर्शन नहीं है. versions_with_info प्रॉपर्टी तय हो जाने के बाद, बिल्ड सिस्टम फ़्रीज़ किए गए वर्शन के साथ-साथ टॉप ऑफ़ ट्री (टीओटी) और सबसे नए फ़्रीज़ किए गए वर्शन के बीच भी जांच करता है.

इसके अलावा, आपको ToT वर्शन की एपीआई डेफ़िनिशन को भी मैनेज करना होगा. जब भी कोई एपीआई अपडेट किया जाए, तो अपडेट करने के लिए foo-update-api को चलाएं.aidl_api/name/current इसमें ToT वर्शन की एपीआई डेफ़िनिशन शामिल है.

इंटरफ़ेस को एक जैसा बनाए रखने के लिए, मालिक इसमें ये नई चीज़ें जोड़ सकते हैं:

  • इंटरफ़ेस के अंत तक के तरीके या साफ़ तौर पर तय किए गए नए क्रमों वाले मेथड
  • पार्स किए जा सकने वाले एलिमेंट के आखिर में मौजूद एलिमेंट (हर एलिमेंट के लिए डिफ़ॉल्ट तौर पर जोड़ा जाना ज़रूरी है)
  • कॉन्स्टेंट वैल्यू
  • Android 11 में एन्यूमरेटर
  • Android 12 में, यूनियन के आखिर तक के फ़ील्ड

कोई अन्य कार्रवाई करने की अनुमति नहीं है और कोई भी अन्य व्यक्ति इंटरफ़ेस में बदलाव नहीं कर सकता (ऐसा न करने पर, मालिक के किए गए बदलावों से टकराव का खतरा हो सकता है).

सभी इंटरफ़ेस रिलीज़ करने के लिए फ़्रीज़ किए गए हैं या नहीं, इसकी जांच करने के लिए, यहां दिए गए एनवायरमेंट वैरिएबल सेट का इस्तेमाल करके बनाएं:

  • AIDL_FROZEN_REL=true m ... - बिल्ड के लिए ऐसे सभी एआईडीएल इंटरफ़ेस को फ़्रीज़ करना ज़रूरी है जिनमें कोई owner: फ़ील्ड न हो.
  • AIDL_FROZEN_OWNERS="aosp test" - बिल्ड के लिए सभी स्थायी AIDL इंटरफ़ेस को "aosp" या "test" के तौर पर दिए गए owner: फ़ील्ड के साथ फ़्रीज़ करना ज़रूरी है.

इंपोर्ट होने की स्थिरता

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

Android प्लैटफ़ॉर्म कोड में android.hardware.graphics.common, इस तरह के वर्शन अपग्रेड का सबसे बड़ा उदाहरण है.

वर्शन वाले इंटरफ़ेस का इस्तेमाल करना

इंटरफ़ेस के तरीके

रनटाइम के दौरान, किसी पुराने सर्वर पर नए तरीकों को कॉल करने की कोशिश करते समय, नए क्लाइंट को बैकएंड के आधार पर कोई गड़बड़ी या अपवाद मिलता है.

  • cpp बैकएंड को ::android::UNKNOWN_TRANSACTION मिलता है.
  • ndk बैकएंड को STATUS_UNKNOWN_TRANSACTION मिलता है.
  • java बैकएंड को यह मैसेज android.os.RemoteException मिलता है कि एपीआई लागू नहीं है.

इसे मैनेज करने की रणनीतियों के लिए, क्वेरी वर्शन और डिफ़ॉल्ट इस्तेमाल देखें.

पार्स किए जा सकने वाले

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

क्लाइंट को यह उम्मीद नहीं करनी चाहिए कि सर्वर तब तक नए फ़ील्ड का इस्तेमाल करेंगे, जब तक उन्हें पता न हो कि सर्वर उस वर्शन को लागू कर रहा है जिसमें फ़ील्ड तय किया गया है (क्वेरी वर्शन देखें).

Enum और कॉन्सटेंट

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

यूनियन

अगर पाने वाला पुराना है और उसे फ़ील्ड के बारे में नहीं पता है, तो नए फ़ील्ड के साथ यूनियन भेजने की कोशिश नहीं की जा सकती. लागू करने पर, कभी भी नए फ़ील्ड के साथ यूनियन नहीं दिखेगा. अगर यह एकतरफ़ा ट्रांज़ैक्शन है, तो इसे अनदेखा कर दिया जाता है. ऐसा न होने पर, BAD_VALUE(C++ या NDK बैकएंड के लिए) गड़बड़ी होती है. इसके अलावा, IllegalArgumentException(Java बैकएंड के लिए) में भी गड़बड़ी होती है. गड़बड़ी तब मिलती है, जब क्लाइंट नए फ़ील्ड में यूनियन सेट को किसी पुराने सर्वर पर भेज रहा हो या जब कोई पुराना क्लाइंट, नए सर्वर से यूनियन को नए फ़ील्ड में ले रहा हो.

फ़्लैग-आधारित डेवलपमेंट

रिलीज़ डिवाइसों पर इन-डेवलपमेंट (अनफ़्रीज़ किए गए) इंटरफ़ेस इस्तेमाल नहीं किए जा सकते, क्योंकि वे पुराने सिस्टम के साथ काम करने की गारंटी नहीं देते.

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

एआईडीएल बिल्ड फ़्लैग

इस व्यवहार को कंट्रोल करने वाले फ़्लैग को build/release/build_flags.bzl में RELEASE_AIDL_USE_UNFROZEN बताया गया है. true का मतलब है कि रन टाइम के दौरान, इंटरफ़ेस के फ़्रीज़ न किए गए वर्शन का इस्तेमाल किया जाता है और false का मतलब है कि बिना फ़्रीज़ किए गए वर्शन की लाइब्रेरी, अपने पिछले फ़्रीज वर्शन की तरह काम करती हैं. लोकल डेवलपमेंट के लिए, फ़्लैग को true में बदला जा सकता है. हालांकि, रिलीज़ से पहले इसे वापस false में सेट करना होगा. आम तौर पर, डेवलपमेंट ऐसे कॉन्फ़िगरेशन की मदद से किया जाता है जिसमें फ़्लैग, true पर सेट होता है.

कंपैटबिलिटी मैट्रिक्स और मेनिफ़ेस्ट

वेंडर इंटरफ़ेस ऑब्जेक्ट (VINTF ऑब्जेक्ट) से यह तय होता है कि कौनसे वर्शन होने चाहिए और वेंडर इंटरफ़ेस के दोनों ओर दिए गए वर्शन कौनसे हैं.

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

मैट्रिसेस

पार्टनर के मालिकाना हक वाले इंटरफ़ेस, डिवाइस या किसी प्रॉडक्ट के साथ काम करने वाले ऐसे मैट्रिक्स में जोड़े जाते हैं जिसे डिवाइस, डेवलपमेंट के दौरान टारगेट करता है. इसलिए, जब कंपैटबिलिटी मैट्रिक्स में किसी इंटरफ़ेस का नया और फ़्रीज़ न किया गया वर्शन जोड़ा जाता है, तो पिछले फ़्रीज़ किए गए वर्शन RELEASE_AIDL_USE_UNFROZEN=false के लिए बने रहने चाहिए. इसे मैनेज करने के लिए, RELEASE_AIDL_USE_UNFROZEN के अलग-अलग कॉन्फ़िगरेशन के लिए अलग-अलग मैट्रिक्स फ़ाइलों का इस्तेमाल करें. इसके अलावा, एक साथ काम करने वाली मैट्रिक्स फ़ाइल में दोनों वर्शन की अनुमति दी जा सकती है, जिसका इस्तेमाल सभी कॉन्फ़िगरेशन में किया जाता है.

उदाहरण के लिए, फ़्रीज़ न किए गए वर्शन 4 को जोड़ते समय, <version>3-4</version> का इस्तेमाल करें.

वर्शन 4 को फ़्रीज़ किए जाने पर, काम करने वाले मैट्रिक्स से वर्शन 3 को हटाया जा सकता है. ऐसा इसलिए किया जा सकता है, क्योंकि RELEASE_AIDL_USE_UNFROZEN के false होने पर, फ़्रीज़ किए गए वर्शन 4 का इस्तेमाल किया जाता है.

मेनिफ़ेस्ट

Android 15 (एओएसपी को एक्सपेरिमेंट के तौर पर शुरू किया गया) 15 में, RELEASE_AIDL_USE_UNFROZEN की वैल्यू के आधार पर बिल्ड के समय मेनिफ़ेस्ट फ़ाइलों में बदलाव करने के लिए, libvintf में बदलाव किया गया है.

मेनिफ़ेस्ट और मेनिफ़ेस्ट फ़्रैगमेंट से यह पता चलता है कि सेवा, इंटरफ़ेस का कौनसा वर्शन लागू करेगी. किसी इंटरफ़ेस के फ़्रीज़ न किए गए नए वर्शन का इस्तेमाल करते समय, इस नए वर्शन को दिखाने के लिए मेनिफ़ेस्ट को अपडेट करना ज़रूरी है. जब जनरेट की गई एआईडीएल लाइब्रेरी में हुए बदलाव को दिखाने के लिए, RELEASE_AIDL_USE_UNFROZEN=false मेनिफ़ेस्ट एंट्री में libvintf बदलाव किया जाता है. इस वर्शन में, फ़्रीज़ नहीं किए गए वर्शन N से लेकर, फ़्रीज़ किए गए पिछले वर्शन N - 1 में बदलाव किया गया है. इसलिए, उपयोगकर्ताओं को अपनी हर सेवा के लिए, एक से ज़्यादा मेनिफ़ेस्ट या मेनिफ़ेस्ट फ़्रैगमेंट मैनेज करने की ज़रूरत नहीं होती.

एचएएल क्लाइंट में किए गए बदलाव

HAL क्लाइंट कोड, पिछले सभी काम करने वाले फ़्रीज़ किए गए वर्शन के साथ पुराने सिस्टम के साथ काम करना चाहिए. जब RELEASE_AIDL_USE_UNFROZEN, false पर सेट होता है, तो सेवाएं हमेशा फ़्रीज़ किए गए पिछले वर्शन या उससे पहले की तरह दिखती हैं. उदाहरण के लिए, फ़्रीज़ किए गए नए तरीकों को कॉल करने पर UNKNOWN_TRANSACTION या नए parcelable फ़ील्ड की डिफ़ॉल्ट वैल्यू दिखती है. यह ज़रूरी है कि Android फ़्रेमवर्क क्लाइंट, पुराने वर्शन के साथ काम करें. हालांकि, वेंडर क्लाइंट और पार्टनर के मालिकाना हक वाले इंटरफ़ेस के क्लाइंट के लिए, यह नई जानकारी है.

एचएएल को लागू करने के तरीके में बदलाव

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

पुराने सिस्टम के साथ काम करने से जुड़ी ज़रूरी शर्तें आम तौर पर क्लाइंट और सर्वर, फ़्रेमवर्क कोड और वेंडर कोड,

उदाहरण: किसी इंटरफ़ेस में तीन फ़्रीज़ किए गए वर्शन होते हैं. इंटरफ़ेस को एक नए तरीके से अपडेट किया गया है. क्लाइंट और सेवा, दोनों को नए वर्शन 4 की लाइब्रेरी का इस्तेमाल करने के लिए अपडेट किया जाता है. V4 लाइब्रेरी, इंटरफ़ेस के बिना फ़्रीज़ किए गए वर्शन पर आधारित होती है. इसलिए, जब RELEASE_AIDL_USE_UNFROZEN false है, तो यह आखिरी फ़्रोज़न वर्शन यानी वर्शन 3 की तरह काम करती है. साथ ही, इसमें नए तरीके के इस्तेमाल पर रोक लगाई जाती है.

जब इंटरफ़ेस फ़्रीज़ होता है, तो RELEASE_AIDL_USE_UNFROZEN की सभी वैल्यू उस रुका हुआ वर्शन का इस्तेमाल करती हैं. साथ ही, पुराने सिस्टम के साथ काम करने की सुविधा को मैनेज करने वाले कोड को हटाया जा सकता है.

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

// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
    mMyCallback = cb;
    // Get the version of the callback for later when we call methods on it
    auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
    return status;
}

// Example of using the callback later
void NotifyCallbackLater() {
  // From the latest frozen version (V2)
  mMyCallback->foo();
  // Call this method from the unfrozen V3 only if the callback is at least V3
  if (mMyCallbackVersion >= 3) {
    mMyCallback->bar();
  }
}

RELEASE_AIDL_USE_UNFROZEN के false होने पर, हो सकता है कि मौजूदा टाइप (parcelable, enum, union) के नए फ़ील्ड मौजूद न हों या उनकी डिफ़ॉल्ट वैल्यू शामिल न हों. प्रोसेस के दौरान, उन नए फ़ील्ड की वैल्यू हटा दी जाती हैं जिन्हें कोई सेवा भेजने की कोशिश करती है.

फ़्रीज़ न किए गए इस वर्शन में जोड़े गए नए टाइप, इंटरफ़ेस से न तो भेजे जा सकते हैं और न ही पाए जा सकते हैं.

RELEASE_AIDL_USE_UNFROZEN के false होने पर, लागू करने की प्रोसेस को कभी भी किसी क्लाइंट से नए तरीकों के लिए कॉल नहीं किया जाता.

नए एन्यूमरेटर का इस्तेमाल सिर्फ़ उसी वर्शन के साथ करें जिसमें उन्हें पेश किया गया है, न कि पिछले वर्शन के साथ.

आम तौर पर, यह देखने के लिए foo->getInterfaceVersion() का इस्तेमाल किया जाता है कि रिमोट इंटरफ़ेस किस वर्शन का इस्तेमाल कर रहा है. हालांकि फ़्लैग-आधारित वर्शन के साथ काम करने पर, आप दो अलग-अलग वर्शन लागू कर रहे हैं, इसलिए हो सकता है कि आप मौजूदा इंटरफ़ेस का वर्शन पाना चाहें. ऐसा करने के लिए, मौजूदा ऑब्जेक्ट का इंटरफ़ेस वर्शन पाएं. उदाहरण के लिए, this->getInterfaceVersion() या my_ver के लिए दूसरे तरीके. ज़्यादा जानकारी के लिए, रिमोट ऑब्जेक्ट के इंटरफ़ेस वर्शन के बारे में क्वेरी करना देखें.

नए VINTF और स्टेबल इंटरफ़ेस

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

डिवाइस मेकफ़ाइल में RELEASE_AIDL_USE_UNFROZEN फ़्लैग की वैल्यू के आधार पर, सेवाओं को कुछ शर्तों के साथ जोड़ा जा सकता है:

ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
    android.hardware.health.storage-service
endif

अगर सेवा किसी बड़ी प्रोसेस का हिस्सा है, तो इसे डिवाइस पर कुछ शर्तों के साथ नहीं जोड़ा जा सकता. ऐसे में, यह देखें कि IServiceManager::isDeclared() के साथ सेवा का एलान किया गया है या नहीं. अगर यह एलान हो चुका है और रजिस्टर नहीं हो पाया है, तो प्रोसेस को रद्द करें. अगर इसका एलान नहीं किया गया है, तो हो सकता है कि यह रजिस्टर न हो पाए.

डेवलपमेंट टूल के तौर पर कटलफ़िश

वीआईएनटीएफ़ के फ़्रीज़ होने के बाद, हर साल हम फ़्रेमवर्क कंपैटबिलिटी मैट्रिक्स (FCM) target-level और कटलफ़िश के PRODUCT_SHIPPING_API_LEVEL में बदलाव करते हैं, ताकि उनमें उन डिवाइसों की जानकारी दिखे जो अगले साल की रिलीज़ के साथ लॉन्च हो रहे हैं. हम target-level और PRODUCT_SHIPPING_API_LEVEL में बदलाव करते हैं, ताकि यह पक्का किया जा सके कि लॉन्च होने वाले कुछ ऐसे डिवाइस मौजूद हों जिनकी जांच की जा चुकी हो और जो अगले साल की रिलीज़ से जुड़ी नई ज़रूरी शर्तों को पूरा करते हों.

जब RELEASE_AIDL_USE_UNFROZEN की उम्र true है, तो आने वाले समय में Android के रिलीज़ होने वाले अपडेट बनाने के लिए, Cuttleफ़िश का इस्तेमाल किया जाएगा. यह अगले साल के Android रिलीज़ के FCM लेवल और PRODUCT_SHIPPING_API_LEVEL को टारगेट करता है. इसके लिए, इसे अगली रिलीज़ की वेंडर सॉफ़्टवेयर से जुड़ी ज़रूरी शर्तों (वीएसआर) को पूरा करना होता है.

जब RELEASE_AIDL_USE_UNFROZEN की वैल्यू false होती है, तब रिलीज़ डिवाइस को दिखाने के लिए, कटलफ़िश के पास पहले से target-level और PRODUCT_SHIPPING_API_LEVEL होते हैं. Android 14 और उससे पहले के वर्शन में, यह अंतर उन Git की अलग-अलग ब्रांच की मदद से पूरा किया जाएगा जिनमें FCM target-level, शिपिंग एपीआई लेवल या अगली रिलीज़ को टारगेट करने वाले किसी भी अन्य कोड में बदलाव नहीं किया जाता.

मॉड्यूल का नाम रखने के नियम

Android 11 में, चालू किए गए वर्शन और बैकएंड के हर कॉम्बिनेशन के लिए, एक स्टब लाइब्रेरी मॉड्यूल अपने-आप बन जाता है. किसी खास स्टब लाइब्रेरी मॉड्यूल को लिंक करने के लिए, aidl_interface मॉड्यूल के नाम का इस्तेमाल न करें. इसके बजाय, स्टब लाइब्रेरी मॉड्यूल के नाम का इस्तेमाल करें, जो कि ifacename-version-backend है, जहां

  • ifacename: aidl_interface मॉड्यूल का नाम
  • version इनमें से कोई एक है
    • फ़्रीज़ किए गए वर्शन के लिए Vversion-number
    • ट्री-ऑफ़-ट्री (अभी-अभी फ़्रोज़न) वर्शन के लिए Vlatest-frozen-version-number + 1
  • backend इनमें से कोई एक है
    • Java बैकएंड के लिए java,
    • C++ बैकएंड के लिए cpp,
    • NDK बैकएंड के लिए, ndk या ndk_platform. पहला विकल्प ऐप्लिकेशन के लिए है और बाद वाला टूल, प्लैटफ़ॉर्म के इस्तेमाल के लिए है.
    • Rust बैकएंड के लिए rust.

मान लें कि foo नाम का एक मॉड्यूल है और उसका सबसे नया वर्शन 2 है. साथ ही, यह NDK और C++ दोनों पर काम करता है. इस मामले में, AIDL ये मॉड्यूल जनरेट करता है:

  • वर्शन 1 के मुताबिक
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • वर्शन 2 (नए स्टेबल वर्शन) के आधार पर
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • ToT वर्शन के हिसाब से
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

Android 11 के मुकाबले,

  • foo-backend, जिसे सबसे नए स्टेबल वर्शन के तौर पर बताया गया है, वह foo-V2-backend हो गई है
  • foo-unstable-backend, जो सेवा की शर्तों (ToT) वर्शन का रेफ़र किया गया है, foo-V3-backend हो जाता है

आउटपुट फ़ाइल के नाम हमेशा मॉड्यूल के नाम जैसे होते हैं.

  • वर्शन 1 पर आधारित: foo-V1-(cpp|ndk|ndk_platform|rust).so
  • वर्शन 2 पर आधारित: foo-V2-(cpp|ndk|ndk_platform|rust).so
  • सेवा की शर्तों (ToT) के वर्शन पर आधारित: foo-V3-(cpp|ndk|ndk_platform|rust).so

ध्यान दें कि एआईडीएल कंपाइलर, न तो unstable वर्शन वाला मॉड्यूल बनाता है और न ही स्थिर एआईडीएल इंटरफ़ेस के लिए, बिना वर्शन वाला मॉड्यूल. Android 12 के बाद से, स्टेबल एआईडीएल इंटरफ़ेस से जनरेट किए गए मॉड्यूल के नाम में हमेशा इसका वर्शन शामिल होता है.

मेटा इंटरफ़ेस की नई विधियां

Android 10 में, स्टेबल एआईडीएल के लिए कई मेटा इंटरफ़ेस मेथड जोड़े गए हैं.

रिमोट ऑब्जेक्ट के इंटरफ़ेस वर्शन की क्वेरी की जा रही है

क्लाइंट, उस इंटरफ़ेस के वर्शन और हैश की क्वेरी कर सकते हैं जिसे रिमोट ऑब्जेक्ट लागू कर रहा है. साथ ही, दिखाई गई वैल्यू की तुलना, क्लाइंट के इस्तेमाल किए गए इंटरफ़ेस की वैल्यू से कर सकते हैं.

cpp बैकएंड के साथ उदाहरण:

sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();

ndk (और ndk_platform) बैकएंड के साथ उदाहरण:

IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
  // the remote side is using an older interface
}

std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);

java बैकएंड के साथ उदाहरण:

IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
  // the remote side is using an older interface
}

String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();

Java की भाषा के लिए, रिमोट साइड को getInterfaceVersion() और getInterfaceHash() को इस तरह से लागू करना होगा (कॉपी करने/चिपकाने से जुड़ी गलतियों से बचने के लिए, IFoo के बजाय super का इस्तेमाल किया जाता है. चेतावनियों को बंद करने के लिए, @SuppressWarnings("static") एनोटेशन की ज़रूरत पड़ सकती है. यह javac कॉन्फ़िगरेशन पर निर्भर करता है:

class MyFoo extends IFoo.Stub {
    @Override
    public final int getInterfaceVersion() { return super.VERSION; }

    @Override
    public final String getInterfaceHash() { return super.HASH; }
}

इसकी वजह यह है कि जनरेट की गई क्लास (IFoo, IFoo.Stub वगैरह) को क्लाइंट और सर्वर के बीच शेयर किया जाता है. उदाहरण के लिए, क्लास बूट क्लास पाथ में हो सकती हैं. जब क्लास शेयर की जाती हैं, तो सर्वर को क्लास के सबसे नए वर्शन से भी लिंक कर दिया जाता है. भले ही, उसे इंटरफ़ेस के किसी पुराने वर्शन की मदद से बनाया गया हो. अगर इस मेटा इंटरफ़ेस को शेयर की गई क्लास में लागू किया जाता है, तो यह हमेशा सबसे नया वर्शन दिखाता है. हालांकि, ऊपर दिए गए तरीके को लागू करने से, इंटरफ़ेस का वर्शन नंबर सर्वर के कोड में एम्बेड हो जाता है (क्योंकि IFoo.VERSION, एक static final int होता है, जिसे रेफ़रंस के दौरान इनलाइन किया जाता है) और इस तरह यह तरीका वही वर्शन दिखा सकता है जिससे सर्वर बनाया गया था.

पुराने इंटरफ़ेस के साथ काम करना

ऐसा हो सकता है कि किसी क्लाइंट को एआईडीएल इंटरफ़ेस के नए वर्शन से अपडेट किया गया हो, लेकिन सर्वर पुराने एआईडीएल इंटरफ़ेस का इस्तेमाल कर रहा हो. ऐसे मामलों में, किसी पुराने इंटरफ़ेस पर किसी तरीके को कॉल करने पर, UNKNOWN_TRANSACTION नतीजा मिलता है.

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

Android 13 और उसके बाद के वर्शन में C++ पर इसका उदाहरण:

class MyDefault : public IFooDefault {
  Status anAddedMethod(...) {
   // do something default
  }
};

// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());

foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
                         // remote side is not implementing it

Java में उदाहरण:

IFoo.Stub.setDefaultImpl(new IFoo.Default() {
    @Override
    public xxx anAddedMethod(...)  throws RemoteException {
        // do something default
    }
}); // once per an interface in a process


foo.anAddedMethod(...);

आपको किसी एआईडीएल इंटरफ़ेस में सभी तरीकों को डिफ़ॉल्ट रूप से लागू करने की सुविधा देने की ज़रूरत नहीं है. जिन तरीकों के लिए रिमोट साइड में लागू होने की गारंटी होती है उन्हें डिफ़ॉल्ट impl क्लास में ओवरराइड करने की ज़रूरत नहीं होती. ऐसा इसलिए होता है, क्योंकि आपको यकीन है कि रिमोट को एआईडीएल इंटरफ़ेस की जानकारी में बताए जाने के दौरान ही बनाया गया था.

मौजूदा एआईडीएल को स्ट्रक्चर्ड/स्टेबल एआईडीएल में बदलना

अगर आपके पास कोई मौजूदा AIDL और ऐसा कोड है जो उसका इस्तेमाल करता है, तो इंटरफ़ेस को स्थिर एआईडीएल इंटरफ़ेस में बदलने के लिए, यहां दिया गया तरीका अपनाएं.

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

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

  3. ऐसा aidl_interface पैकेज बनाएं (जैसा कि ऊपर बताया गया है) जिसमें आपके मॉड्यूल का नाम, उसकी डिपेंडेंसी, और ज़रूरत के मुताबिक अन्य जानकारी शामिल हो. इसे स्टेबलाइज़ करने के लिए (सिर्फ़ स्ट्रक्चर ही नहीं) करने के लिए, इसका वर्शन भी होना चाहिए. ज़्यादा जानकारी के लिए, वर्शन इंटरफ़ेस देखें.