Stable AIDL

Android 10, স্থিতিশীল Android ইন্টারফেস ডেফিনিশন ল্যাঙ্গুয়েজ (AIDL)-এর জন্য সহায়তা যোগ করে, এটি হল AIDL ইন্টারফেসের মাধ্যমে প্রদান করা অ্যাপ্লিকেশন প্রোগ্রাম ইন্টারফেস (API) এবং অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (ABI) ট্র্যাক করার একটি নতুন উপায়। স্টেবল AIDL ঠিক AIDL-এর মতোই কাজ করে, তবে বিল্ড সিস্টেম ইন্টারফেসের মানানসই হওয়া ট্র্যাক করে এবং আপনি কী করতে পারবেন তার উপর বিধিনিষেধ থাকে:

  • aidl_interfaces-এর মাধ্যমে বিল্ড সিস্টেমে ইন্টারফেস সংজ্ঞায়িত করা হয়।
  • ইন্টারফেসে শুধুমাত্র স্ট্রাকচার্ড ডেটা থাকতে পারে। পছন্দের ধরনকে প্রতিনিধিত্বকারী পার্সেলযোগ্য আইটেম তাদের AIDL সংজ্ঞা অনুযায়ী অটোমেটিক তৈরি হয় এবং অটোমেটিক মার্শেল ও আনমার্শেল করা হয়।
  • ইন্টারফেসকে স্থিতিশীল (ব্যাকওয়ার্ড-কম্প্যাটিবল) হিসেবে ঘোষণা করা যেতে পারে। এটি হলে, তাদের API ট্র্যাক করা হয় এবং AIDL ইন্টারফেসের পাশে একটি ফাইলে ভার্সন করা হয়।

স্ট্রাকচার্ড বনাম স্টেবল AIDL

স্ট্রাকচার্ড AIDL বলতে শুধুমাত্র AIDL-এ সংজ্ঞায়িত ধরনকে বোঝায়। যেমন, পার্সেল করা যায় এমন ঘোষণা (কাস্টম পার্সেল করা যায় এমন) স্ট্রাকচার্ড AIDL নয়। AIDL-এ সংজ্ঞায়িত ফিল্ড সহ পার্সেলযোগ্যকে স্ট্রাকচার্ড পার্সেলযোগ্য বলা হয়।

স্থিতিশীল AIDL-এর জন্য স্ট্রাকচার্ড AIDL প্রয়োজন যাতে বিল্ড সিস্টেম ও কম্পাইলার পার্সেলেবেলে করা পরিবর্তন ব্যাকওয়ার্ড কম্প্যাটিবল কিনা তা বুঝতে পারে। তবে, সব স্ট্রাকচার্ড ইন্টারফেস স্থিতিশীল নয়। স্থিতিশীল হতে, কোনও ইন্টারফেসকে অবশ্যই শুধুমাত্র স্ট্রাকচার্ড ধরন ব্যবহার করতে হবে এবং এটিকেও অবশ্যই নিম্নলিখিত ভার্সনিং ফিচার ব্যবহার করতে হবে। বিপরীতভাবে, কোনও ইন্টারফেস স্থিতিশীল নয় যদি কোর বিল্ড সিস্টেম এটি তৈরি করতে ব্যবহার করা হয় অথবা যদি 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: AIDL ইন্টারফেস মডিউলের নাম যা অনন্যভাবে একটি AIDL ইন্টারফেসকে শনাক্ত করে।
  • srcs: ইন্টারফেস তৈরি করা AIDL সোর্স ফাইলের তালিকা। com.acme প্যাকেজে সংজ্ঞায়িত Foo AIDL টাইপের পাথ <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-এর অধীনে ফ্রিজ করা হয়েছে। কোনও ইন্টারফেসের ফ্রোজেন ভার্সন না থাকলে, এটি উল্লেখ করার প্রয়োজন নেই এবং কম্প্যাটিবিলিটি চেক করা হবে না। 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 হিসেবে সেট করা থাকলে, বিল্ড সিস্টেম ইন্টারফেসের জন্য API ডাম্প তৈরি করে না এবং এটি আপডেট করারও প্রয়োজন হয় না।
  • frozen: ঐচ্ছিক ফ্ল্যাগ যা true-এ সেট করা হলে তার অর্থ হল ইন্টারফেসের আগের ভার্সনের পর থেকে ইন্টারফেসে কোনও পরিবর্তন হয়নি। এর ফলে আরও বেশি বিল্ড-টাইম চেক করা যায়। false হিসেবে সেট করা থাকলে, এর অর্থ হল ইন্টারফেসটি ডেভেলপমেন্টের পর্যায়ে আছে এবং এতে নতুন পরিবর্তন করা হয়েছে, তাই foo-freeze-api রান করালে একটি নতুন ভার্সন তৈরি হয় এবং অটোমেটিক ভ্যালু পরিবর্তন করে true করা হয়। Android 14-এ চালু করা হয়েছে।
  • backend.<type>.enabled: এই ফ্ল্যাগগুলি প্রতিটি ব্যাকএন্ড টগল করে যার জন্য AIDL কম্পাইলার কোড তৈরি করে। চারটি ব্যাকএন্ড কাজ করে: 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: জেনারেট করা লাইব্রেরি SDK-এর পরিবর্তে প্ল্যাটফর্ম API-এর বিরুদ্ধে বিল্ড করার প্রয়োজন হলে, ঐচ্ছিক ফ্ল্যাগটি সেট করতে হবে।true

