HIDL جافا ، HIDL جافا

في Android 8.0، تمت إعادة تصميم نظام التشغيل Android لتحديد واجهات واضحة بين نظام Android الأساسي المستقل للجهاز، والتعليمات البرمجية الخاصة بالجهاز والبائع. قام Android بالفعل بتعريف العديد من هذه الواجهات في شكل واجهات HAL، والتي تم تعريفها على أنها رؤوس C في hardware/libhardware . استبدل HIDL واجهات HAL هذه بواجهات مستقرة ذات إصدار، والتي يمكن أن تكون إما في Java (موضحة أدناه) أو واجهات HIDL من جانب العميل والخادم في C++ .

تم تصميم واجهات HIDL ليتم استخدامها بشكل أساسي من التعليمات البرمجية الأصلية، ونتيجة لذلك يركز HIDL على الإنشاء التلقائي للتعليمات البرمجية الفعالة في C++. ومع ذلك، يجب أيضًا أن تكون واجهات HIDL متاحة للاستخدام مباشرةً من Java، نظرًا لأن بعض أنظمة Android الفرعية (مثل الاتصالات الهاتفية) تحتوي على واجهات Java HIDL.

تصف الصفحات الموجودة في هذا القسم واجهة Java الأمامية لواجهات HIDL، وتشرح بالتفصيل كيفية إنشاء الخدمات وتسجيلها واستخدامها، وتشرح كيفية تفاعل عملاء HALs وHAL المكتوبين بلغة Java مع نظام HIDL RPC.

كونه عميلا

هذا مثال لعميل واجهة IFoo في الحزمة android.hardware.foo@1.0 المسجلة كاسم خدمة default وخدمة إضافية باسم الخدمة المخصصة second_impl .

إضافة المكتبات

تحتاج إلى إضافة تبعيات إلى مكتبة HIDL المقابلة إذا كنت تريد استخدامها. عادةً ما تكون هذه مكتبة ثابتة:

// 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

إذا كان لديك تطبيق نظام أو مورد يستهدف Android 10 أو أعلى، فيمكنك تضمين هذه المكتبات بشكل ثابت. يمكنك أيضًا استخدام فئات HIDL (فقط) من JARs المخصصة المثبتة على الجهاز مع واجهات برمجة تطبيقات 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 ، ويجب أن يكون للتطبيقات التي تستخدم هذه (التطبيقات الخاصة بالضرورة) نسخ منفصلة خاصة بها. يجب أن تستخدم الوحدات الموجودة على مسار فئة التمهيد باستخدام HIDL المتغيرات السطحية لمكتبات Java هذه ولإضافة jarjar_rules: ":framework-jarjar-rules" إلى Android.bp لاستخدام إصدار هذه المكتبات الموجود في مسار فئة التمهيد.

تعديل مصدر جافا الخاص بك

يوجد إصدار واحد فقط ( @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 إلى تقديم واجهات لتلقي عمليات الاسترجاعات غير المتزامنة من HALs.

بالنسبة لواجهة IFooCallback في الإصدار 1.0 من الحزمة android.hardware.foo ، يمكنك تنفيذ الواجهة الخاصة بك في Java باستخدام الخطوات التالية:

  1. حدد الواجهة الخاصة بك في HIDL.
  2. افتح /tmp/android/hardware/foo/IFooCallback.java كمرجع.
  3. قم بإنشاء وحدة نمطية جديدة لتطبيق Java الخاص بك.
  4. افحص الفئة المجردة 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.
}