ประเภทข้อมูล

การประกาศข้อมูล HIDL จะสร้างโครงสร้างข้อมูลเลย์เอาต์มาตรฐาน C++ เหล่านี้ สามารถวางโครงสร้างในที่ที่ดูเป็นธรรมชาติ (ในกอง ไฟล์ หรือ ขอบเขตรวมทั้งหมด หรืออยู่ในฮีป) ที่สามารถเขียนในรูปแบบเดียวกัน ลูกค้า การเรียกใช้โค้ด HIDL การส่งรหัสพร็อกซีในการอ้างอิง Const และประเภทพื้นฐาน ขณะที่รหัสสตับและรหัสพร็อกซีจะซ่อนรายละเอียดการเรียงอันดับ

หมายเหตุ: โค้ดที่นักพัฒนาซอฟต์แวร์เขียนขึ้นจะไม่ช่วยแก้ปัญหานี้ ที่จำเป็นในการเรียงลำดับหรือดีซีเรียลไลซ์โครงสร้างข้อมูลอย่างชัดเจน

ตารางด้านล่างจะแมปค่าพื้นฐานของ HIDL กับประเภทข้อมูล C++

ประเภท HIDL ประเภทของ C++ ส่วนหัว/คลัง
enum enum class
uint8_t..uint64_t uint8_t..uint64_t <stdint.h>
int8_t..int64_t int8_t..int64_t <stdint.h>
float float
double double
vec<T> hidl_vec<T> libhidlbase
T[S1][S2]...[SN] T[S1][S2]...[SN]
string hidl_string libhidlbase
handle hidl_handle libhidlbase
safe_union (custom) struct
struct struct
union union
fmq_sync MQDescriptorSync libhidlbase
fmq_unsync MQDescriptorUnsync libhidlbase

ส่วนด้านล่างจะอธิบายประเภทข้อมูลอย่างละเอียด

Enum

enum ใน HIDL กลายเป็น enum ใน C++ ดังตัวอย่างต่อไปนี้

enum Mode : uint8_t { WRITE = 1 << 0, READ = 1 << 1 };
enum SpecialMode : Mode { NONE = 0, COMPARE = 1 << 2 };

... กลายเป็น:

enum class Mode : uint8_t { WRITE = 1, READ = 2 };
enum class SpecialMode : uint8_t { WRITE = 1, READ = 2, NONE = 0, COMPARE = 4 };

เริ่มตั้งแต่ Android 10 เป็นต้นไป คุณสามารถทำซ้ำ enum ได้ มากกว่าการใช้ ::android::hardware::hidl_enum_range ช่วงนี้ รวมทุกโปรแกรมตามลำดับที่ปรากฏในซอร์สโค้ด HIDL โดยเริ่มจาก จากการแจกแจงระดับบนสุดลงไปยังรายการย่อยสุดท้าย ตัวอย่างเช่น โค้ดนี้ทำซ้ำ มากกว่า WRITE, READ, NONE และ COMPARE ตามลำดับนั้น ให้ SpecialMode ข้างต้น:

template <typename T>
using hidl_enum_range = ::android::hardware::hidl_enum_range<T>

for (SpecialMode mode : hidl_enum_range<SpecialMode>) {...}

hidl_enum_range ยังใช้เครื่องมือทำซ้ำแบบย้อนกลับและอาจ ใช้ในบริบท constexpr หากค่าปรากฏในการแจกแจง หลายครั้ง ค่าจะปรากฏในช่วงหลายครั้ง

บิตฟิลด์<T>

bitfield<T> (โดยที่ T เป็น enum ที่ผู้ใช้กำหนด) จะกลายเป็นประเภทพื้นฐานของ enum นั้นใน C++ ในตัวอย่างข้างต้น bitfield<Mode> จะกลายเป็น uint8_t

เวค<T>

เทมเพลตชั้นเรียน hidl_vec<T> เป็นส่วนหนึ่งของ libhidlbase และสามารถใช้เพื่อส่งเวกเตอร์ของ HIDL ประเภทใดก็ได้ด้วย ขนาดที่กำหนดเอง คอนเทนเนอร์ขนาดคงที่ที่เทียบเคียงกันได้คือ hidl_array. hidl_vec<T> ยังสามารถเป็น เริ่มต้นให้ชี้ไปยังบัฟเฟอร์ข้อมูลภายนอกประเภท T โดยใช้ ฟังก์ชัน hidl_vec::setToExternal()

นอกจากการปล่อย/แทรกโครงสร้างอย่างเหมาะสมในไฟล์ที่สร้างขึ้น ส่วนหัว C++ การใช้ vec<T> ช่วยสร้างความสะดวก ฟังก์ชันเพื่อแปลเป็น/จาก std::vector และ T เปล่า ตัวชี้ หากใช้ vec<T> เป็นพารามิเตอร์ ฟังก์ชัน มากเกินไป (มีการสร้างต้นแบบสองแบบ) เพื่อยอมรับและ ส่งทั้งโครงสร้าง HIDL และประเภท std::vector<T> สำหรับโครงสร้าง พารามิเตอร์

