لغة AIDL ثابتة

نظام Android 10 يتيح استخدام واجهة Android ثابتة لغة التعريف (AIDL)، وهي طريقة جديدة لتتبع برنامج تقديم الطلبات (API) وواجهة التطبيق الثنائية (ABI) التي توفّرها AIDL من الواجهات. يعمل AIDL الثابتة تمامًا مثل AIDL، ولكن نظام الإصدار يتتبع التوافق مع واجهة المستخدم، وهناك قيود على ما يمكنك فعله:

  • يتم تحديد الواجهات في نظام الإصدار باستخدام aidl_interfaces.
  • يمكن أن تحتوي الواجهات على بيانات منظَّمة فقط. قطع الأراضي التي تمثّل يتم إنشاء الأنواع المفضلة تلقائيًا بناءً على تعريف AIDL الخاصة بها يتم تشكيلها وترتيبها تلقائيًا.
  • يمكن تعريف الواجهات على أنّها مستقرة (متوافقة مع الأنظمة القديمة). عندما يكون هذا يتم تتبُّع واجهة برمجة التطبيقات الخاصة بها وإصدار إصدارات منها في ملف بجانب AIDL من واجهة pyplot.

لغة 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 التي تنشئ الواجهة المسار بالنسبة إلى نوع AIDL Foo المحدَّد في الحزمة 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 من نظام التشغيل Android
  • backend.<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: تم الطرح في في 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.

بالنسبة إلى كل مجموعة من الإصدارات والخلفيات المفعَّلة، يمكن استخدام رمز بديل إنشاء مكتبة جديدة. للتعرّف على كيفية الرجوع إلى الإصدار المحدّد من مكتبة التنويهات الموجزة لخلفية معينة، يرجى الاطّلاع على قواعد تسمية الوحدات.

كتابة ملفات 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-free-api إضافة تعريف جديد لواجهة برمجة التطبيقات ضمن api_dir أو aidl_api/name، استنادًا إلى إصدار Android تضيف ملف .hash، وكلاهما يمثل الإصدار المجمّد حديثًا من من واجهة pyplot. تعمل foo-depth-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" أو "اختبار".

استقرار الواردات

تحديث إصدارات عمليات الاستيراد للإصدارات المجمّدة من الواجهة هو متوافقة مع الأنظمة القديمة في طبقة 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"],
  ...
}

التطوير المستند إلى العلم

لا يمكن استخدام الواجهات قيد التطوير (غير مجمّدة) على أجهزة الإصدار، لأنه ليس مضمونًا أنها متوافقة مع الأنظمة القديمة.

تدعم AIDL الاحتفاظ بنسخة احتياطية من وقت التشغيل لمكتبات الواجهات غير المجمدة بالترتيب لتتم كتابة الرمز البرمجي وفقًا لأحدث نسخة غير مجمّدة ويستمر استخدامه على أجهزة الإصدار. يشبه سلوك التوافق مع الأنظمة القديمة للعملاء السلوك الحالي ومع الإجراء الاحتياطي، تحتاج عمليات التنفيذ أيضًا إلى اتباع هذه السلوكيات. عرض استخدام الواجهات ذات الإصدارات:

علامة إصدار 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 الجديد المكتبة. نظرًا لأن مكتبة 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 وقيم الحقول الجديدة التي تحاول الخدمة إرسالها طريقة الخروج من العملية.

لا يمكن إرسال الأنواع الجديدة التي تمت إضافتها في هذا الإصدار غير المجمّد. أو استلامها من خلال الواجهة.

لا تطلب عملية التنفيذ أبدًا استخدام طرق جديدة من أي عميل عندما تم 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() إذا تم الإعلان عنه وفشل تسجيله، فعندئذ إلغاء العملية. وإذا لم يتم الإعلان عن نتيجة الاختبار، من المتوقّع أن يتعذّر تسجيلها.

الحبار كأداة للتنمية

بعد تجميد VINTF كل عام، يتم تعديل توافق إطار العمل. مصفوفة (FCM) target-level وPRODUCT_SHIPPING_API_LEVEL للحبار لذا فهي تعكس الأجهزة التي يتم إطلاقها مع إصدار العام المقبل. نقوم بتعديل target-level وPRODUCT_SHIPPING_API_LEVEL للتأكد من وجود بعض لإطلاق جهاز تم اختباره ويلبي المتطلبات الجديدة للعام المقبل .

عندما تكون قيمة RELEASE_AIDL_USE_UNFROZEN هي true، يكون الحبار في تطوير إصدارات Android المستقبلية. تستهدف نظام التشغيل Android للعام المقبل مستوى خدمة "المراسلة عبر السحابة الإلكترونية من Firebase" في الإصدار وPRODUCT_SHIPPING_API_LEVEL، ما يتطلب أن يستوفي متطلبات برامج البائعين (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. الأولى مخصصة للتطبيقات أمّا الخيار الثاني، فهو لاستخدام النظام الأساسي لغاية الإصدار 13 من نظام التشغيل Android. ضِمن الإصدار 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)
  • استنادًا إلى إصدار بنود الخدمة
    • foo-V3-(java|cpp|ndk|ndk_platform|rust)

مقارنةً بالإصدار 11 من نظام التشغيل Android:

  • foo-backend، الذي أشار إلى أحدث سعر ثابت يصبح الإصدار foo-V2-backend
  • foo-unstable-backend، التي أشارت إلى "بنود الخدمة" يصبح الإصدار 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();

مثال مع الواجهة الخلفية ndkndk_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 وما إلى ذلك) بين العميل والخادم (على سبيل المثال، يمكن أن تكون الفئات في نظام التشغيل 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 مستقرة.

  1. تحديد جميع تبعيات واجهتك. لكل حزمة المستخدم على واجهة المستخدم، يجب تحديد ما إذا كانت الحزمة محدّدة في واجهة AIDL الثابتة. في حال حذف غير محدد، يجب تحويل الحزمة.

  2. يمكنك تحويل جميع العناصر في واجهتك إلى عناصر ثابتة ( ملفات الواجهة نفسها يمكن أن تظل دون تغيير). إجراء ذلك من خلال وتعبر عن هيكلها مباشرة في ملفات AIDL. يجب أن تتضمن صفوف الإدارة ستتم إعادة كتابته لاستخدام هذه الأنواع الجديدة. ويمكن إجراء ذلك قبل إنشاء حزمة aidl_interface (أدناه).

  3. أنشِئ حزمة aidl_interface (كما هو موضَّح أعلاه) تحتوي على واسم الوحدة وتبعياتها وأي معلومات أخرى تحتاجها. لتحقيق استقرار (وليس منظمًا فقط)، يجب أيضًا تحديد نُسخ مختلفة منه. لمزيد من المعلومات، اطّلِع على واجهات تحديد الإصدارات.