HIDL Java

ב- Android 8.0 מערכת ההפעלה אנדרואיד נבנתה מחדש כדי להגדיר ממשקים ברורים בין פלטפורמת אנדרואיד הבלתי תלויה במכשיר, לבין קוד ספציפי למכשירים ולספקים. אנדרואיד כבר מוגדר ממשקים רבים כאלה בצורת ממשקי HAL, המוגדרים כותרות C ב hardware/libhardware . HIDL החליף ממשקי HAL אלה עם ממשקים יציבים, versioned, אשר גם יכול להיות ב- Java (כמתואר להלן) או להיות ממשקי HIDL client- ו בצד השרת ב- C ++ .

ממשקי HIDL מיועדים לשימוש בעיקר מקוד מקורי, וכתוצאה מכך HIDL מתמקד ביצירת אוטומטי של קוד יעיל ב- C ++. עם זאת, ממשקי HIDL חייבים להיות זמינים לשימוש ישירות מג'אווה, מכיוון שלמערכות משנה מסוימות של Android (כגון טלפוניה) יש ממשקי Java HIDL.

הדפים בסעיף זה מתארים את חזית הג'אווה של ממשקי HIDL, מפרטים כיצד ליצור, לרשום ולהשתמש בשירותים, ולהסביר כיצד אינטראקציות של HAL ולקוחות HAL שנכתבו ב- Java מתקיימות עם מערכת HIDL RPC.

להיות לקוח

זוהי דוגמא של לקוח עבור ממשק IFoo בחבילה android.hardware.foo@1.0 כי רשום לשירות שם default ואת שירות נוסף עם שם שירות המותאם אישית second_impl .

הוספת ספריות

עליך להוסיף תלות בספריית ה- 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

אם אתה יודע שאתה כבר משתמש בתלות בספריות אלה, תוכל גם להשתמש בקישור משותף:

// 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 מתוך צנצנות מנהג המותקנת במכשיר עם APIs Java היציב לרשות באמצעות קיימים uses-library מנגנון אפליקציות מערכת. הגישה האחרונה חוסכת מקום במכשיר. לפרטים נוספים, ראה 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 וספריות המנהל אינן זמינות יותר במסלול האתחול לאפליקציות (בעבר, הן שימשו לעתים כ- API מוסתר, בגלל מטעין הכיתות הראשון של אנדרואיד). במקום זאת, הם כבר עברו לגור מרחב חדש עם jarjar , וכן באפליקציות שבן נעשה שימוש אלה (בהכרח אפליקציות priv) חייבות להיות עותקים נפרדים משלהם. מודולים על classpath האתחול באמצעות HIDL חייב להשתמש רדוד וריאנטים של ספריות ג'אווה אלה וכדי להוסיף 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(…);

מתן שירות

קוד מסגרת בג'אווה עשוי להזדקק לשרת ממשקים כדי לקבל התקשרויות אסינכרוניות מחברות HAL.

עבור IFooCallback הממשק בגרסה 1.0 של android.hardware.foo החבילה, אתה יכול ליישם את הממשק ב- Java באמצעות השלבים הבאים:

  1. הגדר את הממשק שלך ב- HIDL.
  2. Open /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.
}