อาร์เรย์

อาร์เรย์คงที่ในการซ่อนจะแสดงด้วยคลาส hidl_array ใน libhidlbase hidl_array<T, S1, S2, …, SN> แสดงอาร์เรย์ขนาดคงที่ N มิติ T[S1][S2]…[SN].

สตริง

คลาส hidl_string (ส่วนหนึ่งของ libhidlbase) มี ใช้เพื่อส่งสตริงผ่านอินเทอร์เฟซ HIDL และมีการกำหนดไว้ใน /system/libhidl/base/include/hidl/HidlSupport.h พื้นที่เก็บข้อมูลแรก ตำแหน่งในชั้นเรียนจะเป็นตัวชี้ไปยังบัฟเฟอร์อักขระ

hidl_string รู้วิธีแปลงเป็นและแปลง std::string and char* (สตริงรูปแบบ C) โดยใช้ operator=, แคสต์โดยนัย และฟังก์ชัน .c_str() โครงสร้างสตริง HIDL มีตัวสร้างและกำหนดการคัดลอกที่เหมาะสม โอเปอเรเตอร์ต่อไปนี้

  • โหลดสตริง HIDL จากสตริง std::string หรือ C
  • สร้าง std::string ใหม่จากสตริง HIDL

นอกจากนี้ สตริง HIDL มีเครื่องมือสร้างการแปลงเพื่อให้สตริง C (char *) และสตริง C++ (std::string) ใช้ได้ใน ที่ใช้สตริง HIDL

โครงสร้าง

struct ใน HIDL มีเฉพาะประเภทข้อมูลที่มีขนาดคงที่ และไม่มี คำจำกัดความโครงสร้าง HIDL จะแมปกับเลย์เอาต์มาตรฐานโดยตรง struct ใน C++ โดยทำให้มั่นใจว่า struct มี และเค้าโครงหน่วยความจำที่สม่ำเสมอ โครงสร้างอาจรวมประเภท HIDL ซึ่งรวมถึง handle, string และ vec<T> ที่ ชี้ไปที่บัฟเฟอร์ที่มีความยาวตัวแปรแยกกัน

แฮนเดิล

คำเตือน: ที่อยู่ทุกประเภท (รวมถึงที่อยู่จริง ที่อยู่ของอุปกรณ์) ต้องไม่เป็นส่วนหนึ่งของแฮนเดิลเนทีฟ ผ่าน ข้อมูลระหว่างขั้นตอนเหล่านั้นเป็นอันตรายและเสี่ยงต่อการถูกโจมตี ต้องตรวจสอบค่าใดๆ ที่ส่งผ่านกระบวนการก่อนที่จะนำไปใช้ในการค้นหา เพิ่มหน่วยความจำที่จัดสรรไว้ภายในกระบวนการ มิเช่นนั้น แฮนเดิลที่ไม่ถูกต้องอาจทำให้แฮนเดิลไม่ถูกต้อง การเข้าถึงหน่วยความจําหรือการเสียหายของหน่วยความจํา

ประเภท handle จะแสดงด้วย hidl_handle ใน C++ ซึ่งเป็น Wrapper ง่ายๆ ที่ชี้ไปยัง const native_handle_t ออบเจ็กต์ (ซึ่งมีอยู่ใน Android สำหรับ เป็นเวลานาน)

typedef struct native_handle
{
    int version;        /* sizeof(native_handle_t) */
    int numFds;         /* number of file descriptors at &data[0] */
    int numInts;        /* number of ints at &data[numFds] */
    int data[0];        /* numFds + numInts ints */
} native_handle_t;

โดยค่าเริ่มต้น hidl_handle จะไม่เป็นเจ้าของ ของเคอร์เซอร์ native_handle_t ที่รวมอยู่ จัดเก็บตัวชี้ไปยัง native_handle_t เพื่อให้สามารถใช้ใน ทั้งกระบวนการ 32 และ 64 บิต

สถานการณ์ที่ hidl_handle เป็นเจ้าของไฟล์ที่แนบมา เช่น

  • หลังจากการเรียกเมธอด setTo(native_handle_t* handle, bool shouldOwn) โดยมีการตั้งค่าพารามิเตอร์ shouldOwn เป็น true
  • เมื่อสร้างออบเจ็กต์ hidl_handle โดยการสร้างการคัดลอก จากออบเจ็กต์ hidl_handle อีกรายการ
  • เมื่อคัดลอกออบเจ็กต์ hidl_handle มาจากออบเจ็กต์อื่น วัตถุ hidl_handle รายการ

