في الإصدار 8.0 من Android، تمت إعادة تصميم نظام التشغيل لتحديد واجهات واضحة
بين منصة Android المستقلة عن الجهاز والرمز المبرمَج الخاص بالجهاز والمورّد. لقد حدّد نظام التشغيل Android العديد من هذه الواجهات في شكل واجهات HAL
، والتي تم تحديدها كرؤوس C في hardware/libhardware
. حلّت HIDL
محل واجهات HAL هذه بواجهات ثابتة ومُحدَّدة الإصدار، والتي يمكن أن تكون
باستخدام Java (كما هو موضّح أدناه) أو واجهات HIDL
لجهة العميل والخادم باستخدام C++.
يُقصد استخدام واجهات HIDL بشكل أساسي من الرموز البرمجية الأصلية، ونتيجةً لذلك، تركز HIDL على إنشاء رمز برمجي فعّال تلقائيًا بلغة C++. ومع ذلك، يجب أن تكون واجهات HIDL متاحة أيضًا للاستخدام مباشرةً من Java، لأنّ بعض الأنظمة الفرعية في Android (مثل نظام الهاتف) تتضمّن واجهات Java HIDL.
تصف الصفحات في هذا القسم الواجهة الأمامية لـ Java لواجهات HIDL، ويشرح بالتفصيل كيفية إنشاء الخدمات وتسجيلها واستخدامها، ويوضّح كيفية تفاعل واجهات HAL وHAL العملاء المكتوبة بلغة Java مع نظام HIDL RPC.
مثال على العميل
في ما يلي مثال على واجهة IFoo
في الحزمة
android.hardware.foo@1.0
المسجَّلة باسم الخدمة
default
وخدمة إضافية باسم الخدمة المخصّص
second_impl
.
إضافة مكتبات
عليك إضافة تبعيات على مكتبة HIDL stub library المقابلة إذا أردت استخدامها. وعادةً ما تكون هذه مكتبة ثابتة:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
إذا كنت تعرف أنّك تستخدِم حاليًا مكتبات تابعة لهذه المكتبات، يمكنك أيضًا استخدام الربط المشترَك:
// in Android.bp libs: [ "android.hardware.foo-V1.0-java", ], // in Android.mk LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java
اعتبارات إضافية لإضافة مكتبات في Android 10
إذا كان لديك تطبيق نظام أو مطوِّر يستهدف الإصدار 10 من نظام التشغيل Android أو إصدارًا أحدث،
يمكنك تضمين هذه المكتبات بشكل ثابت. يمكنك أيضًا استخدام فئات HIDL (فقط)
من حِزم JAR المخصّصة المثبَّتة على الجهاز مع توفير واجهات برمجة تطبيقات Java الثابتة
باستخدام آلية uses-library
الحالية لتطبيقات النظام. ويؤدي استخدام الأسلوب
الأخير إلى توفير مساحة على الجهاز. لمزيد من التفاصيل، يُرجى الاطّلاع على مقالة تنفيذ مكتبة Java SDK. بالنسبة إلى
التطبيقات القديمة، يتم الاحتفاظ بالسلوك القديم.
بدءًا من Android 10، أصبحت أيضًا الإصدارات "البسيطة" من هذه المكتبات متوفرة. وتشمل هذه الصفّ المعنيّ، ولكنّها لا تشمل أيًا
من الصفوف التابعة. على سبيل المثال، يحتوي ملف تعريف الارتباط
android.hardware.foo-V1.0-java-shallow
على فئات في حزمة foo
، ولكنّه لا يحتوي على فئات في
android.hidl.base-V1.0-java
، الذي يحتوي على الفئة الأساسية لجميع واجهت
HIDL. إذا كنت بصدد إنشاء مكتبة تتضمّن حاليًا فئات أساسية
للواجهة المفضّلة كعنصر تابع، يمكنك استخدام ما يلي:
// in Android.bp static_libs: [ "android.hardware.foo-V1.0-java-shallow", ], // in Android.mk LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow
لم تعُد مكتبتا HIDL الأساسية والمديرة متوفّرتان أيضًا في ملف مسار تحميل تطبيقات التمهيد (كانتا تُستخدَمان في السابق كواجهة برمجة تطبيقات مخفية، وذلك بسبب ملف تحميل الفئات الذي يعتمد على المفوّض أولاً في Android). بدلاً من ذلك، تم نقلها إلى مساحة اسم
جديدة باستخدام jarjar
، ويجب أن تتضمّن التطبيقات التي تستخدم هذه التطبيقات (priv
apps) نسخًا منفصلة خاصة بها. يجب أن تستخدم الوحدات في مسار تحميل التمهيد التي تستخدم
HIDL الصيغ البسيطة لمكتبات Java هذه وأن تضيف
jarjar_rules: ":framework-jarjar-rules"
إلى
Android.bp
لاستخدام إصدار هذه المكتبات المتوفّر
في مسار تحميل التمهيد.
تعديل رمز مصدر Java
يتوفّر إصدار واحد فقط (@1.0
) من هذه الخدمة، لذا لا يسترجع هذا الرمز سوى هذا الإصدار. اطّلِع على إضافات الواجهة للتعرّف على كيفية التعامل مع إصدارات متعددة مختلفة من الخدمة.
import android.hardware.foo.V1_0.IFoo; ... // retry to wait until the service starts up if it is in the manifest IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IFoo anotherServer = IFoo.getService("second_impl", true /* retry */); server.doSomething(…);
تقديم خدمة
قد يحتاج رمز الإطار في Java إلى عرض واجهات لتلقّي طلبات إعادة الاتصال غير المتزامنة من واجهات HAL.
بالنسبة إلى واجهة IFooCallback
في الإصدار 1.0 من حزمة
android.hardware.foo
، يمكنك تنفيذ الواجهة في
Java باستخدام الخطوات التالية:
- حدِّد واجهتك في HIDL.
- افتح
/tmp/android/hardware/foo/IFooCallback.java
كمرجع. - أنشئ وحدة جديدة لتنفيذ Java.
- راجِع الفئة المجردة
android.hardware.foo.V1_0.IFooCallback.Stub
، ثم اكتب فئة جديدة لتوسيع نطاقها وتنفيذ الطرق المجردة.
عرض الملفات التي تم إنشاؤها تلقائيًا
للاطّلاع على الملفات التي تم إنشاؤها تلقائيًا، يمكنك تنفيذ ما يلي:
hidl-gen -o /tmp -Ljava \ -randroid.hardware:hardware/interfaces \ -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0
تنشئ هذه الأوامر الدليل
/tmp/android/hardware/foo/1.0
. بالنسبة إلى الملف
hardware/interfaces/foo/1.0/IFooCallback.hal
، يؤدي ذلك إلى إنشاء
الملف /tmp/android/hardware/foo/1.0/IFooCallback.java
الذي
يحتوي على واجهة Java ورمز الوكيل والعناصر المصغّرة (تتوافق كلّ من العناصر المصغّرة والوكيل مع الواجهة).
ينشئ -Lmakefile
القواعد التي تُنفِّذ هذا الأمر في وقت الإنشاء، ويسمح لك بتضمين
android.hardware.foo-V1.0-java
والربط بالملفّات المناسبة. يمكن العثور على نص برمجي ينفّذ ذلك تلقائيًا لمشروع مليء
بالواجهات على الرابط hardware/interfaces/update-makefiles.sh
.
المسارات في هذا المثال نسبية، ويمكن أن تكون الأجهزة/الواجهات ملفًا مؤقتًا
ضمن شجرة الرموز البرمجية لتتمكّن من تطوير HAL قبل
نشره.
تشغيل خدمة
يوفّر HAL واجهة IFoo
التي يجب أن تُجري مكالمات تكميلية غير متزامنة للإطار على واجهة IFooCallback
. لا يتم تسجيل واجهة
IFooCallback
باسم كخدمة قابلة للاكتشاف، بل يجب أن تحتوي IFoo
على طريقة مثل
setFooCallback(IFooCallback x)
.
لإعداد IFooCallback
من الإصدار 1.0 من حزمة
android.hardware.foo
، أضِف
android.hardware.foo-V1.0-java
إلى Android.mk
. التعليمة البرمجية
لتشغيل الخدمة هي:
import android.hardware.foo.V1_0.IFoo; import android.hardware.foo.V1_0.IFooCallback.Stub; .... class FooCallback extends IFooCallback.Stub { // implement methods } .... // Get the service from which you will be receiving callbacks. // This also starts the threadpool for your callback service. IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available .... // This must be a persistent instance variable, not local, // to avoid premature garbage collection. FooCallback mFooCallback = new FooCallback(); .... // Do this once to create the callback service and tell the "foo-bar" service server.setFooCallback(mFooCallback);
إضافات الواجهة
على افتراض أنّ خدمة معيّنة تنفِّذ واجهة IFoo
على جميع
الأجهزة، من الممكن أن توفّر الخدمة على جهاز معيّن
إمكانات إضافية يتم تنفيذها في إضافة الواجهة
IBetterFoo
، على النحو التالي:
interface IFoo { ... }; interface IBetterFoo extends IFoo { ... };
يمكن للرمز المُطلِب الذي يُدرك الواجهة الموسَّعة استخدام castFrom()
طريقة Java لتحويل الواجهة الأساسية إلى الواجهة الموسَّعة بأمان:
IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available IBetterFoo extendedService = IBetterFoo.castFrom(baseService); if (extendedService != null) { // The service implements the extended interface. } else { // The service implements only the base interface. }