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

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

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

संरचित बनाम स्थिर एआईडीएल

संरचित एआईडीएल विशुद्ध रूप से एआईडीएल में परिभाषित प्रकारों को संदर्भित करता है। उदाहरण के लिए, एक पार्सल योग्य घोषणा (एक कस्टम पार्सल योग्य) संरचित एआईडीएल नहीं है। एआईडीएल में परिभाषित अपने क्षेत्रों के साथ पार्सलेबल्स को संरचित पार्सलेबल्स कहा जाता है।

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

एआईडीएल इंटरफ़ेस को परिभाषित करना

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 : एआईडीएल स्रोत फ़ाइलों की सूची जो इंटरफ़ेस बनाती है। पैकेज 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_interface से एक इंटरफ़ेस या पार्सलेबल का उपयोग करता है, तो उसका नाम यहां रखें। नवीनतम संस्करण को संदर्भित करने के लिए यह स्वयं नाम हो सकता है, या किसी विशिष्ट संस्करण को संदर्भित करने के लिए संस्करण प्रत्यय वाला नाम (जैसे -V1 ) हो सकता है। एंड्रॉइड 12 के बाद से एक संस्करण निर्दिष्ट करने का समर्थन किया गया है
  • versions : इंटरफ़ेस के पिछले संस्करण जो api_dir के अंतर्गत फ़्रीज़ किए गए हैं, Android 11 में प्रारंभ करके, versions aidl_api/ name के अंतर्गत फ़्रीज़ किए गए हैं। यदि इंटरफ़ेस का कोई जमे हुए संस्करण नहीं हैं, तो इसे निर्दिष्ट नहीं किया जाना चाहिए, और संगतता जांच नहीं होगी। इस फ़ील्ड को 13 और उच्चतर के लिए versions_with_info से बदल दिया गया है।
  • versions_with_info : टुपल्स की सूची, जिनमें से प्रत्येक में जमे हुए संस्करण का नाम और अन्य सहायता_इंटरफ़ेस मॉड्यूल के संस्करण आयात के साथ एक सूची शामिल है, जो सहायता_इंटरफ़ेस के इस संस्करण को आयात करता है। 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" का समर्थन करता है। यदि यह सेट नहीं है, तो यह इस संकलन संदर्भ के भीतर स्थिरता वाले इंटरफ़ेस से मेल खाता है (इसलिए यहां लोड किया गया इंटरफ़ेस केवल एक साथ संकलित चीजों के साथ उपयोग किया जा सकता है, उदाहरण के लिए system.img पर)। यदि इसे "vintf" पर सेट किया गया है, तो यह स्थिरता के वादे से मेल खाता है: इंटरफ़ेस को तब तक स्थिर रखा जाना चाहिए जब तक इसका उपयोग किया जाता है।
  • gen_trace : ट्रेसिंग को चालू या बंद करने के लिए वैकल्पिक ध्वज। एंड्रॉइड 14 में प्रारंभ होकर cpp और java बैकएंड के लिए डिफ़ॉल्ट true है।
  • host_supported : वैकल्पिक ध्वज जो true पर सेट होने पर उत्पन्न लाइब्रेरी को होस्ट वातावरण के लिए उपलब्ध कराता है।
  • unstable : वैकल्पिक ध्वज का उपयोग यह चिह्नित करने के लिए किया जाता है कि इस इंटरफ़ेस को स्थिर होने की आवश्यकता नहीं है। जब इसे true पर सेट किया जाता है, तो बिल्ड सिस्टम न तो इंटरफ़ेस के लिए एपीआई डंप बनाता है और न ही इसे अपडेट करने की आवश्यकता होती है।
  • frozen : वैकल्पिक ध्वज जिसे true पर सेट करने का मतलब है कि इंटरफ़ेस में इंटरफ़ेस के पिछले संस्करण के बाद से कोई बदलाव नहीं है। यह अधिक बिल्ड-टाइम जांच सक्षम करता है। जब false पर सेट किया जाता है तो इसका मतलब है कि इंटरफ़ेस विकास में है और इसमें नए बदलाव हैं इसलिए foo-freeze-api चलाने से एक नया संस्करण उत्पन्न होगा और मान स्वचालित रूप से true में बदल जाएगा। एंड्रॉइड 14 में पेश किया गया।
  • backend.<type>.enabled : ये फ़्लैग प्रत्येक बैकएंड को टॉगल करते हैं जिनके लिए एआईडीएल कंपाइलर कोड उत्पन्न करता है। वर्तमान में, चार बैकएंड समर्थित हैं: जावा, सी++, एनडीके और रस्ट। जावा, C++ और NDK बैकएंड डिफ़ॉल्ट रूप से सक्षम हैं। यदि इन तीन बैकएंड में से किसी की भी आवश्यकता नहीं है, तो इसे स्पष्ट रूप से अक्षम करने की आवश्यकता है। जंग डिफ़ॉल्ट रूप से अक्षम है.
  • backend.<type>.apex_available : APEX नामों की सूची जिसके लिए जेनरेट की गई स्टब लाइब्रेरी उपलब्ध है।
  • backend.[cpp|java].gen_log : वैकल्पिक ध्वज जो नियंत्रित करता है कि लेनदेन के बारे में जानकारी इकट्ठा करने के लिए अतिरिक्त कोड उत्पन्न करना है या नहीं।
  • backend.[cpp|java].vndk.enabled : इस इंटरफ़ेस को VNDK का हिस्सा बनाने के लिए वैकल्पिक ध्वज। डिफ़ॉल्ट false है.
  • backend.[cpp|ndk].additional_shared_libraries : एंड्रॉइड 14 में पेश किया गया, यह ध्वज मूल पुस्तकालयों में निर्भरता जोड़ता है। यह ध्वज ndk_header और cpp_header के साथ उपयोगी है।
  • backend.java.sdk_version : एसडीके के उस संस्करण को निर्दिष्ट करने के लिए वैकल्पिक ध्वज जिसके विरुद्ध जावा स्टब लाइब्रेरी बनाई गई है। डिफ़ॉल्ट "system_current" है। जब backend.java.platform_apis सत्य हो तो इसे सेट नहीं किया जाना चाहिए।
  • backend.java.platform_apis : वैकल्पिक ध्वज जिसे तब true पर सेट किया जाना चाहिए जब जेनरेट की गई लाइब्रेरी को एसडीके के बजाय प्लेटफ़ॉर्म एपीआई के विरुद्ध निर्माण करने की आवश्यकता होती है।