hidl_handle ให้ Conversion ทั้งโดยนัยและโดยชัดแจ้ง ไปยัง/จากnative_handle_t* ออบเจ็กต์ การใช้งานหลักสำหรับ handle ประเภทใน HIDL คือการส่งข้อบ่งชี้ไฟล์ผ่าน HIDL อินเทอร์เฟซ ดังนั้น ตัวอธิบายไฟล์เดี่ยวจะแสดงด้วยองค์ประกอบ native_handle_t ที่ไม่มี int และมีรายการเดียว fd หากลูกค้าและเซิร์ฟเวอร์อยู่ในกระบวนการอื่น RPC จะดูแลข้อบ่งชี้ไฟล์โดยอัตโนมัติเพื่อให้แน่ใจว่า ทั้ง 2 กระบวนการจะทำงานในไฟล์เดียวกันได้

แม้ว่าตัวระบุไฟล์ที่ได้รับใน hidl_handle โดย ใช้ได้ในกระบวนการนั้น และไม่ได้คงอยู่เกินจากการรับ (ปิดเมื่อฟังก์ชันแสดงผล) กระบวนการที่ต้องการ จะยังคงเข้าถึงข้อบ่งชี้ไฟล์ได้อย่างต่อเนื่องdup() หรือคัดลอกออบเจ็กต์ hidl_handle ทั้งหมด

ความทรงจำ

แมปประเภท memory แบบ HIDL กับคลาส hidl_memory ใน libhidlbase ซึ่งแสดงถึงหน่วยความจำที่ใช้ร่วมกันที่ไม่ได้แมป นี่คือ ซึ่งเป็นออบเจ็กต์ที่ต้องส่งระหว่างกระบวนการเพื่อแชร์หน่วยความจำใน HIDL ถึง ใช้หน่วยความจำที่ใช้ร่วมกัน:

  1. รับอินสแตนซ์ของ IAllocator (ขณะนี้มีเฉพาะอินสแตนซ์ "Ashmem" ว่าง) และใช้เพื่อจัดสรรหน่วยความจำที่แชร์
  2. IAllocator::allocate() แสดงผล hidl_memory ที่สามารถส่งผ่าน HIDL RPC และแมปลงในกระบวนการโดยใช้ ฟังก์ชัน mapMemory ของ libhidlmemory
  3. mapMemory ส่งคืนการอ้างอิงไปยัง sp<IMemory> ออบเจ็กต์ที่ใช้เข้าถึงหน่วยความจำได้ (IMemory และ IAllocator กำหนดไว้ใน android.hidl.memory@1.0)

อินสแตนซ์ของ IAllocator ใช้เพื่อจัดสรรหน่วยความจำได้ ดังนี้

#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::hardware::hidl_memory;
....
  sp<IAllocator> ashmemAllocator = IAllocator::getService("ashmem");
  ashmemAllocator->allocate(2048, [&](bool success, const hidl_memory& mem) {
        if (!success) { /* error */ }
        // now you can use the hidl_memory object 'mem' or pass it around
  }));

การเปลี่ยนแปลงหน่วยความจำจริงจะต้องดำเนินการผ่าน IMemory ที่ด้านข้างของที่สร้าง mem หรือด้านข้างที่ จะได้รับผ่าน HIDL RPC

// Same includes as above

sp<IMemory> memory = mapMemory(mem);
void* data = memory->getPointer();
memory->update();
// update memory however you wish after calling update and before calling commit
data[0] = 42;
memory->commit();
// …
memory->update(); // the same memory can be updated multiple times
// …
memory->commit();

อินเทอร์เฟซ

ส่งอินเทอร์เฟซเป็นออบเจ็กต์ได้ ใช้คำว่าอินเทอร์เฟซได้ เป็นน้ำตาลสังเคราะห์สำหรับประเภท android.hidl.base@1.0::IBase นอกจากนี้ อินเทอร์เฟซปัจจุบันและอินเทอร์เฟซที่นำเข้าก็ได้รับการกำหนด ประเภทหนึ่ง

ตัวแปรที่มีอินเทอร์เฟซควรเป็นตัวชี้ที่มีประสิทธิภาพ ได้แก่ sp<IName>. ฟังก์ชัน HIDL ที่ใช้พารามิเตอร์ของอินเทอร์เฟซ แปลงตัวชี้ดิบเป็นตัวชี้ที่มีประสิทธิภาพ ซึ่งทำให้เกิดพฤติกรรมที่ไม่เป็นธรรมชาติ (เคอร์เซอร์อาจถูกลบโดยไม่คาดคิด) เก็บ HIDL เสมอเพื่อหลีกเลี่ยงปัญหา เป็น sp<>