Kiểu mã HIDL giống với mã C++ trong khung Android, với 4 dấu cách thụt lề và tên tệp có cả chữ hoa và chữ thường. Khai báo gói, nhập và chuỗi tài liệu tương tự như các mã trong Java với một số sửa đổi nhỏ.
Các ví dụ sau cho IFoo.hal
và types.hal
minh hoạ các kiểu mã HIDL và cung cấp các đường liên kết nhanh đến thông tin chi tiết về từng kiểu
(IFooClientCallback.hal
, IBar.hal
và
IBaz.hal
đã bị bỏ qua).
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; }; |
Quy ước đặt tên
Tên hàm, tên biến và tên tệp phải mang tính mô tả; tránh
viết tắt quá mức. Coi từ viết tắt là từ ngữ (ví dụ: sử dụng INfc
/ INFC
).
Cấu trúc thư mục và cách đặt tên tệp
Cấu trúc thư mục sẽ xuất hiện như sau:
ROOT-DIRECTORY
MODULE
SUBMODULE
(không bắt buộc, có thể có nhiều hơn một cấp độ)VERSION
Android.mk
IINTERFACE_1.hal
IINTERFACE_2.hal
…
IINTERFACE_N.hal
types.hal
(không bắt buộc)
Trong trường hợp:
ROOT-DIRECTORY
là:hardware/interfaces
cho các gói HIDL chính.vendor/VENDOR/interfaces
cho các gói của nhà cung cấp, trong đóVENDOR
đề cập đến một nhà cung cấp SoC hoặc một OEM/ODM.
MODULE
phải là một từ viết thường để mô tả hệ thống con (ví dụ:nfc
). Nếu cần nhiều từ, hãy sử dụngSUBMODULE
được lồng. Có thể có nhiều cấp độ lồng nhau.VERSION
phải là cùng một phiên bản (major.minor) như mô tả trong Phiên bản.IINTERFACE_X
phải là tên giao diện vớiUpperCamelCase
/PascalCase
(ví dụ:INfc
) như được mô tả trong Tên giao diện.
Ví dụ:
hardware/interfaces
nfc
1.0
Android.mk
INfc.hal
INfcClientCallback.hal
types.hal
Lưu ý: Tất cả các tệp đều phải có tệp không thể thực thi quyền (trong Git).
Tên gói
Tên gói phải sử dụng tên đủ điều kiện sau đây
(FQN) (còn gọi là PACKAGE-NAME
):
PACKAGE.MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
Trong trường hợp:
PACKAGE
là gói liên kết vớiROOT-DIRECTORY
Cụ thể,PACKAGE
là:android.hardware
cho các gói HIDL chính (ánh xạ tớihardware/interfaces
).vendor.VENDOR.hardware
cho các gói của nhà cung cấp, trong đóVENDOR
đề cập đến một nhà cung cấp SoC hoặc OEM/ODM (liên kết đếnvendor/VENDOR/interfaces
).
MODULE[.SUBMODULE[.SUBMODULE[…]]]@VERSION
có tên thư mục giống hệt nhau trong cấu trúc được mô tả trong Cấu trúc thư mục.- Tên gói phải viết thường. Nếu chúng dài hơn một từ,
các từ này nên được sử dụng làm mô-đun con hoặc được viết trong
snake_case
. - Không được dùng dấu cách.
FQN luôn được dùng trong khai báo gói.
Phiên bản
Phiên bản phải có định dạng sau:
MAJOR.MINOR
Cả phiên bản MAJOR và MINOR đều phải là một phiên bản duy nhất số nguyên. HIDL sử dụng ngữ nghĩa tạo phiên bản.
Nhập
Dữ liệu nhập có một trong ba định dạng sau:
- Nhập toàn bộ gói:
import PACKAGE-NAME;
- Nhập một phần:
import PACKAGE-NAME::UDT;
(hoặc nếu giá trị nhập type nằm trong cùng một gói,import UDT;
- Chỉ nhập loại:
import PACKAGE-NAME::types;
PACKAGE-NAME
tuân theo định dạng trong
Tên gói. của gói hiện tại
types.hal
(nếu có) sẽ được nhập tự động (không nhập)
một cách rõ ràng).
Tên đủ điều kiện (FQN)
Chỉ sử dụng tên đủ điều kiện cho việc nhập loại do người dùng xác định chỉ khi cần thiết.
Bỏ qua PACKAGE-NAME
nếu loại nhập giống nhau
. FQN không được chứa dấu cách. Ví dụ về tên đủ điều kiện:
android.hardware.nfc@1.0::INfcClientCallback
Trong một tệp khác trong android.hardware.nfc@1.0
, hãy tham khảo
bên trên giao diện dưới dạng INfcClientCallback
. Nếu không, chỉ sử dụng
tên đủ điều kiện.
Nhóm và sắp xếp thứ tự nhập
Sử dụng một dòng trống sau khi khai báo gói (trước khi nhập). Mỗi lần nhập phải chiếm một dòng duy nhất và không được thụt lề. Nhóm các lệnh nhập trong thứ tự sau:
- Các gói
android.hardware
khác (sử dụng tên đủ điều kiện). - Các gói
vendor.VENDOR
khác (sử dụng các gói đủ điều kiện tên).- Mỗi nhà cung cấp phải là một nhóm.
- Đặt hàng nhà cung cấp theo thứ tự bảng chữ cái.
- Nhập từ các giao diện khác trong cùng một gói (sử dụng tên đơn giản).
Sử dụng một dòng trống giữa các nhóm. Bên trong mỗi nhóm, hãy sắp xếp dữ liệu nhập theo thứ tự bảng chữ cái. Ví dụ:
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;
Tên giao diện
Tên giao diện phải bắt đầu bằng I
, theo sau là
UpperCamelCase
/PascalCase
tên. Giao diện có tên
Bạn phải xác định IFoo
trong tệp IFoo.hal
. Tệp này
chỉ có thể chứa định nghĩa cho giao diện IFoo
(giao diện
INAME
phải nằm trong INAME.hal
).
Hàm
Đối với tên hàm, đối số và tên biến trả về, hãy sử dụng
lowerCamelCase
. Ví dụ:
open(INfcClientCallback clientCallback) generates (int32_t retVal); oneway pingAlive(IFooCallback cb);
Tên trường kết hợp và cấu trúc
Đối với tên trường cấu trúc hoặc liên kết, hãy sử dụng lowerCamelCase
. Ví dụ:
struct FooReply { vec<uint8_t> replyData; }
Nhập tên
Tên loại đề cập đến định nghĩa cấu trúc hoặc liên kết, định nghĩa loại enum và
typedef
giây. Đối với các tên này, hãy sử dụng
UpperCamelCase
/PascalCase
. Ví dụ:
enum NfcStatus : int32_t { /*...*/ }; struct NfcData { /*...*/ };
Giá trị enum
Giá trị enum phải là UPPER_CASE_WITH_UNDERSCORES
. Khi chuyển
giá trị enum dưới dạng đối số hàm và trả về các giá trị đó dưới dạng hàm trả về, hãy sử dụng
loại enum thực tế (không phải loại số nguyên cơ bản). Ví dụ:
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 };
Lưu ý: Loại cơ bản của một loại enum là được khai báo rõ ràng sau dấu hai chấm. Vì không phụ thuộc vào trình biên dịch, nên việc sử dụng loại enum thực tế sẽ rõ ràng hơn.
Đối với những tên đủ điều kiện cho các giá trị enum, hãy sử dụng dấu hai chấm giữa tên loại enum và tên giá trị enum:
PACKAGE-NAME::UDT[.UDT[.UDT[…]]:ENUM_VALUE_NAME
Tên không được có dấu cách trong một tên đủ điều kiện. Hãy sử dụng thông tin chi tiết đủ điều kiện khi cần và bỏ qua các phần không cần thiết. Ví dụ:
android.hardware.foo@1.0::IFoo.IFooInternal.FooEnum:ENUM_OK
Bình luận
Đối với nhận xét một dòng, //
, /* */
và /** */
đều ổn.
// This is a single line comment /* This is also single line comment */ /** This is documentation comment */
-
Sử dụng
/* */
để nhận xét. Mặc dù HIDL hỗ trợ//
cho nhận xét, chúng không được khuyến khích vì chúng không xuất hiện trong đầu ra được tạo. - Sử dụng
/** */
cho tài liệu đã tạo. Bạn có thể áp dụng các đề xuất này chỉ để khai báo giá trị loại, phương thức, trường và giá trị enum. Ví dụ:/** 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, ... }
- Bắt đầu nhận xét ở nhiều dòng với
/**
trên một dòng riêng. Sử dụng*
ở đầu mỗi dòng. Kết thúc ghi chú bằng*/
trên một dòng riêng, căn chỉnh các dấu hoa thị. Ví dụ:/** * My multi-line * comment */
- Nhật ký thay đổi và thông báo cấp phép sẽ bắt đầu một dòng mới với
/*
(một dấu hoa thị), sử dụng*
ở đầu mỗi dòng và đặt*/
trên dòng cuối cùng (các dấu hoa thị phải căn chỉnh). Ví dụ:/* * Copyright (C) 2017 The Android Open Source Project * ... */ /* * Changelog: * ... */
Nhận xét về tệp
Khởi động mỗi tệp bằng thông báo cấp phép thích hợp. Đối với HAL (Lớp trừu tượng phần cứng) cốt lõi,
phải là giấy phép AOSP Apache trong
development/docs/copyright-templates/c.txt
.
Hãy nhớ cập nhật năm và sử dụng nhận xét nhiều dòng theo kiểu /* */
như đã giải thích ở trên.
Bạn có thể tuỳ ý đặt một dòng trống sau thông báo giấy phép, sau đó
thông tin nhật ký thay đổi/thông tin tạo phiên bản. Sử dụng kiểu /* */
ghi chú nhiều dòng như đã giải thích ở trên, hãy đặt dòng trống sau dòng
nhật ký thay đổi, sau đó làm theo nội dung khai báo gói.
Nhận xét về TODO
VIỆC CẦN LÀM phải bao gồm chuỗi TODO
bằng tất cả chữ viết hoa theo sau là
dấu hai chấm. Ví dụ:
// TODO: remove this code before foo is checked in.
Chỉ cho phép nhận xét về TODO trong quá trình phát triển; họ phải không tồn tại trong giao diện đã xuất bản.
Nhận xét về giao diện và chức năng (chuỗi tài liệu)
Sử dụng /** */
cho các chuỗi tài liệu nhiều dòng và một dòng. Không sử dụng
//
cho chuỗi tài liệu.
Chuỗi tài liệu cho giao diện phải mô tả cơ chế chung của giao diện, lý do thiết kế, mục đích, v.v. Tài liệu cho các hàm nên là cụ thể cho hàm (tài liệu cấp gói nằm trong tệp README trong thư mục gói).
/** * 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(); };
Bạn phải thêm @param
và @return
cho mỗi loại
tham số/giá trị trả về:
- Bạn phải thêm
@param
cho mỗi tham số. Phải theo sau là tên của tham số rồi đến chuỗi tài liệu. - Bạn phải thêm
@return
cho mỗi giá trị trả về. Nó phải theo sau là tên của giá trị trả về, rồi đến chuỗi tài liệu.
Ví dụ:
/** * 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);
Quy tắc định dạng
Quy tắc định dạng chung bao gồm:
- Độ dài dòng. Mỗi dòng văn bản chỉ được dài tối đa Dài 100 cột.
- Khoảng trắng. Không có khoảng trắng ở cuối các dòng; dòng trống không được chứa khoảng trắng.
- Phím cách và thẻ. Chỉ sử dụng dấu cách.
- Tăng kích thước thụt lề. Dùng 4 dấu cách cho các khối và 8 dấu cách để xuống dòng
- Mang. Ngoại trừ chú thích
, thì dấu ngoặc nhọn open nằm trên cùng một dòng với dấu ngoặc nhọn đứng trước
nhưng dấu ngoặc nhọn close và dấu chấm phẩy sau đây chiếm
toàn bộ dòng. Ví dụ:
interface INfc { close(); };
Khai báo gói
Phần khai báo gói phải ở đầu tệp sau khi cấp phép chú ý, nên chiếm toàn bộ dòng và không nên thụt lề. Các gói là được khai báo bằng định dạng sau (để định dạng tên, hãy xem Tên gói):
package PACKAGE-NAME;
Ví dụ:
package android.hardware.nfc@1.0;
Khai báo hàm
Tên hàm, tham số, generates
và giá trị trả về phải
trên cùng một dòng nếu chúng phù hợp. Ví dụ:
interface IFoo { /** ... */ easyMethod(int32_t data) generates (int32_t result); };
Nếu chúng không vừa trên cùng một dòng, hãy thử đặt các tham số và trả về
các giá trị ở cùng mức thụt lề và phân biệt generate
để giúp
người đọc sẽ nhanh chóng thấy các thông số và giá trị trả về. Ví dụ:
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); }
Thông tin chi tiết bổ sung:
- Dấu ngoặc đơn mở luôn nằm trên cùng một dòng với tên hàm.
- Không có khoảng trắng giữa tên hàm và dấu ngoặc đơn mở.
- Không có khoảng trắng giữa dấu ngoặc đơn và các tham số, trừ trường hợp có là những nguồn cấp dữ liệu dòng giữa chúng.
- Nếu
generates
nằm trên cùng một dòng với lệnh đóng trước đó dấu ngoặc đơn, hãy sử dụng dấu cách phía trước. Nếugenerates
ở trên cùng một làm dấu ngoặc đơn mở tiếp theo, theo sau là một dấu cách. - Căn chỉnh tất cả tham số và trả về giá trị (nếu có thể).
- Mức thụt lề mặc định là 4 dấu cách.
- Tham số được gói được căn chỉnh với các tham số đầu tiên trên dòng trước đó, nếu không, chúng sẽ có thụt lề 8 dấu cách.
Chú thích
Sử dụng định dạng sau cho chú thích:
@annotate(keyword = value, keyword = {value, value, value})
Sắp xếp chú thích theo thứ tự bảng chữ cái và sử dụng dấu cách xung quanh dấu bằng. Ví dụ:
@callflow(key = value) @entry @exit
Đảm bảo chú giải chiếm toàn bộ dòng. Ví dụ:
/* Good */ @entry @exit /* Bad */ @entry @exit
Nếu chú thích không thể vừa trên cùng một dòng, hãy thụt lề bằng 8 dấu cách. Ví dụ:
@annotate( keyword = value, keyword = { value, value }, keyword = value)
Nếu toàn bộ mảng giá trị không thể nằm vừa trong cùng một dòng, hãy ngắt dòng sau
dấu ngoặc nhọn mở {
và sau mỗi dấu phẩy bên trong mảng. Đóng địa điểm
dấu ngoặc đơn ngay sau giá trị cuối cùng. Không đặt dấu ngoặc nhọn nếu có
một giá trị duy nhất.
Nếu toàn bộ mảng giá trị có thể nằm vừa trong cùng một dòng, thì đừng sử dụng dấu cách sau dấu ngoặc nhọn mở và trước khi đóng dấu ngoặc nhọn, đồng thời sử dụng một dấu cách sau mỗi dấu phẩy. Ví dụ:
/* Good */ @callflow(key = {"val", "val"}) /* Bad */ @callflow(key = { "val","val" })
KHÔNG được có dòng trống giữa chú giải và hàm khai báo. Ví dụ:
/* Good */ @entry foo(); /* Bad */ @entry foo();
Khai báo enum
Sử dụng các quy tắc sau để khai báo enum:
- Nếu nội dung khai báo enum được chia sẻ với một gói khác, hãy đặt nội dung khai báo
trong
types.hal
thay vì nhúng bên trong một giao diện. - Sử dụng dấu cách trước và sau dấu hai chấm và dấu cách sau kiểu cơ bản trước dấu mở ngoặc nhọn.
- Giá trị enum cuối cùng có thể không có thêm dấu phẩy.
Khai báo cấu trúc
Sử dụng các quy tắc sau để khai báo cấu trúc:
- Nếu nội dung khai báo cấu trúc được chia sẻ với một gói khác, hãy đặt nội dung khai báo
trong
types.hal
thay vì nhúng bên trong một giao diện. - Sử dụng dấu cách sau tên loại cấu trúc trước dấu ngoặc nhọn mở.
- Căn chỉnh tên trường (không bắt buộc). Ví dụ:
struct MyStruct { vec<uint8_t> data; int32_t someInt; }
Khai báo mảng
Đừng để dấu cách giữa các dòng sau:
- Loại phần tử và dấu ngoặc vuông mở.
- Mở dấu ngoặc vuông và kích thước mảng.
- Kích thước mảng và đóng dấu ngoặc vuông.
- Đóng dấu ngoặc vuông và dấu ngoặc vuông mở tiếp theo nếu có nhiều dấu ngoặc vuông .
Ví dụ:
/* Good */ int32_t[5] array; /* Good */ int32_t[5][6] multiDimArray; /* Bad */ int32_t [ 5 ] [ 6 ] array;
Vectơ
Đừng để dấu cách giữa các dòng sau:
vec
và dấu ngoặc góc mở.- Dấu ngoặc góc mở và loại phần tử (Ngoại lệ: loại phần tử cũng là
vec
). - Loại phần tử và dấu ngoặc góc đóng (Ngoại lệ: loại phần tử cũng là
vec
).
Ví dụ:
/* 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;