संस्करणों और सक्षम बैकएंड के प्रत्येक संयोजन के लिए, एक स्टब लाइब्रेरी बनाई जाती है। किसी विशिष्ट बैकएंड के लिए स्टब लाइब्रेरी के विशिष्ट संस्करण का संदर्भ कैसे लें, इसके लिए मॉड्यूल नामकरण नियम देखें।

एआईडीएल फ़ाइलें लिखना

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

// 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 के लिए एक डिफ़ॉल्ट वर्तमान में समर्थित है (लेकिन आवश्यक नहीं)। एंड्रॉइड 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

जावा में उदाहरण:

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

जंग में उदाहरण:

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

संस्करण इंटरफ़ेस

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

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

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

  • इंटरफ़ेस के अंत तक की विधियाँ (या स्पष्ट रूप से परिभाषित नए धारावाहिकों वाली विधियाँ)
  • पार्सल करने योग्य के अंत में तत्व (प्रत्येक तत्व के लिए एक डिफ़ॉल्ट जोड़ने की आवश्यकता है)
  • निरंतर मूल्य
  • एंड्रॉइड 11 में, गणनाकार
  • Android 12 में, यूनियन के अंत तक फ़ील्ड

किसी भी अन्य कार्रवाई की अनुमति नहीं है, और कोई भी इंटरफ़ेस को संशोधित नहीं कर सकता है (अन्यथा वे मालिक द्वारा किए गए परिवर्तनों के साथ टकराव का जोखिम उठाते हैं)।

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

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

आयात की स्थिरता

इंटरफ़ेस के जमे हुए संस्करणों के लिए आयात के संस्करणों को अद्यतन करना स्थिर एआईडीएल परत पर पिछड़ा संगत है। हालाँकि, इन्हें अपडेट करने के लिए उन सभी सर्वर और क्लाइंट को अपडेट करने की आवश्यकता होती है जो इंटरफ़ेस के पुराने संस्करण का उपयोग करते हैं, और विभिन्न प्रकार के संस्करणों को मिलाते समय कुछ एप्लिकेशन भ्रमित हो सकते हैं। आम तौर पर, केवल-प्रकार या सामान्य पैकेजों के लिए, यह सुरक्षित है क्योंकि आईपीसी लेनदेन से अज्ञात प्रकारों को संभालने के लिए कोड को पहले से ही लिखा जाना आवश्यक है।

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

संस्करणित इंटरफ़ेस का उपयोग करना

इंटरफ़ेस विधियाँ

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

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

इसे संभालने की रणनीतियों के लिए संस्करणों की क्वेरी करना और डिफ़ॉल्ट का उपयोग करना देखें।

पार्सल करने योग्य

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

ग्राहकों को सर्वर से नए फ़ील्ड का उपयोग करने की अपेक्षा नहीं करनी चाहिए जब तक कि उन्हें पता न हो कि सर्वर उस संस्करण को कार्यान्वित कर रहा है जिसमें फ़ील्ड परिभाषित है ( क्वेरी संस्करण देखें)।

गणनाएँ और स्थिरांक

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

यूनियन

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

ध्वज आधारित विकास

इन-डेवलपमेंट (अनफ़्रोज़ेन) इंटरफ़ेस का उपयोग रिलीज़ डिवाइस पर नहीं किया जा सकता है, क्योंकि उनके बैकवर्ड संगत होने की गारंटी नहीं है।

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

एआईडीएल निर्माण ध्वज

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

संगतता मैट्रिक्स और मैनिफ़ेस्ट