ভার্সন ও চালু করা ব্যাকএন্ডের প্রতিটি কম্বিনেশনের জন্য, একটি স্টাব লাইব্রেরি তৈরি করা হয়। নির্দিষ্ট ব্যাকএন্ডের জন্য কীভাবে স্টাব লাইব্রেরির নির্দিষ্ট ভার্সন রেফার করতে হয়, তা জানতে মডিউল নামকরণের নিয়ম দেখুন।

AIDL ফাইল লেখা

স্টেবল AIDL-এর ইন্টারফেসগুলি ঐতিহ্যগত ইন্টারফেসের মতোই, তবে ব্যতিক্রম হল যে তারা আনস্ট্রাকচার্ড পার্সেলযোগ্য ব্যবহার করার অনুমতি পায় না (কারণ এগুলি স্টেবল নয়! স্ট্রাকচার্ড বনাম স্টেবল AIDL দেখুন)। স্টেবল AIDL-এ প্রধান পার্থক্য হল পার্সেলযোগ্য কীভাবে সংজ্ঞায়িত করা হয়। আগে, পার্সেলযোগ্য আইটেম ফরোয়ার্ড ডিক্লেয়ার করা হত; স্টেবল (এবং সেই জন্য স্ট্রাকচার্ড) AIDL-এ, পার্সেলযোগ্য ফিল্ড ও ভেরিয়েবল স্পষ্টভাবে সংজ্ঞায়িত করা হয়।

// 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-এ, ব্যবহারকারী-নির্ধারিত এনুমেরেশনের ডিফল্ট কাজ করে। ডিফল্ট মান নির্দিষ্ট করা না থাকলে, ০-এর মতো বা খালি মান ব্যবহার করা হয়। ডিফল্ট ভ্যালু ছাড়া এনিউমারেশন ০ হিসেবে শুরু করা হয়, এমনকি কোনও জিরো এনিউমারেটর না থাকলেও।

স্টাব লাইব্রেরি ব্যবহার করা

আপনার মডিউলে ডিপেন্ডেন্সি হিসেবে স্টাব লাইব্রেরি যোগ করার পরে, আপনি সেগুলি আপনার ফাইলে অন্তর্ভুক্ত করতে পারবেন। এখানে বিল্ড সিস্টেমে স্টাব লাইব্রেরির উদাহরণ দেওয়া হল (Android.mk লিগ্যাসি মডিউল ডেফিনিশনের জন্যও ব্যবহার করা যেতে পারে)। মনে রাখবেন, এইসব উদাহরণে ভার্সন নেই, তাই এটি অস্থিতিশীল ইন্টারফেস ব্যবহার করাকে বোঝায়, কিন্তু ভার্সন সহ ইন্টারফেসের নামে অতিরিক্ত তথ্য থাকে, ভার্সনিং ইন্টারফেস দেখুন।

cc_... {
    name: ...,
    // use `shared_libs:` to load your library and its transitive dependencies
    // dynamically
    shared_libs: ["my-module-name-cpp"],
    // use `static_libs:` to include the library in this binary and drop
    // transitive dependencies
    static_libs: ["my-module-name-cpp"],
    ...
}
# or
java_... {
    name: ...,
    // use `static_libs:` to add all jars and classes to this jar
    static_libs: ["my-module-name-java"],
    // use `libs:` to make these classes available during build time, but
    // not add them to the jar, in case the classes are already present on the
    // boot classpath (such as if it's in framework.jar) or another jar.
    libs: ["my-module-name-java"],
    // use `srcs:` with `-java-sources` if you want to add classes in this
    // library jar directly, but you get transitive dependencies from
    // somewhere else, such as the boot classpath or another jar.
    srcs: ["my-module-name-java-source", ...],
    ...
}
# 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

