دليل نمط التعليمات البرمجية

يشبه نمط كود HIDL كود C++ في إطار عمل Android، مع مسافات بادئة ذات 4 مسافات وأسماء ملفات ذات أحرف مختلطة. تتشابه إعلانات الحزم والواردات والمستندات مع تلك الموجودة في 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 هي أسماء المجلدات نفسها تمامًا في البنية الموضحة في بنية الدليل .
  • يجب أن تكون أسماء الحزم صغيرة. إذا كان طولها أكثر من كلمة واحدة، فيجب إما استخدام الكلمات كوحدات فرعية أو كتابتها في 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);

أسماء حقول البنية/الاتحاد

بالنسبة لأسماء حقول البنية/الاتحاد، استخدم lowerCamelCase . مثال:

struct FooReply {
    vec<uint8_t> replyData;
}

اكتب الأسماء

تشير أسماء الأنواع إلى تعريفات البنية/الاتحاد وتعريفات نوع التعداد و typedef s. بالنسبة لهذه الأسماء، استخدم UpperCamelCase / PascalCase . أمثلة:

enum NfcStatus : int32_t {
    /*...*/
};
struct NfcData {
    /*...*/
};

قيم التعداد

يجب أن تكون قيم التعداد UPPER_CASE_WITH_UNDERSCORES . عند تمرير قيم التعداد كوسيطات دالة وإعادتها كإرجاعات دالة، استخدم نوع التعداد الفعلي (وليس النوع الصحيح الأساسي). مثال:

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
};

ملاحظة: يتم الإعلان عن النوع الأساسي لنوع التعداد بشكل صريح بعد النقطتين. نظرًا لأنه لا يعتمد على المترجم، فإن استخدام نوع التعداد الفعلي يكون أكثر وضوحًا.

بالنسبة للأسماء المؤهلة بالكامل لقيم التعداد، يتم استخدام نقطتين بين اسم نوع التعداد واسم قيمة التعداد:

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 // للتعليقات، إلا أنه لا ينصح بها لأنها لا تظهر في المخرجات التي تم إنشاؤها.
  • استخدم /** */ للوثائق التي تم إنشاؤها. يمكن تطبيق ذلك فقط على إعلانات قيمة النوع والأسلوب والحقل والتعداد. مثال:
    /** 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 بأحرف كبيرة متبوعة بنقطتين. مثال:

// TODO: remove this code before foo is checked in.

يُسمح بتعليقات TODO فقط أثناء التطوير؛ ويجب ألا تكون موجودة في الواجهات المنشورة.

تعليقات الواجهة/الوظيفة (سلاسل المستندات)

استخدم /** */ للمستندات ذات الأسطر المتعددة والأحادية. لا تستخدم // للمستندات.

يجب أن تصف سلاسل المستندات الخاصة بالواجهات الآليات العامة للواجهة، وأساس التصميم، والغرض، وما إلى ذلك. يجب أن تكون سلاسل المستندات الخاصة بالوظائف خاصة بالوظيفة (يتم وضع الوثائق على مستوى الحزمة في ملف 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 لكل قيمة إرجاع. يجب أن يتبعه اسم القيمة المرجعة ثم سلسلة المستندات.

مثال:

/**
 * 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();

إعلانات التعداد

استخدم القواعد التالية لإعلانات التعداد:

  • إذا تمت مشاركة تعريفات التعداد مع حزمة أخرى، فضع التعريفات في types.hal بدلاً من تضمينها داخل الواجهة.
  • استخدم مسافة قبل وبعد النقطتين، ومسافة بعد النوع الأساسي قبل القوس المفتوح.
  • قد تحتوي قيمة التعداد الأخيرة على فاصلة إضافية أو لا تحتوي عليها.

تصريحات الهيكل

استخدم القواعد التالية لإعلانات البنية:

  • إذا تمت مشاركة إعلانات البنية مع حزمة أخرى، فضع الإعلانات في 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;