מדריך סגנון קוד

סגנון הקוד 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 . אחרת, השתמש רק בשם המלא.

קיבוץ והזמנת יבוא

השתמש בשורה ריקה לאחר הצהרת החבילה (לפני היבוא). כל ייבוא ​​צריך לתפוס שורה בודדת ואין להזין אותו. קבץ יבוא בסדר הבא:

  1. חבילות android.hardware אחרות (השתמש בשמות מתאימים לחלוטין).
  2. vendor. VENDOR חבילות vendor. VENDOR (השתמש בשמות מתאימים לחלוטין).
    • כל ספק צריך להיות קבוצה.
    • הזמינו ספקים בסדר אלפביתי.
  3. יבוא מממשקים אחרים באותה חבילה (השתמש בשמות פשוטים).

השתמש בשורה ריקה בין קבוצות. בתוך כל קבוצה, מיין ייבוא ​​לפי אלפביתי. דוגמא:

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

ערכי ה-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;