HIDL Java

ใน Android 8.0 ระบบปฏิบัติการ Android ได้รับการออกแบบใหม่เพื่อกำหนดอินเทอร์เฟซที่ชัดเจนระหว่างแพลตฟอร์ม Android ที่ไม่ขึ้นกับอุปกรณ์ และรหัสเฉพาะของอุปกรณ์และผู้ขาย Android กำหนดไว้แล้วการเชื่อมต่อดังกล่าวจำนวนมากในรูปแบบของการเชื่อมต่อระบบ HAL ที่กำหนดให้เป็นส่วนหัวของซีใน hardware/libhardware HIDL แทนที่อินเตอร์เฟซ HAL เหล่านี้ด้วยความมั่นคงอินเตอร์เฟซ versioned ซึ่งสามารถเป็นได้ทั้งในชวา (อธิบายด้านล่าง) หรือจะเป็นแบบ client และฝั่งเซิร์ฟเวอร์อินเตอร์เฟซ 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 จากขวดที่กำหนดเองที่ติดตั้งบนอุปกรณ์ที่มีเสถียรภาพ Java API ที่ทำให้มีการใช้ที่มีอยู่ 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 นั้นไม่มีให้ใช้งานบน Boot classpath สำหรับแอพอีกต่อไป (ก่อนหน้านี้ บางครั้งพวกมันถูกใช้เป็น API ที่ซ่อนอยู่ เนื่องจากตัวโหลดคลาสแรกที่ได้รับมอบสิทธิ์ของ Android) แต่พวกเขาได้รับการย้ายไปอยู่ที่ใหม่ที่มี namespace jarjar และปพลิเคชันที่ใช้ (ปพลิเคชันจำเป็นต้อง priv) เหล่านี้จะต้องมีสำเนาของตัวเองต่างหาก โมดูลใน classpath บูตใช้ HIDL ต้องใช้ตื้นสายพันธุ์เหล่านี้ห้องสมุด Java และเพื่อเพิ่ม jarjar_rules: ":framework-jarjar-rules" ของพวกเขา Android.bp ใช้รุ่นของห้องสมุดเหล่านี้ที่มีอยู่ใน classpath บูต

การแก้ไขซอร์ส 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 โดยใช้ขั้นตอนต่อไปนี้:

  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 ก่อนที่จะเผยแพร่ได้

เรียกใช้บริการ

ฮาลให้ 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.
}