نظام Android 10 يتيح استخدام واجهة Android ثابتة لغة التعريف (AIDL)، وهي طريقة جديدة لتتبع برنامج تقديم الطلبات (API) وواجهة التطبيق الثنائية (ABI) التي توفّرها AIDL من الواجهات. تعمل لغة AIDL الثابتة تمامًا مثل AIDL، لكنّ نظام الإصدار يتتبّع التوافق مع واجهة المستخدم، وهناك قيود على ما يمكنك فعله:
- يتم تحديد الواجهات في نظام الإنشاء باستخدام
aidl_interfaces
. - يمكن أن تحتوي الواجهات على بيانات منظَّمة فقط. قطع الأراضي التي تمثّل يتم إنشاء الأنواع المفضلة تلقائيًا بناءً على تعريف AIDL الخاصة بها يتم تشكيلها وترتيبها تلقائيًا.
- يمكن تعريف الواجهات على أنّها مستقرة (متوافقة مع الأنظمة القديمة). عندما يكون هذا يتم تتبُّع واجهة برمجة التطبيقات الخاصة بها وإصدار إصدارات منها في ملف بجانب AIDL من واجهة pyplot.
لغة AIDL مهيكلة مقابل ثابتة
تشير لغة AIDL المركّبة إلى أنواع محدّدة في لغة AIDL فقط. على سبيل المثال، ملف تعريف parcelable (ملف تعريف parcelable مخصّص) ليس ملف تعريف 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 التي تنشئ الواجهة يجب أن يكون المسار لنوع AIDLFoo
المحدّد في حزمةcom.acme
على العنوان<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
. وإذا لم تكن هناك إصدارات ثابتة من الواجهة، يجب عدم تحديد هذا الحقل، ولن يتم إجراء عمليات تحقق من التوافق. تم استبدال هذا الحقل بـversions_with_info
لنظام التشغيل Android. 13 وأعلى.versions_with_info
: قائمة الصفوف، يحتوي كلٌ منها على اسم نسخة مجمدة وقائمة مع استيرادات إصدار لـ aidl_interface التي قام هذا الإصدار من aidl_interface باستيرادها. التعريف من الإصدار V من واجهة AIDL، يقع الموقع الجغرافي علىaidl_api/IFACE/V
تم تقديم هذا الحقل في Android 13، وليس من المفترض أن يتم تعديله فيAndroid.bp
مباشرةً. الحقل هو تمت إضافتها أو تعديلها من خلال استدعاء*-update-api
أو*-freeze-api
. بالإضافة إلى ذلك، يتم نقل حقولversions
تلقائيًا إلىversions_with_info
عندما يستدعي المستخدم*-update-api
أو*-freeze-api
.stability
: العلامة الاختيارية التي توفر وعدًا بالثبات لهذه الواجهة. يمكن استخدام"vintf"
فقط. في حال تركstability
بدون ضبط، سيتم يتحقق من توافق الواجهة مع الإصدارات القديمة ما لم تم تحديدunstable
. يرتبط عدم ضبط القيمة بواجهة تتسم بالثبات في سياق الترجمة هذا (أي جميع عناصر النظام، مثلاً، العناصر فيsystem.img
والأقسام ذات الصلة، أو جميع عناصر المورّد، مثلاً، العناصر فيvendor.img
والأقسام ذات الصلة). في حال حذف تم ضبطstability
على"vintf"
، ويتوافق هذا مع وعد استقرار: يجب الحفاظ على استقرار الواجهة ما دام قيد الاستخدام.-
gen_trace
: العلامة الاختيارية لتفعيل التتبُّع أو إيقافه. بدءًا من الإصدار Android 14، يكون الإعداد التلقائي هوtrue
لخلفيتَيcpp
وjava
. -
host_supported
: العلامة الاختيارية التي عند ضبطها علىtrue
تجعل المكتبات التي تم إنشاؤها متاحة للبيئة المستضافة unstable
: العلامة الاختيارية المستخدمة لوضع علامة على أن هذه الواجهة لا يجب أن تكون مستقرة. عند ضبط هذا الخيار علىtrue
، لا ينشئ نظام الإنشاء ملفًا لبيانات واجهة برمجة التطبيقات للواجهة ولا يطلب تحديثه.frozen
: العلامة الاختيارية التي عند ضبطها علىtrue
، تعني أنّ الواجهة لم تطرأ أي تغييرات منذ الإصدار السابق من الواجهة. وهذا يمكّن المزيد من عمليات التحقق من وقت الإصدار. عند ضبط القيمة علىfalse
، يعني ذلك أنّ الواجهة في مرحلة تطوير وتحتوي على تغييرات جديدة، لذا يؤدي تشغيلfoo-freeze-api
إلى إنشاء إصدار جديد وتغيير القيمة تلقائيًا إلىtrue
. تم إدخال القدرة لأول مرة في الإصدار 14 من نظام التشغيل Androidbackend.<type>.enabled
: تعمل هذه العلامات على تبديل كل من الخلفيات التي يقوم المحول البرمجي لـ AIDL بإنشاء التعليمات البرمجية. تتوفّر أربعة أنظمة أساسية: Java وC++ وNDK وRust. يتم تفعيل الخلفيات Java وC++ وNDK تلقائيًا. إذا لم تكن هناك حاجة إلى أي من هذه الخلفيات الثلاث، فيجب بشكل صريح. يتم إيقاف Rust تلقائيًا إلى أن يعمل نظام التشغيل Android. 15-backend.<type>.apex_available
: قائمة بأسماء ملفات APEX التي تم إنشاؤها تتوفر بها مكتبة بدائل.backend.[cpp|java].gen_log
: العلامة الاختيارية التي تتحكم في ما إذا كان سيتم إنشاء رمز إضافي لجمع المعلومات عن المعاملة.backend.[cpp|java].vndk.enabled
: العلامة الاختيارية لإنشاء هذه الواجهة جزءًا من مجموعة VNDK. القيمة التلقائية هيfalse
.backend.[cpp|ndk].additional_shared_libraries
: تمّت إضافة هذه العلامة في الإصدار 14 من نظام التشغيل Android، وهي تضيف تبعيات إلى مكتبات الأصلية. تكون هذه العلامة مفيدة معndk_header
وcpp_header
.backend.java.sdk_version
: العلامة الاختيارية لتحديد الإصدار لحزمة SDK التي بنيت مكتبة كعب Java عليها. القيمة التلقائية هي"system_current"
. لا يجب ضبط هذا الإعداد في حالbackend.java.platform_apis
.true
.backend.java.platform_apis
: العلامة الاختيارية التي يجب ضبطها علىtrue
عندما تحتاج المكتبات التي تم إنشاؤها إلى إنشاء استنادًا إلى واجهة برمجة تطبيقات النظام الأساسي بدلاً من حزمة SDK.
لكلّ تركيبة من الإصدارات وخدمات الخلفية المفعّلة، يتمّ إنشاء مكتبة الرمز المرجعي. للتعرّف على كيفية الرجوع إلى الإصدار المحدّد من مكتبة التنويهات الموجزة لخلفية معينة، يرجى الاطّلاع على قواعد تسمية الوحدات.
كتابة ملفات 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، تكون القيم الافتراضية للتعدادات التي يحددها المستخدم أيضًا
في حال عدم تحديد قيمة تلقائية، يتم استخدام قيمة فارغة أو قيمة مشابهة للقيمة 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، تتم إضافة تعريف جديد لواجهة برمجة التطبيقات تحت api_dir
أو
aidl_api/name
، استنادًا إلى إصدار Android، ويُضاف
ملف .hash
، وكلاهما يمثّل الإصدار المجمّد حديثًا من
الواجهة. يعدّل foo-freeze-api أيضًا السمة versions_with_info
لتعكس الإصدار الإضافي وimports
للإصدار. في الأساس، يتم نسخ imports
في versions_with_info
من الحقل imports
. لكن
تم تحديد أحدث إصدار ثابت في imports
في versions_with_info
الذي لا يحتوي على إصدار صريح.
بعد تحديد السمة versions_with_info
، يُجري نظام الإنشاء عمليات فحص التوافق بين الإصدارات المجمّدة وبين أحدث إصدار مجمّد و"أعلى الشجرة" (ToT).
بالإضافة إلى ذلك، عليك إدارة تعريف واجهة برمجة التطبيقات لإصدار ToT. عند تعديل واجهة برمجة تطبيقات، يجب تشغيل foo-update-api لتعديل aidl_api/name/current
الذي يحتوي على تعريف واجهة برمجة التطبيقات لإصدار ToT.
وللحفاظ على استقرار الواجهة، يمكن للمالكين إضافة عناصر جديدة:
- المناهج حتى نهاية الواجهة (أو الطرق ذات المعرفة الجديدة مسلسلات)
- العناصر في نهاية قطعة قطع (تتطلّب إضافة عنصر تلقائي لكل عنصر )
- القيم الثابتة
- في Android 11، أدوات العد
- في Android 12، الحقول التي تنتهي عند نهاية الاتحاد
لا يُسمح بإجراء أي إجراءات أخرى، ولا يمكن لأي شخص آخر تعديل الواجهة (وإلا أنه يخاطر بالاصطدام مع التغييرات التي يجريها المالك).
لاختبار تجميد جميع الواجهات للإصدار، يمكنك إنشاء الإصدار مع ضبط المتغيّرات البيئية التالية:
AIDL_FROZEN_REL=true m ...
- يتطلب الإنشاء تجميد كل واجهات AIDL الثابتة التي لم يتم تحديد حقلowner:
لها.-
AIDL_FROZEN_OWNERS="aosp test"
- يتطلب الإصدار تجميد جميع واجهات AIDL الثابتة مع تحديد الحقلowner:
على أنّه "aosp" أو "test".
ثبات عمليات الاستيراد
إنّ تعديل إصدارات عمليات الاستيراد للإصدارات المجمّدة من واجهة هو متوافق مع الإصدارات القديمة في طبقة AIDL الثابتة. ومع ذلك، يتطلّب تعديل هذه الأنواع تعديل جميع الخوادم والعملاء الذين يستخدمون إصدارًا سابقًا من الواجهة، وقد تواجه بعض التطبيقات مشكلة في حال خلط إصدارات مختلفة من الأنواع. بشكل عام، بالنسبة للأنواع فقط أو الحزم الشائعة، يعد هذا آمنًا لأن التعليمة البرمجية تحتاج إلى التي تتم كتابتها بالفعل للتعامل مع الأنواع غير المعروفة من معاملات IPC.
في رمز نظام Android الأساسي، يمثّل android.hardware.graphics.common
أكبر
مثال على هذا النوع من ترقية الإصدار.
استخدام واجهات ذات إصدارات
طرق الواجهة
أثناء التشغيل، عند محاولة استدعاء طرق جديدة على خادم قديم، يتلقّى العملاء الجدد إما خطأ أو استثناء، وذلك استنادًا إلى الخلفية.
- الخلفية
cpp
تحصل على::android::UNKNOWN_TRANSACTION
. - تتلقّى
ndk
الخلفيةSTATUS_UNKNOWN_TRANSACTION
. - تحصل الواجهة الخلفية في
java
علىandroid.os.RemoteException
مع رسالة مفادها لم يتم تنفيذ واجهة برمجة التطبيقات.
وبالنسبة إلى استراتيجيات التعامل مع هذا، انظر إصدارات طلب البحث استخدام الإعدادات التلقائية
قطع قِطع الأراضي
عند إضافة حقول جديدة إلى قطع الأراضي، يستبعدها العملاء والخوادم القديمة. عندما تتلقّى الخوادم والعملاء الجدد عناصر قابلة للتقسيم قديمة، يتم تلقائيًا ملء القيم التلقائية لسمات الجديدة. هذا يعني أن الإعدادات الافتراضية يجب أن تكون المحددة لكل الحقول الجديدة في العنصر.
ينبغي ألا يتوقع العملاء أن تستخدم الخوادم الحقول الجديدة ما لم يعرفوا يقوم الخادم بتنفيذ الإصدار الذي يحتوي على الحقل المحدد (انظر إصدارات طلب البحث).
عمليات التعداد والثوابت
وبالمثل، يجب أن يرفض العملاء والخوادم القيم الثابتة والمُجمِّعات غير المعروفة أو يتجاهلونها حسب الاقتضاء، لأنّه قد تتم إضافة المزيد في المستقبل. على سبيل المثال، يجب ألا يوقف الخادم عملية التنفيذ عند تلقّي ملف ناتج عن ملف تعريف مجهول. يجب أن يتجاهل الخادم العداد أو يعرض رسالة تُعلم العميل بأنّه غير متوافق مع هذا التنفيذ.
الاتحادات
فشلت محاولة إرسال اتحاد مع حقل جديد إذا كان الاستقبال قديمًا
لا تعرفه عن هذا المجال. ولن يلاحظ التنفيذ عملية الدمج مع
الحقل الجديد. يتم تجاهل الخطأ إذا كانت المعاملة
اتجاه واحد، وإلا يكون الخطأ BAD_VALUE
(لنظام التشغيل C++ أو NDK
الخلفي) أو IllegalArgumentException
(لنظام التشغيل Java الخلفي). الخطأ هو
إذا كان العميل يرسل اتحادًا تم تعيينه إلى الحقل الجديد إلى حقل قديم
أو عندما يكون برنامجًا قديمًا يتلقى الاتحاد من خادم جديد.
إدارة نُسخ متعددة
يمكن أن تحتوي مساحة اسم الرابط في 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"],
...
}
التطوير المستنِد إلى الإبلاغ عن المشاكل
لا يمكن استخدام الواجهات قيد التطوير (غير المجمّدة) على الأجهزة المتوفّرة للإصدار العلني، لأنّه لا يمكن ضمان توافقها مع الإصدارات السابقة.
تتيح لغة تعريف واجهة نظام Android استخدام الإصدارات الاحتياطية لمكتبات الواجهات غير المجمّدة في وقت التشغيل بهدف كتابة الرمز البرمجي وفقًا لأحدث إصدار غير مجمّد مع إمكانية استخدامه على الأجهزة العلنية. يشبه سلوك التوافق مع الإصدارات القديمة للعملاء السلوك الحالي، ويجب أن تتّبع عمليات التنفيذ أيضًا هذه السلوكيات عند استخدام الإعداد التلقائي. راجِع مقالة استخدام واجهات بإصدارات مختلفة.
علامة إصدار AIDL
العلامة التي تتحكّم في هذا السلوك هي RELEASE_AIDL_USE_UNFROZEN
وتكون محدّدة في build/release/build_flags.bzl
. true
تعني النسخة غير المجمدة من
تُستخدم الواجهة في وقت التشغيل وتعني false
أن مكتبات
فإن جميع النسخ غير المجمدة تتصرف مثل آخر نسخة مجمدة.
يمكنك إلغاء العلامة إلى true
إذا كان
التطوير المحلي، ولكن يجب إعادته إلى الإصدار false
قبل الإصدار. يتم عادةً تطوير الإصدارات باستخدام إعدادات تم ضبط العلامة فيها على true
.
مصفوفة التوافق وبيان التوافق
تحدِّد عناصر واجهة المورّد (عناصر VINTF) الإصدارات المتوقّعة والإصدارات المقدَّمة على أيّ من جانبَي واجهة المورّد.
تستهدف معظم الأجهزة بخلاف الحبار أحدث مصفوفة توافق.
بعد تجميد الواجهات فقط، لن يحدث أي فارق في واجهة AIDL
المكتبات المستندة إلى RELEASE_AIDL_USE_UNFROZEN
.
المصفوفات
تتم إضافة الواجهات التي يملكها الشركاء إلى ملفّات قاعدة بيانات التوافق الخاصة بالأجهزة أو المنتجات التي يستهدفها الجهاز أثناء التطوير. لذلك، عند إضافة
إصدار جديد غير مجمّد من واجهة إلى مصفوفة التوافق،
يجب أن تظل الإصدارات السابقة المجمّدة متاحة ل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
لتعديل ملفات البيان في وقت الإنشاء استنادًا إلى قيمة RELEASE_AIDL_USE_UNFROZEN
.
تشير البيانات وأجزاء البيان إلى إصدار الواجهة.
تنفذها الخدمة. عند استخدام أحدث إصدار غير مجمّد من واجهة،
يجب تعديل البيان ليعكس هذا الإصدار الجديد. عند
RELEASE_AIDL_USE_UNFROZEN=false
، يتم تعديل إدخالات البيان من قِبل
libvintf
لتعكس التغيير في مكتبة AIDL التي تم إنشاؤها. تم تعديل الإصدار
من الإصدار غير المُجمّد N
إلى
الإصدار المجمّد الأخير N - 1
. وبالتالي، لا يحتاج المستخدمون إلى إدارة عدة
بيانات بيان أو أجزاء بيانات بيان لكل خدمة من خدماتهم.
التغييرات في برنامج HAL
يجب أن يكون رمز عميل HAL متوافقًا مع الأنظمة القديمة مع كل عملية تجميد متوافقة سابقة.
. عندما تكون قيمة RELEASE_AIDL_USE_UNFROZEN
هي false
، تظهر الخدمات دائمًا.
مثل آخر نسخة مجمّدة أو سابقة (على سبيل المثال، استدعاء استدعاء الدالة الجديدة غير المجمدة
تُرجعها UNKNOWN_TRANSACTION
، أو يكون الحقول الجديدة parcelable
القيم الافتراضية). يجب أن يكون عملاء إطار عمل Android متوافقين مع الإصدارات السابقة، ولكن هذه تفاصيل جديدة لعملاء المورّدين وعملاء الواجهات التي يملكها الشركاء.
التغييرات في تنفيذ HAL
يكمن أكبر فرق في تطوير HAL مقارنةً بالتطوير المستنِد إلى العلامة في
اشتراط أن تكون عمليات تنفيذ HAL متوافقة مع الإصدارات القديمة
والمجمّدة الأخيرة لكي تعمل عندما يكون RELEASE_AIDL_USE_UNFROZEN
هو false
.
إنّ مراعاة التوافق مع الإصدارات القديمة في عمليات التنفيذ ورمز الجهاز هو عملية جديدة
. راجع استخدام الإصدارات
الواجهات.
اعتبارات التوافق مع الأنظمة القديمة هي نفسها بشكل عام العملاء والخوادم، ولرمز إطار العمل ورمز البائع، ولكن هناك الاختلافات الطفيفة التي يجب أن تكون على دراية بها، لأنك الآن فعال تنفيذ نسختين تستخدمان نفس رمز المصدر (الإصدار الحالي غير المجمّد ).
مثال: تحتوي واجهة على ثلاثة إصدارات مجمّدة. تم تعديل الواجهة باستخدام
طريقة جديدة. يتم تحديث كل من العميل والخدمة لاستخدام الإصدار 4 الجديد
المكتبة. وبما أنّ مكتبة الإصدار 4 تستند إلى إصدار غير مجمّد من
الواجهة، فإنّها تتصرف مثل آخر إصدار مجمّد، وهو الإصدار 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
ويتم تجاهل قيم الحقول الجديدة التي تحاول الخدمة إرسالها عند
الخروج من العملية.
لا يمكن إرسال الأنواع الجديدة التي تمت إضافتها في هذا الإصدار غير المجمّد. أو استلامها من خلال الواجهة.
لا تطلب عملية التنفيذ أبدًا استخدام طرق جديدة من أي عميل عندما
تم false
ميزة RELEASE_AIDL_USE_UNFROZEN
.
يجب استخدام المعرّفات الجديدة مع الإصدار الذي تم تقديمها فيه فقط، وليس مع الإصدار السابق.
يتم عادةً استخدام 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
وPRODUCT_SHIPPING_API_LEVEL
للحبار
لذا فهي تعكس الأجهزة التي يتم إطلاقها مع إصدار العام المقبل. نحن نعدّل
target-level
وPRODUCT_SHIPPING_API_LEVEL
للتأكّد من توفّر
جهاز إطلاق تم اختباره ويستوفي المتطلبات الجديدة لإصدار العام القادم.
عندما يكون RELEASE_AIDL_USE_UNFROZEN
هو true
، يتم استخدام Cuttlefish
لتطوير إصدارات Android المستقبلية. يستهدف مستوى FCM وPRODUCT_SHIPPING_API_LEVEL
لإصدار Android القادم من العام المقبل، ما يتطلّب منه استيفاء متطلبات برامج المورّدين (VSR) للإصدار القادم.
عندما تكون قيمة RELEASE_AIDL_USE_UNFROZEN
هي false
، يكون لدى الحبّار السابق
target-level
وPRODUCT_SHIPPING_API_LEVEL
لإظهار جهاز إصدار.
في Android 14 والإصدارات الأقدم، سيكون هذا التفرقة
من خلال فروع Git المختلفة التي لا تعتمد التغيير في خدمة "المراسلة عبر السحابة الإلكترونية من Firebase"
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_platform
للواجهة الخلفية NDK. يُستخدَم الأول للتطبيقات، ويُستخدَم الأخير لاستخدام النظام الأساسي حتى Android 13. ضِمن الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث، يجب استخدام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)
مقارنةً بالإصدار 11 من نظام التشغيل Android:
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
- استنادًا إلى إصدار بنود الخدمة:
foo-V3-(cpp|ndk|ndk_platform|rust).so
يُرجى العِلم أنّ مُجمِّع AIDL لا يُنشئ وحدة إصدار unstable
أو وحدة غير مرتبطة بإصدار لواجهة AIDL ثابتة.
اعتبارًا من 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()
على النحو التالي (يتم استخدام super
بدلاً من IFoo
لتجنب
أخطاء النسخ واللصق. قد تحتاج إلى التعليق التوضيحي @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
وما إلى ذلك) تتم مشاركتها
بين العميل والخادم (على سبيل المثال، يمكن أن تكون الفئات في ملف booted
classpath). وعند مشاركة الصفوف، يرتبط الخادم أيضًا بـ
إصدار أحدث من الفصول الدراسية على الرغم من أنه ربما تم بناؤه باستخدام إصدار
من إصدار الواجهة. وإذا تم تنفيذ هذه الواجهة الوصفية في واجهة برمجة التطبيقات
فإنها تعرض دائمًا الإصدار الأحدث. ومع ذلك، من خلال تنفيذ الطريقة
كما هو موضح أعلاه، رقم إصدار الواجهة مضمن في رمز الخادم
(لأنّ IFoo.VERSION
هي static final int
مضمّنة عند الإشارة إليه)
وبالتالي يمكن أن تعرض الطريقة الإصدار المحدد الذي تم إنشاء الخادم باستخدامه.
التعامل مع الواجهات القديمة
من الممكن تحديث العميل إلى الإصدار الأحدث من AIDL
ولكن الخادم يستخدم واجهة AIDL القديمة. في هذه الحالات، يؤدي
استدعاء طريقة على واجهة قديمة إلى عرض القيمة UNKNOWN_TRANSACTION
.
باستخدام مكتبة AIDL الثابتة، يمكن للعملاء التحكّم بشكل أكبر. في جهة العميل، يمكنك ضبط تنفيذ تلقائي لواجهة AIDL. لا يتمّ استدعاء طريقة في التنفيذ التلقائي إلا عندما لا يتمّ تنفيذ الطريقة في الناحية المستبعَدة (لأنّه تمّ إنشاؤها باستخدام إصدار قديم من الواجهة). منذ أن يتم ضبطها تلقائيًا على مستوى العالم، يجب عدم استخدامها من جهات الاتصال التي والسياقات.
مثال في لغة C++ في نظام التشغيل Android 13 والإصدارات الأحدث:
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
من واجهة pyplot. الطرق التي يمكن ضمان تنفيذها في الجانب البعيد
(لأنك متأكد من أن جهاز التحكم عن بُعد قد تم إنشاؤه عندما كانت الطرق في
لا يلزم إلغاء وصف واجهة AIDL) في impl
التلقائي.
الصف.
تحويل لغة AIDL الحالية إلى تنسيق AIDL منظَّم أو ثابت
إذا كانت لديك واجهة AIDL حالية ورمز يستخدمها، استخدِم الخطوات التالية لتحويل الواجهة إلى واجهة AIDL ثابتة.
حدِّد جميع التبعيات لواجهة المستخدم. بالنسبة إلى كل حزمة تعتمد عليها الواجهة، حدِّد ما إذا كانت الحزمة محدّدة في حزمة AIDL الثابتة. إذا كانت هذه السمة غير محدّدة، يجب تحويل الحزمة.
حوِّل جميع العناصر القابلة للتجميع في واجهتك إلى عناصر قابلة للتجميع ثابتة (يمكن أن تظل ملفات الواجهة نفسها بدون تغيير). إجراء ذلك من خلال وتعبر عن هيكلها مباشرة في ملفات AIDL. يجب أن تتضمن صفوف الإدارة ستتم إعادة كتابته لاستخدام هذه الأنواع الجديدة. ويمكن إجراء ذلك قبل إنشاء حزمة
aidl_interface
(أدناه).أنشِئ حزمة
aidl_interface
(كما هو موضَّح أعلاه) تحتوي على واسم الوحدة وتبعياتها وأي معلومات أخرى تحتاجها. ولإضفاء ثبات على البيانات (وليس فقط تنظيمها)، يجب أيضًا تحديد إصدار لها. لمزيد من المعلومات، يُرجى الاطّلاع على واجهات تحديد الإصدار.