Rust-এ উদাহরণ:

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

ইন্টারফেসের ভার্সনিং

foo নামের কোনও মডিউল ঘোষণা করলে, বিল্ড সিস্টেমে একটি টার্গেটও তৈরি হয় যা আপনি মডিউলের API ম্যানেজ করতে ব্যবহার করতে পারবেন। বিল্ড করার সময়, foo-freeze-api Android ভার্সনের উপর নির্ভর করে api_dir বা aidl_api/name-এর অধীনে একটি নতুন API সংজ্ঞা যোগ করে এবং .hash ফাইল যোগ করে, দুটিই ইন্টারফেসের নতুন ফ্রোজেন ভার্সনকে উপস্থাপন করে। foo-freeze-api অতিরিক্ত ভার্সন ও ভার্সনের জন্য imports-কে প্রতিফলিত করতে versions_with_info প্রপার্টিও আপডেট করে। মূলত, versions_with_info-এ imports, imports ফিল্ড থেকে কপি করা হয়েছে। কিন্তু ইমপোর্টের জন্য imports-এ versions_with_info-এ লেটেস্ট স্থিতিশীল ভার্সন উল্লেখ করা আছে, যার কোনও স্পষ্ট ভার্সন নেই। versions_with_info প্রপার্টি নির্দিষ্ট করার পরে, বিল্ড সিস্টেম ফ্রোজেন ভার্সন এবং টপ অফ ট্রি (ToT) ও লেটেস্ট ফ্রোজেন ভার্সনের মধ্যে কম্প্যাটিবিলিটি চেক চালায়।

এছাড়াও, আপনাকে ToT ভার্সনের API সংজ্ঞা ম্যানেজ করতে হবে। কোনও API আপডেট করা হলে, foo-update-api রান করে aidl_api/name/current সেটি আপডেট করুন, যার মধ্যে ToT ভার্সনের API সংজ্ঞা থাকে।

ইন্টারফেসের স্থিতিশীলতা বজায় রাখতে, মালিকরা নতুন এগুলি যোগ করতে পারেন:

  • ইন্টারফেসের শেষে পদ্ধতি (বা স্পষ্টভাবে নতুন সিরিয়াল সংজ্ঞায়িত করা পদ্ধতি)
  • পার্সেলেবল এলিমেন্টের শেষে (প্রতিটি এলিমেন্টের জন্য একটি ডিফল্ট যোগ করতে হবে এলিমেন্ট)
  • ধ্রুবক মান
  • Android 11-এ, এনিউমেরেটর
  • Android 12-এ, ইউনিয়নের শেষ পর্যন্ত ফিল্ড

অন্য কোনও অ্যাকশন অনুমোদিত নয় এবং অন্য কেউ ইন্টারফেস পরিবর্তন করতে পারবেন না (অন্যথায়, মালিকের করা পরিবর্তনের সাথে সংঘর্ষের ঝুঁকি থাকে)।

রিলিজের জন্য সব ইন্টারফেস ফ্রিজ করা হয়েছে কিনা তা পরীক্ষা করতে, আপনি নিম্নলিখিত এনভায়রনমেন্ট ভেরিয়েবল সেট করে বিল্ড করতে পারেন:

  • AIDL_FROZEN_REL=true m ... - বিল্ডের জন্য সব স্থিতিশীল AIDL ইন্টারফেসকে ফ্রোজেন করতে হবে, যেগুলিতে কোনও owner: ফিল্ড নির্দিষ্ট করা নেই।
  • AIDL_FROZEN_OWNERS="aosp test" - বিল্ডের জন্য সব স্টেবল AIDL ইন্টারফেস "aosp" বা "test" হিসেবে নির্দিষ্ট করা owner: ফিল্ডের সাথে ফ্রিজ করতে হবে।

ইমপোর্টের স্থিতিশীলতা

ইন্টারফেসের ফ্রোজেন ভার্সনের জন্য ইম্পোর্টের ভার্সন আপডেট করা স্টেবল AIDL লেয়ারে ব্যাকওয়ার্ড কম্প্যাটিবল। তবে, এগুলি আপডেট করতে হলে, ইন্টারফেসের আগের ভার্সন ব্যবহার করে এমন সব সার্ভার ও ক্লায়েন্টকে আপডেট করতে হবে এবং বিভিন্ন ধরনের ভার্সন একসাথে ব্যবহার করলে কিছু অ্যাপ বিভ্রান্ত হয়ে যেতে পারে। সাধারণত, শুধুমাত্র টাইপ বা সাধারণ প্যাকেজের ক্ষেত্রে, এটি নিরাপদ কারণ IPC ট্রানজ্যাকশন থেকে অজানা টাইপ হ্যান্ডেল করার জন্য কোড আগে থেকেই লেখা থাকতে হবে।

