তথ্যের ধরণ

HIDL ডেটা ঘোষণা C++ স্ট্যান্ডার্ড-লেআউট ডেটা স্ট্রাকচার তৈরি করে। এই স্ট্রাকচারগুলি যে কোনও জায়গায় স্থাপন করা যেতে পারে যা প্রাকৃতিক মনে হয় (স্ট্যাকের উপর, ফাইলে বা গ্লোবাল স্কোপে, বা স্তূপে) এবং একই ফ্যাশনে রচনা করা যেতে পারে। ক্লায়েন্ট কোড এইচআইডিএল প্রক্সি কোডকে কনস্ট রেফারেন্স এবং আদিম প্রকারে পাসিং বলে, যখন স্টাব এবং প্রক্সি কোড সিরিয়ালাইজেশনের বিবরণ লুকিয়ে রাখে।

দ্রষ্টব্য: ডেটা স্ট্রাকচারকে স্পষ্টভাবে সিরিয়ালাইজ বা ডিসিরিয়ালাইজ করার জন্য ডেভেলপার-লিখিত কোডের প্রয়োজন নেই।

নীচের সারণীটি 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

HIDL-এর একটি enum C++ এ একটি enum হয়। উদাহরণ স্বরূপ:

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 থেকে শুরু করে, ::android::hardware::hidl_enum_range ব্যবহার করে একটি enum পুনরাবৃত্তি করা যেতে পারে। এই পরিসরটি 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) C++-এ সেই enum-এর অন্তর্নিহিত ধরণ হয়ে ওঠে। উপরের উদাহরণে, bitfield<Mode> হয়ে যায় uint8_t

vec<T>

hidl_vec<T> ক্লাস টেমপ্লেটটি libhidlbase এর অংশ এবং একটি ইচ্ছামত আকারের সাথে যেকোনো HIDL প্রকারের ভেক্টর পাস করতে ব্যবহার করা যেতে পারে। তুলনাযোগ্য নির্দিষ্ট আকারের ধারকটি হল hidl_arrayhidl_vec::setToExternal() ফাংশন ব্যবহার করে T টাইপের একটি বাহ্যিক ডেটা বাফার নির্দেশ করার জন্য একটি hidl_vec<T> ও শুরু করা যেতে পারে।

জেনারেট করা C++ হেডারে যথাযথভাবে স্ট্রাকট নির্গত/ঢোকানোর পাশাপাশি, vec<T> ব্যবহার std::vector এবং বেয়ার T পয়েন্টার থেকে অনুবাদ করার জন্য কিছু সুবিধাজনক ফাংশন তৈরি করে। যদি vec<T> একটি প্যারামিটার হিসাবে ব্যবহার করা হয়, তাহলে এটি ব্যবহার করা ফাংশনটি ওভারলোড হবে (দুটি প্রোটোটাইপ তৈরি করা হবে) সেই প্যারামিটারের জন্য HIDL স্ট্রাকট এবং একটি std::vector<T> টাইপ উভয়ই গ্রহণ এবং পাস করতে।

অ্যারে

hidl-এ ধ্রুবক অ্যারে libhidlbasehidl_array ক্লাস দ্বারা উপস্থাপিত হয়। একটি 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 স্ট্রিং স্ট্রাকটে উপযুক্ত কপি কনস্ট্রাক্টর এবং অ্যাসাইনমেন্ট অপারেটর রয়েছে:

  • একটি std::string বা একটি C স্ট্রিং থেকে HIDL স্ট্রিং লোড করুন।
  • একটি HIDL স্ট্রিং থেকে একটি নতুন std::string তৈরি করুন।

উপরন্তু, HIDL স্ট্রিংগুলিতে রূপান্তর কনস্ট্রাক্টর রয়েছে তাই C স্ট্রিং ( char * ) এবং C++ স্ট্রিংগুলি ( std::string ) একটি HIDL স্ট্রিং নেওয়া পদ্ধতিতে ব্যবহার করা যেতে পারে।

গঠন

HIDL-এর একটি struct শুধুমাত্র নির্দিষ্ট-আকারের ডেটা প্রকার থাকতে পারে এবং কোনও ফাংশন নেই। HIDL struct সংজ্ঞাগুলি সরাসরি C++-এ স্ট্যান্ডার্ড-লেআউট struct s-এ ম্যাপ করে, নিশ্চিত করে যে struct এর একটি সামঞ্জস্যপূর্ণ মেমরি বিন্যাস রয়েছে। একটি স্ট্রাকটে HIDL প্রকারগুলি অন্তর্ভুক্ত থাকতে পারে, handle , string , এবং vec<T> সহ, যা পৃথক পরিবর্তনশীল-দৈর্ঘ্য বাফারের দিকে নির্দেশ করে।

