يشبه نمط كود 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
. خلاف ذلك ، استخدم فقط الاسم المؤهل بالكامل.
تجميع وترتيب الواردات
استخدم سطرًا فارغًا بعد إعلان الحزمة (قبل الاستيراد). يجب أن تشغل كل عملية استيراد سطرًا واحدًا ولا يجب وضع مسافة بادئة لها. استيراد المجموعة بالترتيب التالي:
- حزم
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);
أسماء الحقول الهيكلية / الاتحاد
بالنسبة لأسماء الحقول الهيكلية / الموحدة ، استخدم 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
. تذكر تحديث السنة واستخدام /* */
style التعليقات متعددة الأسطر كما هو موضح أعلاه.
يمكنك اختياريًا وضع سطر فارغ بعد إشعار الترخيص ، متبوعًا بمعلومات سجل التغيير / الإصدار. استخدم /* */
style multi-line comments كما هو موضح أعلاه ، ضع السطر الفارغ بعد سجل التغيير ، ثم اتبع إعلان الحزمة.
تعليقات TODO
يجب أن تتضمن TODO سلسلة TODO
في جميع الأحرف الاستهلالية متبوعة بنقطتين. مثال:
// TODO: remove this code before foo is checked in.
لا يُسمح بتعليقات TODO إلا أثناء التطوير ؛ يجب ألا تكون موجودة في الواجهات المنشورة.
تعليقات الواجهة / الوظيفة (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();
تعداد الإعلانات
استخدم القواعد التالية لإقرارات التعداد:
- إذا تمت مشاركة تعريفات التعداد مع حزمة أخرى ، فضع الإعلانات في
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;