Android প্ল্যাটফর্ম কোডে android.hardware.graphics.common হল এই ধরনের ভার্সন আপগ্রেডের সবচেয়ে বড় উদাহরণ।

ভার্সন করা ইন্টারফেস ব্যবহার করা

ইন্টারফেস পদ্ধতি

রানটাইমে, পুরনো সার্ভারে নতুন পদ্ধতি কল করার চেষ্টা করলে, নতুন ক্লায়েন্টরা ব্যাকএন্ডের উপর নির্ভর করে সমস্যা বা ব্যতিক্রম দেখতে পান।

  • cpp ব্যাকএন্ডে ::android::UNKNOWN_TRANSACTION আছে।
  • ndk ব্যাকএন্ড STATUS_UNKNOWN_TRANSACTION পায়।
  • java ব্যাকএন্ডে android.os.RemoteException সহ একটি মেসেজ আসে যাতে বলা হয় যে API প্রয়োগ করা হয়নি।

এটি ম্যানেজ করার কৌশল সম্পর্কে জানতে কোয়েরি ভার্সন এবং ডিফল্ট ব্যবহার করা দেখুন।

পার্সেল করা যায়

পার্সেলেবল ডেটাতে নতুন ফিল্ড যোগ করা হলে, পুরনো ক্লায়েন্ট ও সার্ভার সেগুলি বাদ দিয়ে দেয়। নতুন ক্লায়েন্ট ও সার্ভার পুরনো পার্সেলযোগ্য ডেটা পেলে, নতুন ফিল্ডের ডিফল্ট ভ্যালু অটোমেটিক পূরণ হয়ে যায়। এর অর্থ হল, পার্সেল করার উপযুক্ত সব নতুন ফিল্ডের জন্য ডিফল্ট মান নির্দিষ্ট করতে হবে।

ক্লায়েন্টদের নতুন ফিল্ড ব্যবহার করার জন্য সার্ভারের উপর ভরসা করা উচিত নয়, যতক্ষণ না তারা জানে যে সার্ভার এমন ভার্সন প্রয়োগ করছে যেখানে ফিল্ডটি সংজ্ঞায়িত করা আছে (দেখুন কোয়েরি ভার্সন)।

এনাম ও কনস্ট্যান্ট

একইভাবে, ক্লায়েন্ট ও সার্ভারকে উপযুক্তভাবে অচেনা কনস্ট্যান্ট ভ্যালু ও এনুমেরেটর বাতিল বা উপেক্ষা করতে হবে, কারণ ভবিষ্যতে আরও যোগ করা হতে পারে। যেমন, কোনও সার্ভারকে যদি এমন কোনও এনুমারেটর পাঠানো হয় যার ব্যাপারে সেটি জানে না, তাহলে সেটিকে বাতিল করা উচিত নয়। সার্ভারকে হয় এনুমেরেটর উপেক্ষা করতে হবে, অথবা এমন কিছু রিটার্ন করতে হবে যাতে ক্লায়েন্ট বুঝতে পারে যে এই ইমপ্লিমেন্টেশনে এটি কাজ করে না।

ইউনিয়ন

নতুন ফিল্ড সহ ইউনিয়ন পাঠানোর চেষ্টা করলে তা ব্যর্থ হয় যদি রিসিভার পুরনো হয় এবং ফিল্ড সম্পর্কে না জানে। নতুন ফিল্ডের সাথে ইউনিয়ন কখনওই প্রয়োগ করা হবে না। এটি ওয়ান-ওয়ে ট্রানজ্যাকশন হলে, ব্যর্থতা উপেক্ষা করা হয়; অন্যথায়, BAD_VALUE(C++ বা NDK ব্যাকএন্ডের জন্য) বা IllegalArgumentException(Java ব্যাকএন্ডের জন্য) সমস্যা হয়। ক্লায়েন্ট যদি নতুন ফিল্ডে পুরনো সার্ভারে ইউনিয়ন সেট পাঠায় অথবা পুরনো ক্লায়েন্ট যদি নতুন সার্ভার থেকে ইউনিয়ন পায়, তাহলে সমস্যাটি হয়।

মডিউল-লেভেল ভার্সন হেডার (C++ / NDK)

