ใน Android 8.0 ระบบปฏิบัติการ Android ได้รับการออกแบบใหม่เพื่อกำหนดอินเทอร์เฟซที่ชัดเจนระหว่างแพลตฟอร์ม Android ที่ไม่ขึ้นกับอุปกรณ์ และรหัสเฉพาะของอุปกรณ์และผู้ขาย Android ได้กำหนดอินเทอร์เฟซดังกล่าวไว้มากมายในรูปแบบของอินเทอร์เฟซ HAL ซึ่งกำหนดเป็นส่วนหัว C ใน hardware/libhardware
HIDL แทนที่อินเทอร์เฟซ HAL เหล่านี้ด้วยอินเทอร์เฟซที่มีเวอร์ชันเสถียร ซึ่งสามารถอยู่ใน Java (อธิบายด้านล่าง) หรือเป็นอินเทอร์เฟซ HIDL ฝั่งไคลเอ็นต์และเซิร์ฟเวอร์ใน C++
อินเทอร์เฟซ HIDL มีวัตถุประสงค์เพื่อใช้เป็นหลักจากโค้ดเนทีฟ และด้วยเหตุนี้ HIDL จึงมุ่งเน้นไปที่การสร้างโค้ดที่มีประสิทธิภาพโดยอัตโนมัติใน C++ อย่างไรก็ตาม อินเทอร์เฟซ HIDL จะต้องพร้อมใช้งานโดยตรงจาก Java เนื่องจากระบบย่อย Android บางระบบ (เช่น Telephony) มีอินเทอร์เฟซ Java HIDL
หน้าในส่วนนี้จะอธิบายส่วนหน้า Java สำหรับอินเทอร์เฟซ HIDL รายละเอียดวิธีการสร้าง ลงทะเบียน และใช้บริการ และอธิบายว่า HAL และไคลเอ็นต์ 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 จาก JAR แบบกำหนดเองที่ติดตั้งบนอุปกรณ์ที่มี Java API ที่เสถียรซึ่งพร้อมใช้งานโดย uses-library
ที่มีอยู่สำหรับแอประบบ วิธีหลังช่วยประหยัดพื้นที่บนอุปกรณ์ สำหรับรายละเอียดเพิ่มเติม โปรดดูที่ Implementing Java SDK Library สำหรับแอปที่เก่ากว่า การทำงานแบบเก่าจะยังคงอยู่
ตั้งแต่ 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 นั้นไม่มีให้ใช้งานบน Boot classpath สำหรับแอพอีกต่อไป (ก่อนหน้านี้ บางครั้งพวกมันถูกใช้เป็น API ที่ซ่อนอยู่ เนื่องจากตัวโหลดคลาสแรกที่ได้รับมอบสิทธิ์ของ Android) พวกเขาถูกย้ายไปยังเนมสเปซใหม่ด้วย jarjar
และแอพที่ใช้สิ่งเหล่านี้ (แอพ Priv ที่จำเป็น) จะต้องมีสำเนาแยกต่างหาก โมดูลบนบูตคลาสพาธที่ใช้ 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
จากแพ็คเกจ android.hardware.foo
เวอร์ชัน 1.0 ให้เพิ่ม 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. }