Android 10 में, स्टैबल Android इंटरफ़ेस डिफ़िनिशन लैंग्वेज (एआईडीएल) के लिए सहायता जोड़ी गई है. यह एआईडीएल इंटरफ़ेस से मिलने वाले ऐप्लिकेशन प्रोग्रामिंग इंटरफ़ेस (एपीआई) और ऐप्लिकेशन बाइनरी इंटरफ़ेस (एबीआई) को ट्रैक करने का एक नया तरीका है. स्थिर एआईडीएल बिलकुल एआईडीएल की तरह ही काम करता है, लेकिन बिल्ड सिस्टम इंटरफ़ेस को ट्रैक करके उसे सपोर्ट करता है. साथ ही, इस पर कुछ पाबंदियां भी होती हैं कि इनका इस्तेमाल किया जा सकता है:
- इंटरफ़ेस को बिल्ड सिस्टम में
aidl_interfaces
के साथ तय किया जाता है. - इंटरफ़ेस में सिर्फ़ स्ट्रक्चर्ड डेटा शामिल किया जा सकता है. पसंदीदा टाइप दिखाने वाले Parcelables, उनकी AIDL परिभाषा के आधार पर अपने-आप बन जाते हैं. साथ ही, ये अपने-आप मार्शल और अनमार्शल हो जाते हैं.
- इंटरफ़ेस को स्थिर (पुराने सिस्टम के साथ काम करने की सुविधा वाला) के तौर पर घोषित किया जा सकता है. ऐसा होने पर, उनके एपीआई को ट्रैक किया जाता है और AIDL इंटरफ़ेस के बगल में मौजूद फ़ाइल में उसका वर्शन सेव किया जाता है.
स्ट्रक्चर्ड बनाम स्टेबल एआईडीएल
स्ट्रक्चर्ड AIDL का मतलब, पूरी तरह से AIDL में तय किए गए टाइप से है. उदाहरण के लिए, पार्सल किए जा सकने वाले एलान (कस्टम पार्स किया जा सकने वाला एलान) का स्ट्रक्चर एआईडीएल नहीं होना चाहिए. एआईडीएल में तय किए गए फ़ील्ड वाले पार्स किए जा सकने वाले पार्सल को स्ट्रक्चर्ड पार्सल कहा जाता है.
स्टैबल एआईडीएल के लिए, स्ट्रक्चर्ड एआईडीएल की ज़रूरत होती है, ताकि बिल्ड सिस्टम और कंपाइलर यह समझ सकें कि पार्सल किए जा सकने वाले आइटम में किए गए बदलाव, पुराने सिस्टम के साथ काम करते हैं या नहीं.
हालांकि, सभी स्ट्रक्चर्ड इंटरफ़ेस स्थिर नहीं होते. स्थिर रहने के लिए, इंटरफ़ेस में सिर्फ़ स्ट्रक्चर्ड टाइप का इस्तेमाल होना चाहिए. साथ ही, इसमें इन वर्शन की सुविधाओं का भी इस्तेमाल होना चाहिए. इसके उलट, अगर किसी इंटरफ़ेस को बनाने के लिए मुख्य बिल्ड सिस्टम का इस्तेमाल किया गया है या 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
: AIDL इंटरफ़ेस मॉड्यूल का नाम, जो किसी AIDL इंटरफ़ेस की खास पहचान करता है.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_interface
का इंटरफ़ेस या पार्स किया जा सकने वाला इंटरफ़ेस इस्तेमाल किया जाता है, तो उसका नाम यहां डालें. नए वर्शन के बारे में बताने के लिए, यह नाम हो सकता है. इसके अलावा, किसी खास वर्शन के बारे में बताने के लिए, वर्शन के सफ़िक्स (जैसे कि-V1
) का नाम भी हो सकता है. Android 12 से, वर्शन की जानकारी देने की सुविधा उपलब्ध हैversions
: इंटरफ़ेस के पिछले वर्शन, जोapi_dir
में फ़्रीज़ किए गए हैं. Android 11 से,versions
कोaidl_api/name
में फ़्रीज़ किया गया है. अगर किसी इंटरफ़ेस के फ़्रीज़ किए गए वर्शन मौजूद नहीं हैं, तो इसकी जानकारी नहीं दी जानी चाहिए. साथ ही, इसकी जांच भी नहीं की जाएगी कि यह वर्शन, पुराने सिस्टम के साथ काम करता है या नहीं. Android 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
केtrue
होने पर, इस वैल्यू को सेट नहीं करना चाहिए.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 your preference 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
में एक नई एपीआई परिभाषा जोड़ता है. साथ ही, एक .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:
फ़ील्ड के साथ फ़्रीज़ करना ज़रूरी है.
इंपोर्ट होने की स्थिरता
किसी इंटरफ़ेस के फ़्रीज़ किए गए वर्शन के लिए, इंपोर्ट के वर्शन अपडेट करने पर, स्टेबल AIDL लेयर पर बैकवर्ड कम्पैटिबल होता है. हालांकि, इन्हें अपडेट करने के लिए उन सभी सर्वर और क्लाइंट को अपडेट करना पड़ता है जो इंटरफ़ेस के पिछले वर्शन का इस्तेमाल करते हैं. साथ ही, अलग-अलग तरह के वर्शन इस्तेमाल करने पर कुछ ऐप्लिकेशन को भ्रम हो सकता है. आम तौर पर, सिर्फ़ टाइप वाले या सामान्य पैकेज के लिए, यह सुरक्षित होता है. ऐसा इसलिए, क्योंकि आईपीसी ट्रांज़ैक्शन से मिलने वाले अज्ञात टाइप के मामलों को मैनेज करने के लिए, कोड को पहले से लिखा जाना ज़रूरी है.
Android प्लैटफ़ॉर्म कोड में, android.hardware.graphics.common
इस तरह के वर्शन अपग्रेड का सबसे बड़ा उदाहरण है.
वर्शन वाले इंटरफ़ेस का इस्तेमाल करना
इंटरफ़ेस के तरीके
रनटाइम के दौरान, किसी पुराने सर्वर पर नए तरीके कॉल करने पर, नए क्लाइंट को बैकएंड के आधार पर गड़बड़ी या अपवाद मिलता है.
cpp
बैकएंड को::android::UNKNOWN_TRANSACTION
मिलता है.ndk
बैकएंड कोSTATUS_UNKNOWN_TRANSACTION
मिलता है.java
बैकएंड को यह मैसेजandroid.os.RemoteException
मिलता है कि एपीआई लागू नहीं है.
इस समस्या को हल करने की रणनीतियों के लिए, वर्शन के बारे में क्वेरी करना और डिफ़ॉल्ट का इस्तेमाल करना लेख पढ़ें.
पार्स किए जा सकने वाले
जब पार्स किए जा सकने वाले किसी फ़ील्ड में नए फ़ील्ड जोड़े जाते हैं, तो पुराने क्लाइंट और सर्वर उन्हें छोड़ देते हैं. जब नए क्लाइंट और सर्वर को पुराने पार्सल किए जा सकते हैं, तो नए फ़ील्ड की डिफ़ॉल्ट वैल्यू अपने-आप भर जाती हैं. इसका मतलब है कि पार्स किए जा सकने वाले किसी फ़ील्ड में, सभी नए फ़ील्ड के लिए डिफ़ॉल्ट जानकारी देनी होगी.
क्लाइंट को तब तक नए फ़ील्ड का इस्तेमाल करने की उम्मीद नहीं करनी चाहिए, जब तक उन्हें यह पता न हो कि सर्वर उस वर्शन को लागू कर रहा है जिसमें फ़ील्ड तय किया गया है (वर्शन के बारे में क्वेरी करना देखें).
Enums और कॉन्स्टेंट
इसी तरह, क्लाइंट और सर्वर को ऐसी वैल्यू और एनोमेरेटर को अस्वीकार करना चाहिए जिन्हें पहचाना नहीं जा सका है. हालांकि, आने वाले समय में और भी वैल्यू और एनोमेरेटर जोड़े जा सकते हैं. उदाहरण के लिए, किसी ऐसे एन्यूमरेटर को मिलने पर सर्वर को रद्द नहीं किया जाना चाहिए जिसके बारे में उसे पता नहीं है. सर्वर को या तो एनुमरेटर को अनदेखा कर देना चाहिए या उसे कुछ लौटाना चाहिए, ताकि क्लाइंट को पता चल सके कि इस इंप्लिमेंटेशन में यह काम नहीं करता है.
यूनियन
अगर रिसीवर पुराना है और उसे फ़ील्ड के बारे में नहीं पता है,
तो नए फ़ील्ड के साथ यूनियन भेजने की कोशिश नहीं की जा सकती. लागू करने पर, नए फ़ील्ड के साथ यूनियन कभी नहीं दिखेगा. अगर लेन-देन एकतरफा है, तो गड़बड़ी को अनदेखा कर दिया जाता है. अगर ऐसा नहीं है, तो गड़बड़ी BAD_VALUE
(C++ या NDK बैकएंड के लिए) या IllegalArgumentException
(Java बैकएंड के लिए) होती है. यह गड़बड़ी तब मिलती है, जब क्लाइंट नए फ़ील्ड में यूनियन सेट को किसी पुराने सर्वर पर भेज रहा हो या जब कोई पुराना क्लाइंट, नए सर्वर से यूनियन पा रहा हो.
एक से ज़्यादा वर्शन मैनेज करना
Android में लिंकर नेमस्पेस में किसी खास aidl
इंटरफ़ेस का सिर्फ़ एक वर्शन हो सकता है. ऐसा उन स्थितियों से बचने के लिए किया जा सकता है जहां जनरेट किए गए aidl
टाइप की एक से ज़्यादा डेफ़िनिशन हों. C++ में एक परिभाषा वाला नियम है, जिसके तहत हर सिंबल के लिए सिर्फ़ एक परिभाषा की ज़रूरत होती है.
जब कोई मॉड्यूल, एक ही aidl_interface
लाइब्रेरी के अलग-अलग वर्शन पर निर्भर होता है, तो Android बिल्ड गड़बड़ी दिखाता है. हो सकता है कि मॉड्यूल, अपनी डिपेंडेंसी की डिपेंडेंसी के ज़रिए, इन लाइब्रेरी पर सीधे तौर पर या किसी दूसरे तरीके से निर्भर हो. ये गड़बड़ियां, काम न करने वाले मॉड्यूल से लेकर aidl_interface
लाइब्रेरी के उन वर्शन तक के डिपेंडेंसी ग्राफ़ को दिखाती हैं जिनमें अंतर है. इन लाइब्रेरी के एक ही (आम तौर पर नए) वर्शन को शामिल करने के लिए, सभी डिपेंडेंसी को अपडेट करना ज़रूरी है.
अगर इंटरफ़ेस लाइब्रेरी का इस्तेमाल कई अलग-अलग मॉड्यूल करते हैं, तो लाइब्रेरी और प्रोसेस के किसी भी ग्रुप के लिए cc_defaults
, java_defaults
, और rust_defaults
बनाना मददगार हो सकता है. ऐसा तब करना चाहिए, जब लाइब्रेरी और प्रोसेस के सभी ग्रुप को एक ही वर्शन का इस्तेमाल करना हो. इंटरफ़ेस के नए वर्शन को लॉन्च करते समय, डिफ़ॉल्ट वैल्यू को अपडेट किया जा सकता है. साथ ही, उनका इस्तेमाल करने वाले सभी मॉड्यूल को एक साथ अपडेट किया जा सकता है. इससे यह पक्का किया जा सकता है कि वे इंटरफ़ेस के अलग-अलग वर्शन का इस्तेमाल न कर रहे हों.
cc_defaults {
name: "my.aidl.my-process-group-ndk-shared",
shared_libs: ["my.aidl-V3-ndk"],
...
}
cc_library {
name: "foo",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
cc_binary {
name: "bar",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
जब aidl_interface
मॉड्यूल, दूसरे aidl_interface
मॉड्यूल इंपोर्ट करते हैं, तो इससे अतिरिक्त डिपेंडेंसी बनती हैं. इन डिपेंडेंसी के लिए, एक साथ कुछ खास वर्शन का इस्तेमाल करना ज़रूरी होता है. अगर एक ही प्रोसेस में एक से ज़्यादा aidl_interface
मॉड्यूल का इस्तेमाल किया जाता है और उनमें एक जैसे aidl_interface
मॉड्यूल इंपोर्ट किए जाते हैं, तो इस स्थिति को मैनेज करना मुश्किल हो सकता है.
aidl_interfaces_defaults
का इस्तेमाल, aidl_interface
के लिए डिपेंडेंसी के नए वर्शन की एक परिभाषा को एक ही जगह पर अपडेट करने के लिए किया जा सकता है. साथ ही, उस सामान्य इंटरफ़ेस को इंपोर्ट करने वाले सभी aidl_interface
मॉड्यूल इसका इस्तेमाल कर सकते हैं.
aidl_interface_defaults {
name: "android.popular.common-latest-defaults",
imports: ["android.popular.common-V3"],
...
}
aidl_interface {
name: "android.foo",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
aidl_interface {
name: "android.bar",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
शिकायत के आधार पर डेवलपमेंट
जिन इंटरफ़ेस पर काम चल रहा है (जिन्हें फ़्रीज़ नहीं किया गया है) उनका इस्तेमाल रिलीज़ किए गए डिवाइसों पर नहीं किया जा सकता. ऐसा इसलिए, क्योंकि यह पक्का नहीं है कि वे पुराने वर्शन के साथ काम करेंगे.
एआईडीएल, इन अनफ़्रीज़ की गई इंटरफ़ेस लाइब्रेरी के लिए रन टाइम फ़ॉलबैक के साथ काम करता है, ताकि फ़्रोज़न किए गए नए वर्शन के हिसाब से कोड को लिखा जा सके और रिलीज़ डिवाइसों पर भी उसका इस्तेमाल किया जा सके. क्लाइंट का बैकवर्ड-कंपैटिबल व्यवहार, मौजूदा व्यवहार से मिलता-जुलता है. साथ ही, फ़ॉलबैक के साथ, लागू करने की प्रोसेस को भी उन व्यवहारों का पालन करना होगा. वर्शन वाले इंटरफ़ेस इस्तेमाल करना देखें.
एआईडीएल बिल्ड फ़्लैग
इस व्यवहार को कंट्रोल करने वाले फ़्लैग के बारे में build/release/build_flags.bzl
में बताया गया है.RELEASE_AIDL_USE_UNFROZEN
true
का मतलब है कि रन टाइम के दौरान, इंटरफ़ेस के अनफ़्रीज़ किए गए वर्शन का इस्तेमाल किया जाता है. वहीं, false
का मतलब है कि अनफ़्रीज़ किए गए वर्शन की लाइब्रेरी, अपने आखिरी फ़्रीज़ किए गए वर्शन की तरह काम करती हैं.
स्थानीय डेवलपमेंट के लिए, फ़्लैग को true
पर बदला जा सकता है. हालांकि, रिलीज़ करने से पहले, इसे false
पर वापस ले जाना होगा. आम तौर पर, ऐसे कॉन्फ़िगरेशन की मदद से डेवलपमेंट किया जाता है जिसमें फ़्लैग, true
पर सेट होता है.
कंपैटबिलिटी मैट्रिक्स और मेनिफ़ेस्ट
वेंडर इंटरफ़ेस ऑब्जेक्ट (VINTF ऑब्जेक्ट) से पता चलता है कि कौनसे वर्शन ज़रूरी हैं और वेंडर इंटरफ़ेस के दोनों ओर कौनसे वर्शन उपलब्ध कराए जाते हैं.
Cuttlefish के अलावा, ज़्यादातर डिवाइस इंटरफ़ेस फ़्रीज़ होने के बाद ही, काम करने के लिए डिवाइसों के बीच के नए मैट्रिक को टारगेट करते हैं. इसलिए, 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 में, libvintf
में बदलाव किया गया है, ताकि libvintf
की वैल्यू के आधार पर, बिल्ड के समय मेनिफ़ेस्ट फ़ाइलों में बदलाव किया जा सके.RELEASE_AIDL_USE_UNFROZEN
मेनिफ़ेस्ट और मेनिफ़ेस्ट फ़्रैगमेंट से पता चलता है कि कोई सेवा, इंटरफ़ेस का कौनसा वर्शन लागू करती है. इंटरफ़ेस के अनफ़्रीज़ किए गए नए वर्शन का इस्तेमाल करते समय, इस नए वर्शन को दिखाने के लिए मेनिफ़ेस्ट को अपडेट करना ज़रूरी है. जनरेट की गई एआईडीएल लाइब्रेरी में हुए बदलाव को दिखाने के लिए, RELEASE_AIDL_USE_UNFROZEN=false
के हिसाब से मेनिफ़ेस्ट एंट्री में बदलाव किया जाता है.libvintf
वर्शन को, फ़्रीज़ किए गए वर्शन N
से बदलकर, आखिरी फ़्रीज़ किए गए वर्शन N - 1
पर सेट किया गया है. इसलिए, उपयोगकर्ताओं को अपनी हर सेवा के लिए, एक से ज़्यादा मेनिफ़ेस्ट या मेनिफ़ेस्ट फ़्रैगमेंट मैनेज करने की ज़रूरत नहीं होती.
HAL क्लाइंट में हुए बदलाव
HAL क्लाइंट कोड, काम करने वाले हर पुराने फ़्रीज़ किए गए वर्शन के साथ काम करना चाहिए. जब RELEASE_AIDL_USE_UNFROZEN
, false
पर सेट होता है, तो सेवाएं हमेशा फ़्रीज़ किए गए पिछले वर्शन या उससे पहले की तरह दिखती हैं. उदाहरण के लिए, फ़्रीज़ किए गए नए तरीकों को कॉल करने पर UNKNOWN_TRANSACTION
या parcelable
के नए फ़ील्ड की डिफ़ॉल्ट वैल्यू दिखती है. Android फ़्रेमवर्क क्लाइंट, पिछले वर्शन के साथ काम करने चाहिए. हालांकि, यह जानकारी, वेंडर क्लाइंट और पार्टनर के मालिकाना हक वाले इंटरफ़ेस के क्लाइंट के लिए नई है.
एचएएल को लागू करने के तरीके में बदलाव
फ़्लैग-आधारित डेवलपमेंट के मुकाबले, एचएएल डेवलपमेंट में सबसे बड़ा फ़र्क़ यह है कि एचएएल लागू करने के लिए, यह ज़रूरी है कि वह आखिरी फ़्रीज़ किए गए वर्शन के साथ बैकवर्ड कम्पैटिबल हो, ताकि RELEASE_AIDL_USE_UNFROZEN
के false
होने पर वह काम कर सके.
लागू करने और डिवाइस कोड में पिछली सुविधाओं के साथ काम करने की सुविधा को ध्यान में रखना एक नया तरीका है. वर्शन वाले इंटरफ़ेस का इस्तेमाल करना लेख पढ़ें.
आम तौर पर, क्लाइंट और सर्वर के साथ-साथ फ़्रेमवर्क कोड और वेंडर कोड के लिए, बैकवर्ड कम्पैटिबिलिटी से जुड़ी शर्तें एक जैसी होती हैं. हालांकि, इनमें कुछ छोटे अंतर होते हैं, जिनके बारे में आपको पता होना चाहिए. ऐसा इसलिए है, क्योंकि अब एक ही सोर्स कोड (मौजूदा, अनफ़्रीज़ किया गया वर्शन) का इस्तेमाल करने वाले दो वर्शन लागू किए जा रहे हैं.
उदाहरण: किसी इंटरफ़ेस में तीन फ़्रीज़ किए गए वर्शन होते हैं. इंटरफ़ेस को नए तरीके से अपडेट किया गया है. क्लाइंट और सेवा, दोनों को लाइब्रेरी के नए वर्शन 4 का इस्तेमाल करने के लिए अपडेट किया गया है. V4 लाइब्रेरी, इंटरफ़ेस के बिना फ़्रीज़ किए गए वर्शन पर आधारित होती है. इसलिए, यह पिछले फ़्रोज़न वर्शन यानी वर्शन 3 की तरह काम करती है, जब RELEASE_AIDL_USE_UNFROZEN
false
है. साथ ही, यह नए तरीके के इस्तेमाल को रोकता है.
इंटरफ़ेस फ़्रीज़ होने पर, RELEASE_AIDL_USE_UNFROZEN
की सभी वैल्यू उस फ़्रीज़ किए गए वर्शन का इस्तेमाल करती हैं. साथ ही, पुराने वर्शन के साथ काम करने वाले कोड को हटाया जा सकता है.
कॉलबैक पर तरीके कॉल करते समय, आपको UNKNOWN_TRANSACTION
के रिटर्न होने पर, उस स्थिति को सही तरीके से मैनेज करना होगा. रिलीज़ कॉन्फ़िगरेशन के आधार पर, क्लाइंट किसी कॉलबैक के दो अलग-अलग वर्शन लागू कर सकते हैं. इसलिए, यह नहीं माना जा सकता कि क्लाइंट सबसे नया वर्शन भेजता है और नए तरीके इसे दिखा सकते हैं. यह उसी तरह है जिस तरह वर्शन वाले इंटरफ़ेस का इस्तेमाल करें में बताया गया है कि स्टैबल AIDL क्लाइंट, सर्वर के साथ बैकवर्ड कम्पैटिबिलिटी बनाए रखते हैं.
// 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();
}
}
ऐसा हो सकता है कि मौजूदा टाइप (parcelable
, enum
, union
) में नए फ़ील्ड मौजूद न हों या RELEASE_AIDL_USE_UNFROZEN
के false
होने पर, उनमें डिफ़ॉल्ट वैल्यू मौजूद न हों. साथ ही, सेवा की ओर से भेजे जाने वाले नए फ़ील्ड की वैल्यू, प्रोसेस के दौरान हटा दी जाती हैं.
अनफ़्रीज़ किए गए इस वर्शन में जोड़े गए नए टाइप, इंटरफ़ेस के ज़रिए भेजे या पाए नहीं जा सकते.
जब 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()
के साथ एलान किया गया है या नहीं. अगर यह एलान किया गया है और रजिस्ट्रेशन नहीं हो पाया है, तो प्रोसेस को बंद कर दें. अगर इसका एलान नहीं किया गया है, तो हो सकता है कि वह रजिस्टर न हो पाए.
डेवलपमेंट टूल के तौर पर Cuttlefish
VINTF फ़्रीज़ होने के बाद, हम हर साल फ़्रेमवर्क के साथ काम करने वाले डिवाइसों के मैट्रिक (FCM) target-level
और Cuttlefish के 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
है, तो रिलीज़ डिवाइस दिखाने के लिए, Cuttlefish में पिछला 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 बैकएंड के लिए,cpp
C++ बैकएंड के लिए,- NDK बैकएंड के लिए,
ndk
याndk_platform
. पहला, ऐप्लिकेशन के लिए है और दूसरा, Android 13 तक प्लैटफ़ॉर्म के इस्तेमाल के लिए है. Android 13 और उसके बाद के वर्शन में, सिर्फ़ndk
का इस्तेमाल करें. - 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
बन जाता है
आउटपुट फ़ाइलों के नाम हमेशा मॉड्यूल के नामों से मेल खाते हैं.
- पहले वर्शन के आधार पर:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- दूसरे वर्शन के आधार पर:
foo-V2-(cpp|ndk|ndk_platform|rust).so
- ToT वर्शन के आधार पर:
foo-V3-(cpp|ndk|ndk_platform|rust).so
ध्यान दें कि एआईडीएल कंपाइलर, न तो unstable
वर्शन वाला मॉड्यूल बनाता है और न ही स्थिर एआईडीएल इंटरफ़ेस के लिए, बिना वर्शन वाला मॉड्यूल.
Android 12 के बाद, स्थिर AIDL इंटरफ़ेस से जनरेट किए गए मॉड्यूल के नाम में, हमेशा उसका वर्शन शामिल होता है.
नए मेटा इंटरफ़ेस के तरीके
Android 10 में, स्थिर AIDL के लिए कई मेटा इंटरफ़ेस तरीके जोड़े गए हैं.
रिमोट ऑब्जेक्ट के इंटरफ़ेस वर्शन के बारे में क्वेरी करना
क्लाइंट, उस इंटरफ़ेस के वर्शन और हैश के बारे में क्वेरी कर सकते हैं जिसे रिमोट ऑब्जेक्ट लागू कर रहा है. साथ ही, रिटर्न की गई वैल्यू की तुलना, क्लाइंट के इस्तेमाल किए जा रहे इंटरफ़ेस की वैल्यू से की जा सकती है.
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
का इस्तेमाल किया जाता है. javac
कॉन्फ़िगरेशन के आधार पर, चेतावनियां बंद करने के लिए, @SuppressWarnings("static")
एनोटेशन की ज़रूरत पड़ सकती है:
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
है जिसे रेफ़रंस देने पर इनलाइन किया जाता है). इसलिए, यह तरीका उस सटीक वर्शन को दिखा सकता है जिससे सर्वर बनाया गया था.
पुराने इंटरफ़ेस का इस्तेमाल करना
ऐसा हो सकता है कि किसी क्लाइंट को AIDL इंटरफ़ेस के नए वर्शन पर अपडेट किया गया हो, लेकिन सर्वर पुराने AIDL इंटरफ़ेस का इस्तेमाल कर रहा हो. ऐसे मामलों में, किसी पुराने इंटरफ़ेस पर किसी तरीके को कॉल करने पर 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(...);
आपको AIDL इंटरफ़ेस में सभी तरीकों को डिफ़ॉल्ट रूप से लागू करने की ज़रूरत नहीं है. जिन तरीकों के लिए रिमोट साइड में लागू होने की गारंटी होती है उन्हें डिफ़ॉल्ट impl
क्लास में ओवरराइड करने की ज़रूरत नहीं होती. ऐसा इसलिए होता है, क्योंकि आपको यकीन है कि रिमोट को एआईडीएल इंटरफ़ेस की जानकारी में बताए जाने के दौरान ही बनाया गया था.
मौजूदा AIDL को स्ट्रक्चर्ड या स्टेबल AIDL में बदलना
अगर आपके पास कोई मौजूदा AIDL इंटरफ़ेस और उसका इस्तेमाल करने वाला कोड है, तो इंटरफ़ेस को स्टैबल AIDL इंटरफ़ेस में बदलने के लिए, यहां दिए गए निर्देशों का पालन करें.
अपने इंटरफ़ेस की सभी डिपेंडेंसी की पहचान करें. इंटरफ़ेस जिस हर पैकेज पर निर्भर करता है उसके लिए यह तय करें कि पैकेज को स्टैबल एआईडीएल में तय किया गया है या नहीं. अगर तय नहीं है, तो पैकेज को बदलना होगा.
अपने इंटरफ़ेस में मौजूद सभी पार्सल करने लायक आइटम को, स्थिर पार्सल करने लायक आइटम में बदलें. हालांकि, इंटरफ़ेस की फ़ाइलों में कोई बदलाव नहीं किया जा सकता. ऐसा करने के लिए, उनके स्ट्रक्चर को सीधे तौर पर एआईडीएल फ़ाइलों में दिखाएं. इन नए टाइप का इस्तेमाल करने के लिए, मैनेजमेंट क्लास को फिर से लिखना होगा. ऐसा,
aidl_interface
पैकेज (नीचे) बनाने से पहले किया जा सकता है.ऐसा
aidl_interface
पैकेज बनाएं (जैसा कि ऊपर बताया गया है) जिसमें आपके मॉड्यूल का नाम, उसकी डिपेंडेंसी, और ज़रूरत के मुताबिक अन्य जानकारी शामिल हो. डेटा को सिर्फ़ स्ट्रक्चर्ड ही नहीं, बल्कि स्थिर भी बनाया जा सकता है. इसके लिए, डेटा का वर्शन भी बनाना होगा. ज़्यादा जानकारी के लिए, इंटरफ़ेस के वर्शन देखें.