cpp বা ndk ব্যাকএন্ড ব্যবহার করে স্টেবল, ভার্সন করা AIDL মডিউলের জন্য, Soong অটোমেটিক মডিউল-লেভেল সিন্থেটিক হেডার জেনারেট করে:

  • C++ ব্যাকএন্ড: #include "<module-name>.h"
  • NDK ব্যাক-এন্ড: #include "aidl/<module-name>.h"

এই হেডার AIDL_VERSION_<MODULE_NAME> ম্যাক্রোকে সংজ্ঞায়িত করে, যেখানে মডিউলের নামে ডট . এবং হাইফেন - আপারকেস আন্ডারস্কোর _-এ পরিবর্তিত হয়। ব্যবহৃত লাইব্রেরির ভার্সনের উপর ভিত্তি করে ইন্টারফেস মডিউলের ভার্সন নম্বর ম্যাক্রোকে অ্যাসাইন করা হয়।

যেমন, আপনি android.hardware.foo-V2-ndk থেকে ম্যাক্রো ব্যবহার করতে পারবেন:

#include <aidl/android.hardware.foo.h>

#if AIDL_VERSION_ANDROID_HARDWARE_FOO >= 2
// Code for version 2 or higher
#endif

একাধিক ভার্সন ম্যানেজ করা

Android-এ লিঙ্কার নেমস্পেসে কোনও নির্দিষ্ট aidl ইন্টারফেসের শুধুমাত্র ১টি ভার্সন থাকতে পারে, যাতে জেনারেট করা aidl টাইপের একাধিক ডেফিনিশন না থাকে। C++-এ একটি সংজ্ঞা সংক্রান্ত নিয়ম আছে যার জন্য প্রতিটি প্রতীকের একটি করে সংজ্ঞা প্রয়োজন।

Android বিল্ডে সমস্যা দেখা দেয় যখন কোনও মডিউল একই aidl_interface লাইব্রেরির বিভিন্ন ভার্সনের উপর নির্ভর করে। মডিউলটি সরাসরি বা পরোক্ষভাবে এইসব লাইব্রেরির উপর নির্ভর করতে পারে। এইসব সমস্যা থেকে বোঝা যায় যে, 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"],
  ...
}

ফ্ল্যাগ-ভিত্তিক ডেভেলপমেন্ট

রিলিজ ডিভাইসে ইন-ডেভেলপমেন্ট (আনফ্রিজ) ইন্টারফেস ব্যবহার করা যায় না, কারণ সেগুলি ব্যাকওয়ার্ড কম্প্যাটিবল হবে বলে গ্যারান্টি দেওয়া যায় না।

এইসব আনফ্রোজেন ইন্টারফেস লাইব্রেরির জন্য AIDL রান টাইম ফলব্যাক সাপোর্ট করে যাতে লেটেস্ট আনফ্রোজেন ভার্সনের জন্য কোড লেখা যায় এবং রিলিজ ডিভাইসে ব্যবহার করা যায়। ক্লায়েন্টের ব্যাকওয়ার্ড-কম্প্যাটিবল আচরণ হল আগেকার আচরণের মতো এবং ফলব্যাকের ক্ষেত্রে, প্রয়োগকেও সেইসব আচরণ অনুসরণ করতে হবে। ভার্সন করা ইন্টারফেস ব্যবহার করুন দেখুন।

AIDL বিল্ড ফ্ল্যাগ

এই আচরণ নিয়ন্ত্রণকারী ফ্ল্যাগ হল 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 কনফিগারেশনের জন্য আলাদা আলাদা কম্প্যাটিবিলিটি ম্যাট্রিক্স ফাইল ব্যবহার করে অথবা সব কনফিগারেশনে ব্যবহৃত একটি কম্প্যাটিবিলিটি ম্যাট্রিক্স ফাইলে দুটি ভার্সনকেই অনুমতি দিয়ে ম্যানেজ করতে পারেন।

যেমন, আনফ্রিজ করা ভার্সন ৪ যোগ করার সময় <version>3-4</version> ব্যবহার করুন।

ভার্সন ৪ ফ্রিজ করা হলে, কম্প্যাটিবিলিটি ম্যাট্রিক্স থেকে ভার্সন ৩ সরিয়ে দিতে পারেন কারণ RELEASE_AIDL_USE_UNFROZEN হলে ফ্রিজ করা ভার্সন ৪ ব্যবহার করা হয় false।

ম্যানিফেস্ট

Android 15-এ, libvintf-এ একটি পরিবর্তন করা হয়েছে যা RELEASE_AIDL_USE_UNFROZEN-এর ভ্যালুর উপর ভিত্তি করে বিল্ড টাইমে ম্যানিফেস্ট ফাইল পরিবর্তন করে।

