ב-Android 8.0, מערכת Android OS יצרה ארכיטקטורה מחדש כדי להגדיר ממשקים ברורים
בין פלטפורמת Android שלא תלויה במכשיר לבין פלטפורמה ספציפית למכשיר או לספק
מערכת Android כבר הגדירו הרבה ממשקים כאלה בפורמט HAL
ממשקים, שמוגדרים ככותרות C ב-hardware/libhardware
. hiDL
החליפו את ממשקי HAL האלה בממשקים יציבים בעלי גרסאות, שיכולים
להיות ב-Java (מתוארות בהמשך) או ב-HIDL בצד הלקוח ובשרת
ו-C++.
ממשקי HIDL מיועדים לשימוש בעיקר מקוד נייטיב, התוצאה HIDL מתמקדת בהפקה אוטומטית של קוד יעיל ב-C++. אבל, לפעמים גם ממשקי HIDL חייבים להיות זמינים לשימוש ישירות מ-Java, מאחר שבחלק ממערכות Android במערכות משנה (כמו טלפוניה) יש ממשקי Java HIDL.
הדפים בקטע הזה מתארים את החזית של Java לממשקי 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 (בלבד)
מ-JAR מותאמים אישית שמותקנים במכשיר עם ממשקי API יציבים של Java שזמינים
באמצעות מנגנון uses-library
הקיים לאפליקציות מערכת.
בגישה השנייה חוסכת מקום במכשיר. פרטים נוספים זמינים במאמר הטמעה של ספריית Java SDK. עבור
באפליקציות ישנות, ההתנהגות הישנה נשמרת.
החל מ-Android 10, 'shallow' גרסאות של הספריות
זמינים גם כן. המסמכים האלה כוללים את הכיתה הרלוונטית, אבל לא כוללים
של המחלקות התלויות. לדוגמה,
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 וספריות הניהול כבר לא זמינות באתחול
classpath של אפליקציה (לשעבר, הם שימשו לפעמים כ-API מוסתר, בגלל
הענקת גישה ראשונה ל-Android). במקום זאת, הם הועברו
מרחב שמות עם jarjar
, ואפליקציות שמשתמשות בהרשאה הזו (אין צורך
אפליקציות) חייבים להיות עותקים נפרדים משלהם. מודולים בנתיב הכיתה של האתחול באמצעות
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, את קוד ה-Proxy ואת ה-stubs (גם Proxy וגם
stubs תואמים לממשק).
הפקודה -Lmakefile
יוצרת את הכללים שמריצים את הפקודה הזו ב-build.
ומאפשרת לכם לכלול
android.hardware.foo-V1.0-java
וקישור אל
הקבצים המתאימים. סקריפט שעושה זאת באופן אוטומטי עבור פרויקט מלא
הממשקים נמצאים ב-hardware/interfaces/update-makefiles.sh
.
הנתיבים בדוגמה הזו הם יחסיים; חומרה/ממשקים יכולים להיות
שמתחת לעץ הקוד כדי לאפשר לכם לפתח HAL לפני
לפרסם אותו.
הפעלת שירות
ממשק ה-HAL מספק את הממשק IFoo
, שחייב להיות אסינכרוני
קריאות חוזרות ל-framework דרך הממשק של IFooCallback
.
הממשק של IFooCallback
לא רשום לפי שם כממשק שגלוי לכולם
service; במקום זאת, IFoo
חייב להכיל method כמו
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()
method Java כדי להפעיל Cast של ממשק הבסיס באופן בטוח
בממשק מורחב:
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. }