ใน 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
เพิ่มไลบรารี
คุณต้องเพิ่มทรัพยากร Dependency ในไลบรารี Stub ของ 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
ถ้าคุณทราบว่าคุณได้ดึงทรัพยากร Dependency ในไลบรารีเหล่านี้แล้ว คุณสามารถ สามารถใช้ลิงก์ที่แชร์ได้ด้วย โดยทำดังนี้
// 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
ที่มีอยู่สำหรับแอประบบ
แนวทางหลังจะช่วยประหยัดพื้นที่ในอุปกรณ์ ดูรายละเอียดเพิ่มเติมได้ที่การใช้งานไลบรารี Java SDK สำหรับ
แอปรุ่นเก่า การทำงานแบบเดิมจะยังคงอยู่
เริ่มต้นใน Android 10 "Shallow" เวอร์ชันของไลบรารีเหล่านี้
พร้อมให้บริการด้วย ซึ่งรวมชั้นเรียนที่เป็นปัญหา แต่ไม่รวมชั้นเรียน
ของคลาสที่ต้องพึ่งพากัน ตัวอย่างเช่น
android.hardware.foo-V1.0-java-shallow
รวมชั้นเรียนใน foo
แต่ไม่รวมคลาสใน
android.hidl.base-V1.0-java
ซึ่งมีคลาสฐานของทั้งหมด
อินเทอร์เฟซ HIDL ถ้าคุณสร้างไลบรารีที่มี
คลาสพื้นฐานของอินเทอร์เฟซเป็น Dependency ที่คุณสามารถใช้ได้ ดังนี้
// 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 และไลบรารีบัญชีดูแลจัดการจะใช้ในการเปิดเครื่องไม่ได้อีก
classpath สำหรับแอป (ก่อนหน้านี้บางครั้งถูกใช้เป็น API ที่ซ่อนอยู่เนื่องจาก
Classloader แรกที่ได้รับมอบสิทธิ์ของ 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 อาจต้องแสดงผลอินเทอร์เฟซเพื่อรับแบบอะซิงโครนัส Callback จาก 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
ซึ่งต้องทำแบบอะซิงโครนัส
Callback ไปยังเฟรมเวิร์กผ่านอินเทอร์เฟซ 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. }