ম্যানিফেস্ট ও ম্যানিফেস্ট ফ্র্যাগমেন্ট ঘোষণা করে যে কোনও পরিষেবা কোন ইন্টারফেসের কোন ভার্সন প্রয়োগ করে। ইন্টারফেসের লেটেস্ট আনফ্রিজ করা ভার্সন ব্যবহার করার সময়, এই নতুন ভার্সনটি যাতে দেখা যায় তার জন্য ম্যানিফেস্ট আপডেট করতে হবে। জেনারেট করা AIDL লাইব্রেরিতে পরিবর্তন libvintf প্রতিফলিত করতে RELEASE_AIDL_USE_UNFROZEN=false ম্যানিফেস্ট এন্ট্রি অ্যাডজাস্ট করা হলে। ভার্সনটি আনফ্রোজেন ভার্সন N থেকে শেষ ফ্রোজেন ভার্সন N - 1-এ পরিবর্তন করা হয়েছে। তাই, ব্যবহারকারীদের প্রতিটি পরিষেবার জন্য একাধিক ম্যানিফেস্ট বা ম্যানিফেস্ট ফ্র্যাগমেন্ট ম্যানেজ করতে হয় না।

HAL ক্লায়েন্ট সংক্রান্ত পরিবর্তন

HAL ক্লায়েন্ট কোডকে অবশ্যই আগের প্রতিটি কাজ করে এমন ফ্রোজেন ভার্সনের সাথে ব্যাকওয়ার্ড কম্প্যাটিবল হতে হবে। RELEASE_AIDL_USE_UNFROZEN false হলে, পরিষেবাগুলি সবসময় শেষ ফ্রোজেন ভার্সন বা তার আগের ভার্সনের মতো দেখায় (যেমন, নতুন আনফ্রোজেন মেথড কল করলে UNKNOWN_TRANSACTION রিটার্ন করে অথবা নতুন parcelable ফিল্ডের ডিফল্ট ভ্যালু থাকে)। Android ফ্রেমওয়ার্ক ক্লায়েন্টদের অতিরিক্ত পূর্ববর্তী ভার্সনের সাথে ব্যাকওয়ার্ড কম্প্যাটিবল হতে হবে, তবে এটি ভেন্ডর ক্লায়েন্ট এবং পার্টনারের মালিকানাধীন ইন্টারফেসের ক্লায়েন্টদের জন্য একটি নতুন বিবরণ।

HAL প্রয়োগ সংক্রান্ত পরিবর্তন

ফ্ল্যাগ-ভিত্তিক ডেভেলপমেন্টের সাথে HAL ডেভেলপমেন্টের সবচেয়ে বড় পার্থক্য হল RELEASE_AIDL_USE_UNFROZEN, false হলে কাজ করার জন্য HAL ইমপ্লিমেন্টেশনকে শেষ ফ্রোজেন ভার্সনের সাথে ব্যাকওয়ার্ড কম্প্যাটিবল হতে হবে। ইমপ্লিমেন্টেশনে ব্যাকওয়ার্ড কম্প্যাটিবিলিটি বিবেচনা করা হয় এবং ডিভাইস কোড হল একটি নতুন এক্সারসাইজ। ভার্সন করা ইন্টারফেস ব্যবহার করা দেখুন।

ক্লায়েন্ট ও সার্ভার এবং ফ্রেমওয়ার্ক কোড ও ভেন্ডর কোডের ক্ষেত্রে ব্যাকওয়ার্ড কম্প্যাটিবিলিটি সংক্রান্ত বিষয়গুলি সাধারণত একই হয়, তবে কিছু সূক্ষ্ম পার্থক্য থাকে যেগুলি সম্পর্কে আপনাকে সচেতন থাকতে হবে, কারণ আপনি এখন একই সোর্স কোড (বর্তমান, আনফ্রিজেন ভার্সন) ব্যবহার করে দুটি ভার্সন কার্যকরভাবে প্রয়োগ করছেন।

উদাহরণ: কোনও ইন্টারফেসে তিনটি ফ্রিজ করা ভার্সন আছে। নতুন পদ্ধতি ব্যবহার করে ইন্টারফেস আপডেট করা হয়েছে। নতুন ভার্সন 4 লাইব্রেরি ব্যবহার করার জন্য ক্লায়েন্ট ও পরিষেবা দুটিই আপডেট করা হয়েছে। V4 লাইব্রেরি ইন্টারফেসের আনফ্রোজেন ভার্সনের উপর ভিত্তি করে তৈরি, তাই 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()-এর সাথে ঘোষণা করা হয়েছে কিনা তা চেক করে দেখতে পারেন। এটি ঘোষণা করা হলে এবং রেজিস্টার করা না গেলে, তাহলে প্রসেসটি বাতিল করুন। এটি ঘোষণা করা না থাকলে, রেজিস্টার করা যাবে না।

