סגנון הקוד HIDL דומה לקוד C++ במסגרת Android, עם כניסות של 4 רווחים ושמות קבצים מעורבים באותיות גדולות. הצהרות חבילות, ייבוא ו-docstrings דומים לאלה שב-Java, עם שינויים קלים.
הדוגמאות הבאות עבור IFoo.hal
ו- types.hal
ממחישות סגנונות קוד HIDL ומספקות קישורים מהירים לפרטים על כל סגנון ( IFooClientCallback.hal
, IBar.hal
ו- IBaz.hal
הושמטו).
hardware/interfaces/foo/1.0/IFoo.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; import android.hardware.bar@1.0::IBar; import IBaz; import IFooClientCallback; /** * IFoo is an interface that… */ interface IFoo { /** * This is a multiline docstring. * * @return result 0 if successful, nonzero otherwise. */ foo() generates (FooStatus result); /** * Restart controller by power cycle. * * @param bar callback interface that… * @return result 0 if successful, nonzero otherwise. */ powerCycle(IBar bar) generates (FooStatus result); /** Single line docstring. */ baz(); /** * The bar function. * * @param clientCallback callback after function is called * @param baz related baz object * @param data input data blob */ bar(IFooClientCallback clientCallback, IBaz baz, FooData data); }; |
hardware/interfaces/foo/1.0/types.hal |
---|
/* * (License Notice) */ package android.hardware.foo@1.0; /** Replied status. */ enum Status : int32_t { OK, /* invalid arguments */ ERR_ARG, /* note, no transport related errors */ ERR_UNKNOWN = -1, }; struct ArgData { int32_t[20] someArray; vec<uint8_t> data; }; |
מוסכמות שמות
שמות פונקציות, שמות משתנים ושמות קבצים צריכים להיות תיאוריים; להימנע מקיצור יתר. התייחס לראשי תיבות כמילים (למשל, השתמש ב- INfc
במקום ב- INFC
).
מבנה ספריות ושם קבצים
מבנה הספריות אמור להופיע באופן הבא:
-
ROOT-DIRECTORY
-
MODULE
-
SUBMODULE
(אופציונלי, יכול להיות יותר מרמה אחת)-
VERSION
-
Android.mk
-
I INTERFACE_1 .hal
-
I INTERFACE_2 .hal
-
…
-
I INTERFACE_N .hal
-
types.hal
(אופציונלי)
-
-
-
-
איפה:
-
ROOT-DIRECTORY
הוא:-
hardware/interfaces
לחבילות ליבה HIDL. -
vendor/ VENDOR /interfaces
לחבילות ספקים, כאשרVENDOR
מתייחס לספק SoC או OEM/ODM.
-
-
MODULE
צריכה להיות מילה אחת קטנה שמתארת את תת המערכת (למשלnfc
). אם יש צורך ביותר ממילה אחת, השתמש ב-SUBMODULE
מקונן. יכולה להיות יותר מרמה אחת של קינון. -
VERSION
צריכה להיות אותה גרסה בדיוק (major.minor) כפי שמתואר בגירסאות . -
I INTERFACE_X
צריך להיות שם הממשק עםUpperCamelCase
/PascalCase
(למשלINfc
) כמתואר בשמות ממשקים .
דוגמא:
-
hardware/interfaces
-
nfc
-
1.0
-
Android.mk
-
INfc.hal
-
INfcClientCallback.hal
-
types.hal
-
-
-
הערה: כל הקבצים חייבים להיות בעלי הרשאות שאינן ניתנות להפעלה (ב-Git).
שמות חבילות
שמות החבילות חייבים להשתמש בפורמט השם המלא (FQN) הבא (המכונה PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
איפה:
-
PACKAGE
היא החבילה שממפה ל-ROOT-DIRECTORY
. בפרט,PACKAGE
היא:-
android.hardware
עבור חבילות ליבה HIDL (מיפויhardware/interfaces
). -
vendor. VENDOR .hardware
עבור חבילות ספקים, כאשרVENDOR
מתייחס לספק SoC או OEM/ODM (מיפויvendor/ VENDOR /interfaces
).
-
-
MODULE [. SUBMODULE [. SUBMODULE […]]]@ VERSION
הם אותם שמות תיקיות בדיוק במבנה המתואר במבנה Directory . - שמות החבילות צריכים להיות באותיות קטנות. אם הן באורך יותר ממילה אחת, יש להשתמש במילים כתת-מודולים או לכתוב ב-
snake_case
. - אסור להכניס רווחים.
ה-FQN משמש תמיד בהצהרות חבילות.
גרסאות
גרסאות צריכות להיות בפורמט הבא:
MAJOR.MINOR
גם הגרסה ה- MAJOR וגם ה- MINOR צריכות להיות מספר שלם בודד. HIDL משתמש בכללי גירסאות סמנטיים .
יבוא
לייבוא יש אחד משלושת הפורמטים הבאים:
- יבוא חבילה שלמה:
import PACKAGE-NAME ;
- יבוא חלקי:
import PACKAGE-NAME :: UDT ;
(או, אם הסוג המיובא נמצא באותה חבילה,import UDT ;
- ייבוא מסוגים בלבד:
import PACKAGE-NAME ::types;
PACKAGE-NAME
עוקב אחר הפורמט בשמות החבילות . ה- types.hal
של החבילה הנוכחית (אם היא קיימת) מיובא אוטומטית (אין לייבא אותה במפורש).
שמות מתאימים לחלוטין (FQNs)
השתמש בשמות מתאימים לחלוטין עבור ייבוא סוג מוגדר על ידי משתמש רק כאשר יש צורך. השמט PACKAGE-NAME
אם סוג הייבוא נמצא באותה חבילה. אסור ל-FQN להכיל רווחים. דוגמה לשם מלא:
android.hardware.nfc@1.0::INfcClientCallback
בקובץ אחר תחת android.hardware.nfc@1.0
, עיין בממשק לעיל בשם INfcClientCallback
. אחרת, השתמש רק בשם המלא.
קיבוץ והזמנת יבוא
השתמש בשורה ריקה לאחר הצהרת החבילה (לפני היבוא). כל ייבוא צריך לתפוס שורה בודדת ואין להזין אותו. קבץ יבוא בסדר הבא:
- חבילות
android.hardware
אחרות (השתמש בשמות מתאימים לחלוטין). -
vendor. VENDOR
חבילותvendor. VENDOR
(השתמש בשמות מתאימים לחלוטין).- כל ספק צריך להיות קבוצה.
- הזמינו ספקים בסדר אלפביתי.
- יבוא מממשקים אחרים באותה חבילה (השתמש בשמות פשוטים).
השתמש בשורה ריקה בין קבוצות. בתוך כל קבוצה, מיין ייבוא לפי אלפביתי. דוגמא:
import android.hardware.nfc@1.0::INfc; import android.hardware.nfc@1.0::INfcClientCallback; /* Importing the whole module. */ import vendor.barvendor.bar@3.1; import vendor.foovendor.foo@2.2::IFooBar; import vendor.foovendor.foo@2.2::IFooFoo; import IBar; import IFoo;
שמות ממשקים
שמות ממשקים חייבים להתחיל עם I
, ואחריו שם UpperCamelCase
/ PascalCase
. יש להגדיר ממשק עם השם IFoo
בקובץ IFoo.hal
. קובץ זה יכול להכיל הגדרות רק עבור ממשק IFoo
(הממשק I NAME
צריך להיות ב- I NAME .hal
).
פונקציות
עבור שמות פונקציות, ארגומנטים ושמות משתנים להחזר, השתמש ב- lowerCamelCase
. דוגמא:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
שמות שדות מבנה/איגוד
עבור שמות שדות struct/union, השתמש ב- lowerCamelCase
. דוגמא:
struct FooReply { vec<uint8_t> replyData; }
הקלד שמות
שמות סוגים מתייחסים להגדרות struct/union, הגדרות סוג enum ו- typedef
s. עבור שמות אלה, השתמש ב- UpperCamelCase
/ PascalCase
. דוגמאות:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
ערכי מנה
ערכי ה-Enum צריכים להיות UPPER_CASE_WITH_UNDERSCORES
. כאשר מעבירים ערכי enum כארגומנטים של פונקציה ומחזירים אותם כמחזירי פונקציה, השתמש בסוג ה-enum בפועל (לא בסוג המספר השלם הבסיסי). דוגמא:
enum NfcStatus : int32_t { HAL_NFC_STATUS_OK = 0, HAL_NFC_STATUS_FAILED = 1, HAL_NFC_STATUS_ERR_TRANSPORT = 2, HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 3, HAL_NFC_STATUS_REFUSED = 4 };
הערה: הסוג הבסיסי של סוג enum מוצהר במפורש אחרי המעי הגס. מכיוון שהוא אינו תלוי מהדר, השימוש בסוג ה-enum בפועל ברור יותר.
עבור שמות מלאים עבור ערכי enum, נעשה שימוש בנקודתיים בין שם סוג ה-enum לשם ערך ה-enum:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
אסור שיהיו רווחים בתוך שם מלא. השתמש בשם מלא רק כאשר יש צורך והשמט חלקים מיותרים. דוגמא:
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
הערות
עבור הערה בשורה אחת, //
, /* */
ו- /** */
בסדר.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
- השתמש
/* */
להערות. בעוד HIDL תומך//
עבור הערות, הם לא מעודדים כי הם לא מופיעים בפלט שנוצר. - השתמש
/** */
לתיעוד שנוצר. ניתן להחיל אותם רק על הצהרות ערך מסוג, שיטה, שדה ו-enum. דוגמה:/** Replied status */ enum TeleportStatus { /** Object entirely teleported. */ OK = 0, /** Methods return this if teleportation is not completed. */ ERROR_TELEPORT = 1, /** * Teleportation could not be completed due to an object * obstructing the path. */ ERROR_OBJECT = 2, ... }
- התחל הערות מרובות שורות עם
/**
בשורה נפרדת. השתמש ב-*
בתחילת כל שורה. סיים את ההערה ב-*/
בשורה נפרדת, תוך יישור הכוכביות. דוגמה:/** * My multi-line * comment */
- הודעת הרישוי ויומני השינוי צריכים להתחיל שורה חדשה עם
/*
(כוכבית בודדת), להשתמש ב-*
בתחילת כל שורה, ולמקם את*/
בשורה האחרונה לבד (כוכביות צריכות להתיישר). דוגמה:/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
קובץ הערות
התחל כל קובץ בהודעת הרישוי המתאימה. עבור HALs ליבה, זה צריך להיות רישיון AOSP Apache ב- development/docs/copyright-templates/c.txt
. זכור לעדכן את השנה ולהשתמש /* */
בסגנון הערות מרובות שורות כפי שהוסבר לעיל.
באפשרותך להציב שורה ריקה לאחר הודעת הרישיון, ולאחריה יומן שינויים/מידע על גירסה. השתמש /* */
בסגנון הערות מרובות שורות כפי שהוסבר למעלה, מקם את השורה הריקה אחרי יומן השינויים, ולאחר מכן בצע את הצהרת החבילה.
הערות TODO
TODOs צריכות לכלול את המחרוזת TODO
בכל רישיות ואחריה נקודתיים. דוגמא:
// TODO: remove this code before foo is checked in.
הערות TODO מותרות רק במהלך הפיתוח; אסור להם להתקיים בממשקים שפורסמו.
הערות ממשק/פונקציה (מחרוזות)
השתמש ב- /** */
עבור מחרוזות docstrings מרובות שורות ושורות בודדות. אל תשתמש ב- //
עבור docstrings.
מחרוזות Docstrings עבור ממשקים צריכות לתאר מנגנונים כלליים של הממשק, רציונל עיצוב, מטרה וכו'. Docstrings עבור פונקציות צריכות להיות ספציפיות לפונקציה (תיעוד ברמת החבילה נכנס לקובץ README בספריית החבילות).
/** * IFooController is the controller for foos. */ interface IFooController { /** * Opens the controller. * * @return status HAL_FOO_OK if successful. */ open() generates (FooStatus status); /** Close the controller. */ close(); };
עליך להוסיף @param
s ו- @return
s עבור כל פרמטר/ערך החזרה:
- יש להוסיף
@param
לכל פרמטר. אחריו צריך להיות שם הפרמטר ואז מחרוזת ה-docstring. - יש להוסיף
@return
עבור כל ערך החזרה. אחריו צריך להיות שם ערך ההחזרה ואז מחרוזת ה-docstring.
דוגמא:
/** * Explain what foo does. * * @param arg1 explain what arg1 is * @param arg2 explain what arg2 is * @return ret1 explain what ret1 is * @return ret2 explain what ret2 is */ foo(T arg1, T arg2) generates (S ret1, S ret2);
עיצוב
כללי עיצוב כלליים כוללים:
- אורך קו . כל שורת טקסט צריכה להיות באורך של 100 עמודות לכל היותר.
- רווחים לבנים . אין רווחים נגררים על הקווים; אסור לשורות ריקות להכיל רווחים לבנים.
- רווחים לעומת כרטיסיות . השתמש רק ברווחים.
- גודל כניסה . השתמש ב -4 רווחים עבור בלוקים ו -8 רווחים עבור גלישת שורות
- חיזוק . פרט לערכי הערות , סוגריים פתוחים עוברים על אותה שורה כמו הקוד הקודם אך סוגריים סגורים והנקודה-פסיק הבא תופסת את כל השורה. דוגמה:
interface INfc { close(); };
הצהרת חבילה
הצהרת החבילה צריכה להיות בחלק העליון של הקובץ לאחר הודעת הרישיון, צריכה לתפוס את כל השורה, ואין להזין אותה. חבילות מוצהרות באמצעות הפורמט הבא (לעיצוב שמות, ראה שמות חבילות ):
package PACKAGE-NAME;
דוגמא:
package android.hardware.nfc@1.0;
הצהרות פונקציה
ערכי שם פונקציה, פרמטרים, generates
וערכי החזר צריכים להיות באותה שורה אם הם מתאימים. דוגמא:
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
אם הם לא מתאימים לאותה שורה, נסה לשים פרמטרים וערכי החזרה באותה רמת כניסות ויצירת generate
כדי לעזור לקורא לראות במהירות את הפרמטרים וערכי ההחזרה. דוגמא:
interface IFoo { suchALongMethodThatCannotFitInOneLine(int32_t theFirstVeryLongParameter, int32_t anotherVeryLongParameter); anEvenLongerMethodThatCannotFitInOneLine(int32_t theFirstLongParameter, int32_t anotherVeryLongParameter) generates (int32_t theFirstReturnValue, int32_t anotherReturnValue); superSuperSuperSuperSuperSuperSuperLongMethodThatYouWillHateToType( int32_t theFirstVeryLongParameter, // 8 spaces int32_t anotherVeryLongParameter ) generates ( int32_t theFirstReturnValue, int32_t anotherReturnValue ); /* method name is even shorter than 'generates' */ foobar(AReallyReallyLongType aReallyReallyLongParameter, AReallyReallyLongType anotherReallyReallyLongParameter) generates (ASuperLongType aSuperLongReturnValue, // 4 spaces ASuperLongType anotherSuperLongReturnValue); }
פרטים נוספים:
- סוגריים פתוחים תמיד נמצאים באותה שורה של שם הפונקציה.
- אין רווחים בין שם הפונקציה לסוגריים הפתוחים.
- אין רווחים בין הסוגריים והפרמטרים למעט כאשר יש הזנות קווים ביניהם.
- אם
generates
נמצא באותו קו כמו סוגרי הסגירה הקודם, השתמש ברווח קודם. אםgenerates
נמצא באותו קו כמו הסוגרי הפתוח הבא, בצע רווח. - יישר את כל הפרמטרים והחזר ערכי (אם אפשר).
- הזחה ברירת מחדל היא 4 רווחים.
- פרמטרים עטופים מיושרים לפרמטרים הראשונים בשורה הקודמת, אחרת יש להם הזחה של 8 רווחים.
הערות
השתמש בפורמט הבא להערות:
@annotate(keyword = value, keyword = {value, value, value})
מיין את ההערות בסדר אלפביתי, והשתמש ברווחים סביב סימני שוויון. דוגמא:
@callflow(key = value) @entry @exit
ודא שהערה תופסת את כל השורה. דוגמאות:
/* Good */ @entry @exit /* Bad */ @entry @exit
אם ההערות אינן יכולות להתאים לאותה שורה, הכנס עם 8 רווחים. דוגמא:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
אם מערך הערכים כולו אינו יכול להתאים באותה שורה, שים מעברי שורה אחרי סוגרים פתוחים {
ואחרי כל פסיק בתוך המערך. הצב סוגריים סוגרים מיד אחרי הערך האחרון. אין לשים את הפלטה אם יש רק ערך אחד.
אם כל מערך הערכים יכול להתאים באותה שורה, אל תשתמש ברווחים אחרי סוגרים פתוחים ולפני סגירת סוגרים והשתמש ברווח אחד אחרי כל פסיק. דוגמאות:
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
אסור שיהיו שורות ריקות בין ההערות להצהרת הפונקציה. דוגמאות:
/* Good */ @entry foo(); /* Bad */ @entry foo();
הצהרות אנום
השתמש בכללים הבאים עבור הצהרות מנה:
- אם הצהרות enum משותפים עם חבילה אחרת, שים את ההצהרות ב-
types.hal
במקום להטמיע בתוך ממשק. - השתמש ברווח לפני ואחרי המעי הגס, וברווח אחרי הסוג הבסיסי לפני הפלטה הפתוחה.
- לערך ה-enum האחרון עשוי להיות פסיק נוסף או לא.
הצהרות מבנה
השתמש בכללים הבאים להצהרות מבנה:
- אם הצהרות struct משותפים עם חבילה אחרת, שים את ההצהרות ב-
types.hal
במקום להטמיע בתוך ממשק. - השתמש ברווח אחרי שם סוג המבנה לפני הסוגר הפתוח.
- יישר שמות שדות (אופציונלי). דוגמה:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
הצהרות מערך
אין לשים רווחים בין הדברים הבאים:
- סוג אלמנט וסוגר מרובע פתוח.
- סוגר מרובע פתוח וגודל מערך.
- גודל מערך וסגור סוגר מרובע.
- סגור את הסוגר המרובע ואת הסוגר המרובע הפתוחה הבא, אם קיים יותר מממד אחד.
דוגמאות:
/* Good */ int32_t[5] array; /* Good */ int32_t[5][6] multiDimArray; /* Bad */ int32_t [ 5 ] [ 6 ] array;
וקטורים
אין לשים רווחים בין הדברים הבאים:
-
vec
זווית פתוחה. - סוגר זווית פתוח וסוג אלמנט ( חריג: סוג האלמנט הוא גם
vec
). - סוג אלמנט וסוגר זווית קרובה ( חריג: סוג האלמנט הוא גם
vec
) .
דוגמאות:
/* Good */ vec<int32_t> array; /* Good */ vec<vec<int32_t>> array; /* Good */ vec< vec<int32_t> > array; /* Bad */ vec < int32_t > array; /* Bad */ vec < vec < int32_t > > array;