হাতল

সতর্কতা: যেকোনো ধরনের ঠিকানা (এমনকি শারীরিক ডিভাইসের ঠিকানা) কখনই নেটিভ হ্যান্ডেলের অংশ হতে হবে না। প্রক্রিয়াগুলির মধ্যে এই তথ্যটি পাস করা বিপজ্জনক এবং তাদের আক্রমণের জন্য সংবেদনশীল করে তোলে। একটি প্রক্রিয়ার মধ্যে বরাদ্দ করা মেমরি খোঁজার জন্য ব্যবহার করার আগে প্রক্রিয়াগুলির মধ্যে পাস করা যেকোনো মান অবশ্যই যাচাই করা উচিত। অন্যথায়, খারাপ হ্যান্ডেলগুলি খারাপ মেমরি অ্যাক্সেস বা মেমরি দুর্নীতির কারণ হতে পারে।

handle ধরনটি C++-এ hidl_handle কাঠামো দ্বারা উপস্থাপিত হয়, যা একটি const native_handle_t অবজেক্টের পয়েন্টারের চারপাশে একটি সাধারণ মোড়ক (এটি অনেক দিন ধরে অ্যান্ড্রয়েডে উপস্থিত রয়েছে)।

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 native_handle_t* অবজেক্টে/থেকে অন্তর্নিহিত এবং স্পষ্ট উভয় রূপান্তর প্রদান করে। HIDL-এ handle টাইপের প্রধান ব্যবহার হল HIDL ইন্টারফেসের উপর ফাইল বর্ণনাকারী পাস করা। তাই একটি একক ফাইল বর্ণনাকারীকে কোনো int s এবং একটি একক fd ছাড়াই একটি native_handle_t দ্বারা উপস্থাপন করা হয়। যদি ক্লায়েন্ট এবং সার্ভার একটি ভিন্ন প্রক্রিয়ায় থাকে, তাহলে RPC বাস্তবায়ন স্বয়ংক্রিয়ভাবে ফাইল বর্ণনাকারীর যত্ন নেবে যাতে উভয় প্রক্রিয়া একই ফাইলে কাজ করতে পারে।

যদিও একটি প্রক্রিয়ার দ্বারা hidl_handle এ প্রাপ্ত একটি ফাইল বর্ণনাকারী সেই প্রক্রিয়ায় বৈধ হবে, তবে এটি প্রাপ্তির ফাংশনের বাইরে টিকে থাকবে না (ফাংশনটি ফিরে আসার পরে এটি বন্ধ হয়ে যাবে)। একটি প্রক্রিয়া যা ফাইল বর্ণনাকারীতে অবিরাম অ্যাক্সেস বজায় রাখতে চায় তাকে অবশ্যই আবদ্ধ ফাইল বর্ণনাকারীকে dup() করতে হবে, অথবা সম্পূর্ণ hidl_handle অবজেক্টটি অনুলিপি করতে হবে।

স্মৃতি

HIDL memory টাইপ ম্যাপ libhidlbasehidl_memory ক্লাসে, যা আনম্যাপ করা শেয়ার করা মেমরির প্রতিনিধিত্ব করে। এটি এমন বস্তু যা HIDL-এ মেমরি ভাগ করার জন্য প্রক্রিয়াগুলির মধ্যে পাস করতে হবে। শেয়ার করা মেমরি ব্যবহার করতে:

  1. IAllocator এর একটি উদাহরণ প্রাপ্ত করুন (বর্তমানে শুধুমাত্র উদাহরণ "ashmem" উপলব্ধ) এবং শেয়ার করা মেমরি বরাদ্দ করতে এটি ব্যবহার করুন।
  2. IAllocator::allocate() একটি hidl_memory অবজেক্ট প্রদান করে যা HIDL RPC এর মাধ্যমে পাস করা যেতে পারে এবং libhidlmemory এর mapMemory ফাংশন ব্যবহার করে একটি প্রক্রিয়াতে ম্যাপ করা যেতে পারে।
  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 ইন্টারফেস একটি sp<> হিসাবে সংরক্ষণ করুন।