নতুন VINTF স্টেবল এক্সটেনশন ইন্টারফেস

নতুন এক্সটেনশন ইন্টারফেস এর কোনও আগের ভার্সন নেই যেটিতে ফিরে যাওয়া যায় এবং যেহেতু সেগুলি ServiceManager-এর সাথে রেজিস্টার করা নেই বা VINTF ম্যানিফেস্টে ঘোষণা করা নেই, তাই অন্য ইন্টারফেসের সাথে এক্সটেনশন ইন্টারফেস কখন অ্যাটাচ করতে হবে তা নির্ধারণ করতে IServiceManager::isDeclared() ব্যবহার করা যাবে না।

রিলিজ করা ডিভাইসে এটি ব্যবহার করা এড়াতে, নতুন আনফ্রিজ করা এক্সটেনশন ইন্টারফেসটি বর্তমান ইন্টারফেসের সাথে অ্যাটাচ করা হবে কিনা তা নির্ধারণ করতে RELEASE_AIDL_USE_UNFROZEN ভেরিয়েবল ব্যবহার করা যেতে পারে। রিলিজ করা ডিভাইসে ব্যবহার করার জন্য ইন্টারফেস ফ্রিজ করতে হবে।

রিলিজ করা ডিভাইসে আনফ্রিজ করা এক্সটেনশন ইন্টারফেস ব্যবহার করা হলে vts_treble_vintf_vendor_test এবং vts_treble_vintf_framework_test VTS টেস্ট তা শনাক্ত করে এবং একটি সমস্যা দেখায়।

এক্সটেনশন ইন্টারফেসটি নতুন না হলে এবং আগে থেকে ফ্রিজ করা ভার্সন থাকলে, এটি আগে থেকে ফ্রিজ করা ভার্সনে ফিরে যায় এবং কোনও অতিরিক্ত পদক্ষেপের প্রয়োজন হয় না।

ডেভেলপমেন্ট টুল হিসেবে Cuttlefish

প্রতি বছর VINTF ফ্রিজ করার পরে, আমরা ফ্রেমওয়ার্ক কম্প্যাটিবিলিটি ম্যাট্রিক্স (FCM) target-level এবং Cuttlefish-এর PRODUCT_SHIPPING_API_LEVEL অ্যাডজাস্ট করি যাতে সেগুলি আগামী বছরের রিলিজের সাথে লঞ্চ করা ডিভাইসগুলিকে প্রতিফলিত করে। আমরা target-level এবং PRODUCT_SHIPPING_API_LEVEL অ্যাডজাস্ট করি যাতে নিশ্চিত করা যায় যে এমন কিছু লঞ্চিং ডিভাইস আছে যা পরীক্ষা করা হয়েছে এবং আগামী বছরের রিলিজের জন্য নতুন প্রয়োজনীয়তা পূরণ করে।

RELEASE_AIDL_USE_UNFROZEN true হলে, Cuttlefish ভবিষ্যতে Android রিলিজের ডেভেলপমেন্টের জন্য ব্যবহার করা হয়। এটি আগামী বছর রিলিজ হতে চলা Android ভার্সনের FCM লেভেল ও PRODUCT_SHIPPING_API_LEVEL-কে টার্গেট করে, যার জন্য এটিকে পরবর্তী রিলিজের ভেন্ডর সফটওয়্যার সংক্রান্ত প্রয়োজনীয়তা (VSR) পূরণ করতে হবে।

RELEASE_AIDL_USE_UNFROZEN, false হলে, Cuttlefish-এর কাছে আগের target-level এবং PRODUCT_SHIPPING_API_LEVEL থাকে যা রিলিজ ডিভাইসকে দেখায়। Android 14 এবং তার আগের ভার্সনে, এই পার্থক্যটি বিভিন্ন Git ব্রাঞ্চের মাধ্যমে সম্পন্ন করা হবে যা FCM target-level, শিপিং API লেভেল বা পরবর্তী রিলিজকে টার্গেট করা অন্য কোনও কোডে পরিবর্তন গ্রহণ করে না।

