HIDL Java, HIDL Java

در اندروید 8.0 سیستم عامل اندروید مجدداً طراحی شد تا رابط های واضحی بین پلتفرم اندروید مستقل از دستگاه و کدهای دستگاه و فروشنده مشخص شود. اندروید قبلاً بسیاری از این رابط‌ها را در قالب رابط‌های HAL تعریف کرده است که به عنوان هدر C در hardware/libhardware تعریف می‌شود. HIDL این رابط‌های HAL را با اینترفیس‌های نسخه‌دار و پایدار جایگزین کرد، که می‌توانند در جاوا (توضیح داده شده در زیر) یا رابط‌های HIDL سمت سرویس گیرنده و سرور در C++ باشند.

اینترفیس‌های HIDL عمدتاً از کدهای بومی استفاده می‌شوند و در نتیجه HIDL بر تولید خودکار کد کارآمد در C++ متمرکز است. با این حال، رابط های HIDL نیز باید برای استفاده مستقیم از جاوا در دسترس باشند، زیرا برخی از زیرسیستم های اندروید (مانند تلفن) دارای رابط های Java HIDL هستند.

صفحات این بخش پیشانی جاوا را برای رابط‌های HIDL شرح می‌دهند، نحوه ایجاد، ثبت و استفاده از خدمات را توضیح می‌دهند و نحوه تعامل HAL و کلاینت‌های HAL نوشته شده در جاوا را با سیستم 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

ملاحظات اضافی برای افزودن کتابخانه ها در اندروید 10

اگر سیستم یا برنامه فروشنده ای دارید که Android 10 یا بالاتر را هدف قرار می دهد، می توانید این کتابخانه ها را به صورت ایستا اضافه کنید. همچنین می‌توانید از کلاس‌های HIDL (فقط) از JAR‌های سفارشی نصب‌شده روی دستگاه با رابط‌های برنامه‌نویسی برنامه‌نویسی نرم‌افزار جاوا پایدار که با استفاده از مکانیزم uses-library موجود برای برنامه‌های سیستم در دسترس هستند، استفاده کنید. روش دوم باعث صرفه جویی در فضا در دستگاه می شود. برای جزئیات بیشتر، به اجرای کتابخانه Java SDK مراجعه کنید. برای برنامه های قدیمی تر، رفتار قدیمی حفظ می شود.

با شروع اندروید 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 از آن‌ها به عنوان API پنهان استفاده می‌شدند). در عوض، آنها به یک فضای نام جدید با jarjar منتقل شده‌اند و برنامه‌هایی که از اینها استفاده می‌کنند (الزاماً برنامه‌های خصوصی) باید کپی‌های جداگانه خود را داشته باشند. ماژول‌های موجود در مسیر کلاس بوت با استفاده از HIDL باید از انواع کم عمق این کتابخانه‌های جاوا استفاده کنند و 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(…);

ارائه خدمات

کد فریم ورک در جاوا ممکن است برای دریافت تماس های ناهمزمان از HAL ها به رابط ها نیاز داشته باشد.

برای رابط IFooCallback در نسخه 1.0 بسته android.hardware.foo ، می توانید با استفاده از مراحل زیر رابط خود را در جاوا پیاده سازی کنید:

  1. رابط کاربری خود را در HIDL تعریف کنید.
  2. /tmp/android/hardware/foo/IFooCallback.java را به عنوان مرجع باز کنید.
  3. یک ماژول جدید برای پیاده سازی جاوا خود ایجاد کنید.
  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 را تولید می‌کند که رابط جاوا، کد پراکسی، و خرده‌ها (هر دو پراکسی) را در بر می‌گیرد. و خرد مطابق با رابط).

-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() جاوا برای فرستادن ایمن رابط پایه به رابط توسعه یافته استفاده کند:

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.
}