विक्रेता इंटरफ़ेस ऑब्जेक्ट (VINTF ऑब्जेक्ट) परिभाषित करते हैं कि कौन से संस्करण अपेक्षित हैं, और विक्रेता इंटरफ़ेस के दोनों ओर कौन से संस्करण प्रदान किए जाते हैं।

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

मैट्रिसेस

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

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

जब संस्करण 4 फ़्रीज़ हो जाता है तो आप संस्करण 3 को संगतता मैट्रिक्स से हटा सकते हैं क्योंकि फ़्रीज़ संस्करण 4 का उपयोग तब किया जाता है जब RELEASE_AIDL_USE_UNFROZEN false है।

प्रकट होता है

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

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

एचएएल क्लाइंट बदलता है

एचएएल क्लाइंट कोड प्रत्येक पिछले समर्थित फ्रोज़न संस्करण के साथ बैकवर्ड संगत होना चाहिए। जब RELEASE_AIDL_USE_UNFROZEN false है तो सेवाएँ हमेशा अंतिम जमे हुए संस्करण या उससे पहले की तरह दिखती हैं (उदाहरण के लिए, नए अनफ्रोज़ेन तरीकों को कॉल करने से UNKNOWN_TRANSACTION वापस आ जाता है, या नए parcelable फ़ील्ड में उनके डिफ़ॉल्ट मान होते हैं)। एंड्रॉइड फ्रेमवर्क क्लाइंट को अतिरिक्त पिछले संस्करणों के साथ बैकवर्ड संगत होना आवश्यक है, लेकिन यह विक्रेता क्लाइंट और पार्टनर-स्वामित्व वाले इंटरफेस के क्लाइंट के लिए एक नया विवरण है।

एचएएल कार्यान्वयन परिवर्तन

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

बैकवर्ड संगतता विचार आम तौर पर क्लाइंट और सर्वर और फ्रेमवर्क कोड और विक्रेता कोड के लिए समान होते हैं, लेकिन सूक्ष्म अंतर होते हैं जिनके बारे में आपको अवगत होना चाहिए, क्योंकि अब आप दो संस्करणों को प्रभावी ढंग से कार्यान्वित कर रहे हैं जो समान स्रोत कोड का उपयोग करते हैं (वर्तमान, बिना जमे हुए संस्करण)।

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

जब इंटरफ़ेस फ़्रीज़ हो जाता है, तो 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 स्थिर इंटरफ़ेस

जब एक नया एआईडीएल इंटरफ़ेस पैकेज जोड़ा जाता है तो कोई अंतिम जमे हुए संस्करण नहीं होता है, इसलिए 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() के साथ घोषित की गई है या नहीं। यदि यह घोषित हो गया है और पंजीकरण करने में विफल रहा है, तो प्रक्रिया को निरस्त कर दें। यदि इसे घोषित नहीं किया गया है, तो इसके पंजीकरण में विफल होने की उम्मीद है।

एक विकास उपकरण के रूप में कटलफिश

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

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

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

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

एंड्रॉइड 11 में, संस्करणों के प्रत्येक संयोजन और सक्षम बैकएंड के लिए, एक स्टब लाइब्रेरी मॉड्यूल स्वचालित रूप से बनाया जाता है। लिंक करने के लिए एक विशिष्ट स्टब लाइब्रेरी मॉड्यूल को संदर्भित करने के लिए, aidl_interface मॉड्यूल के नाम का उपयोग न करें, बल्कि स्टब लाइब्रेरी मॉड्यूल के नाम का उपयोग करें, जो कि ifacename - version - backend है, जहां

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

मान लें कि foo नाम का एक मॉड्यूल है और इसका नवीनतम संस्करण 2 है, और यह NDK और C++ दोनों का समर्थन करता है। इस मामले में, एआईडीएल ये मॉड्यूल तैयार करता है:

  • संस्करण 1 पर आधारित
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • संस्करण 2 पर आधारित (नवीनतम स्थिर संस्करण)
    • foo-V2-(java|cpp|ndk|ndk_platform|rust)
  • टीओटी संस्करण पर आधारित
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

एंड्रॉइड 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 संस्करण मॉड्यूल या स्थिर एआईडीएल इंटरफ़ेस के लिए एक गैर-संस्करण मॉड्यूल नहीं बनाता है। एंड्रॉइड 12 के अनुसार, स्थिर एआईडीएल इंटरफ़ेस से उत्पन्न मॉड्यूल नाम में हमेशा इसका संस्करण शामिल होता है।

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

एंड्रॉइड 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();

जावा भाषा के लिए, दूरस्थ पक्ष को 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

जावा में उदाहरण:

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 वर्ग में ओवरराइड करने की आवश्यकता नहीं है।

मौजूदा एआईडीएल को संरचित/स्थिर एआईडीएल में परिवर्तित करना

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

  1. अपने इंटरफ़ेस की सभी निर्भरताओं को पहचानें। प्रत्येक पैकेज के लिए इंटरफ़ेस निर्भर करता है, यह निर्धारित करें कि पैकेज स्थिर एआईडीएल में परिभाषित है या नहीं। यदि परिभाषित नहीं है, तो पैकेज को परिवर्तित किया जाना चाहिए।

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

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