মডিউলের নাম সংক্রান্ত নিয়ম

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। প্রথমটি অ্যাপের জন্য এবং পরেরটি Android 13 পর্যন্ত প্ল্যাটফর্ম ব্যবহারের জন্য। Android 13 ও তার পরবর্তী যেকোনও ভার্সনে, শুধুমাত্র ndk ব্যবহার করুন।
    • Rust ব্যাকএন্ডের জন্য rust।

ধরে নিন যে foo নামের একটি মডিউল আছে এবং এর লেটেস্ট ভার্সন হল 2, এবং এটি NDK ও C++ দু'টিই সাপোর্ট করে। এই ক্ষেত্রে, AIDL এই মডিউলগুলি তৈরি করে:

  • ভার্সন ১-এর উপর ভিত্তি করে
    • foo-V1-(java|cpp|ndk|ndk_platform|rust)
  • ভার্সন ২ (লেটেস্ট স্টেবল ভার্সন)-এর উপর ভিত্তি করে
    • 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

মনে রাখবেন, AIDL কম্পাইলার কোনও স্থিতিশীল AIDL ইন্টারফেসের জন্য 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 রিটার্ন করে।

স্থিতিশীল AIDL-এর মাধ্যমে ক্লায়েন্টরা আরও বেশি নিয়ন্ত্রণ পান। ক্লায়েন্ট সাইডে, আপনি AIDL ইন্টারফেসে একটি ডিফল্ট প্রয়োগ সেট করতে পারবেন। ডিফল্ট ইমপ্লিমেন্টেশনে কোনও পদ্ধতি তখনই কল করা হয় যখন পদ্ধতিটি রিমোট সাইডে ইমপ্লিমেন্ট করা হয় না (কারণ এটি ইন্টারফেসের পুরনো ভার্সন দিয়ে তৈরি করা হয়েছে)। যেহেতু ডিফল্ট মান বিশ্বব্যাপী সেট করা হয়, তাই সম্ভাব্য শেয়ার করা কনটেক্সট থেকে সেগুলি ব্যবহার করা উচিত নয়।

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(...);

আপনাকে AIDL ইন্টারফেসে সব পদ্ধতির ডিফল্ট প্রয়োগ করার প্রয়োজন নেই। যেসব পদ্ধতি রিমোট সাইডে প্রয়োগ করা হবে বলে গ্যারান্টি দেওয়া হয়েছে (কারণ আপনি নিশ্চিত যে পদ্ধতিগুলি AIDL ইন্টারফেস বিবরণে থাকার সময় রিমোট তৈরি করা হয়েছে) সেগুলি ডিফল্ট impl ক্লাসে ওভাররাইড করার প্রয়োজন নেই।

আগে থেকে থাকা AIDL-কে স্ট্রাকচার্ড বা স্থিতিশীল AIDL-এ কনভার্ট করা

আপনার যদি আগে থেকেই AIDL ইন্টারফেস ও কোড থাকে যা এটি ব্যবহার করে, তাহলে ইন্টারফেসকে একটি স্থিতিশীল AIDL ইন্টারফেসে কনভার্ট করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন।

  1. আপনার ইন্টারফেসের সব নির্ভরতা শনাক্ত করুন। প্রতিটি প্যাকেজের জন্য, ইন্টারফেস নির্ভর করে, প্যাকেজটি স্থিতিশীল AIDL-এ সংজ্ঞায়িত করা হয়েছে কিনা তা নির্ধারণ করুন। নির্দিষ্ট করা না থাকলে, প্যাকেজটি কনভার্ট করতে হবে।

  2. আপনার ইন্টারফেসে থাকা সব পার্সেলযোগ্য আইটেমকে স্থিতিশীল পার্সেলযোগ্য আইটেমে কনভার্ট করুন (ইন্টারফেস ফাইলগুলি অপরিবর্তিত থাকতে পারে)। সরাসরি AIDL ফাইলে তাদের স্ট্রাকচার প্রকাশ করে এটি করুন। এইসব নতুন ধরনের ডেটা ব্যবহার করতে ম্যানেজমেন্ট ক্লাসকে আবার লিখতে হবে। আপনি কোনও aidl_interface প্যাকেজ (নিচে দেখুন) তৈরি করার আগে এটি করা যেতে পারে।

  3. আপনার মডিউলের নাম, এর ডিপেন্ডেন্সি এবং আপনার প্রয়োজনীয় অন্যান্য তথ্য সহ একটি aidl_interface প্যাকেজ (উপরে বর্ণিত) তৈরি করুন। এটি স্থিতিশীল (শুধু স্ট্রাকচার্ড নয়) করতে, এটির ভার্সনও থাকতে হবে। আরও তথ্যের জন্য, ভার্সনিং ইন্টারফেস দেখুন।