HIDL

HAL ইন্টারফেস ডেফিনিশন ল্যাঙ্গুয়েজ বা HIDL হল একটি ইন্টারফেস ডেসক্রিপশন ল্যাঙ্গুয়েজ (IDL) যা HAL এবং এর ব্যবহারকারীদের মধ্যে ইন্টারফেস নির্দিষ্ট করে। HIDL, ইন্টারফেস ও প্যাকেজে সংগ্রহ করা ধরন ও মেথড কল নির্দিষ্ট করার অনুমতি দেয়। আরও বিস্তৃতভাবে বলতে গেলে, HIDL হল কোডবেসের মধ্যে যোগাযোগ করার একটি সিস্টেম যা স্বাধীনভাবে কম্পাইল করা যেতে পারে।

HIDL-কে ইন্টার-প্রসেস কমিউনিকেশন (IPC)-এর জন্য ব্যবহার করার উদ্দেশ্যে তৈরি করা হয়েছে। HDL-এর মাধ্যমে তৈরি HAL-কে বাইন্ডারাইজড HAL বলা হয়, কারণ সেগুলি বাইন্ডার ইন্টার-প্রসেস কমিউনিকেশন (IPC) কল ব্যবহার করে অন্যান্য আর্কিটেকচার লেয়ারের সাথে যোগাযোগ করতে পারে। যে ক্লায়েন্ট Binderized HAL ব্যবহার করে, সেটি আলাদা প্রসেসে চলে। যেসব লাইব্রেরি কোনও প্রসেসের সাথে লিঙ্ক করতেই হবে, সেগুলির জন্য পাসথ্রু মোড উপলভ্য (Java-তে কাজ করে না)।

HIDL ডেটা স্ট্রাকচার এবং মেথড সিগনেচার নির্দিষ্ট করে, যা ইন্টারফেসে সাজানো থাকে (ক্লাসের মতো) এবং প্যাকেজে সংগ্রহ করা হয়। HIDL-এর সিনট্যাক্স C++ এবং Java প্রোগ্রামারদের কাছে পরিচিত মনে হতে পারে, তবে এতে আলাদা কীওয়ার্ড থাকে। HIDL-এও জাভা-স্টাইলের অ্যানোটেশন ব্যবহার করা হয়।

পরিভাষা

এই বিভাগে HIDL-সম্পর্কিত নিম্নলিখিত শব্দ ব্যবহার করা হয়েছে:

বাইন্ডারাইজড প্রসেসের মধ্যে রিমোট প্রসিডিওর কলের জন্য HIDL ব্যবহার করা হচ্ছে, বাইন্ডারের মতো মেকানিজমের মাধ্যমে প্রয়োগ করা হয়েছে। এছাড়াও পাসথ্রু দেখুন।
কলব্যাক, অ্যাসিঙ্ক্রোনাস HAL ব্যবহারকারীর দ্বারা পরিবেশিত ইন্টারফেস, HAL-এ পাস করা হয়েছে (HIDL পদ্ধতি ব্যবহার করে) এবং যেকোনও সময় ডেটা ফেরত দেওয়ার জন্য HAL-এর দ্বারা কল করা হয়েছে।
কলব্যাক, সিনক্রোনাস ক্লায়েন্টকে সার্ভারের HIDL মেথড ইমপ্লিমেন্টেশন থেকে ডেটা রিটার্ন করে। যেসব পদ্ধতিতে ভয়েড বা একটি প্রিমিটিভ ভ্যালু রিটার্ন করা হয় সেগুলির জন্য অব্যবহৃত।
ক্লায়েন্ট এমন প্রসেস যা নির্দিষ্ট ইন্টারফেসের মেথড কল করে। একটি HAL বা Android ফ্রেমওয়ার্ক প্রসেস একটি ইন্টারফেসের ক্লায়েন্ট এবং অন্যটির সার্ভার হতে পারে। এছাড়াও passthrough দেখুন।
বাড়ানো হয়েছে এমন একটি ইন্টারফেসকে নির্দেশ করে যা অন্য ইন্টারফেসে পদ্ধতি এবং/অথবা ধরন যোগ করে। একটি ইন্টারফেস শুধুমাত্র অন্য একটি ইন্টারফেসকে এক্সটেন্ড করতে পারে। একই প্যাকেজের নামে মাইনর ভার্সন ইনক্রিমেন্ট করার জন্য অথবা পুরনো প্যাকেজের উপর ভিত্তি করে নতুন প্যাকেজ (যেমন, ভেন্ডর এক্সটেনশন) তৈরি করার জন্য ব্যবহার করা যেতে পারে।
জেনারেট করে ক্লায়েন্টকে ভ্যালু রিটার্ন করে এমন ইন্টারফেস পদ্ধতিকে বোঝায়। একটি নন-প্রিমিটিভ ভ্যালু বা একাধিক ভ্যালু ফেরত দিতে, একটি সিঙ্ক্রোনাস কলব্যাক ফাংশন তৈরি করা হয়।
ইন্টারফেস পদ্ধতি ও প্রকারের সংগ্রহ। C++ বা Java-তে ক্লাসে অনুবাদ করা হয়েছে। ইন্টারফেসে সব পদ্ধতি একই দিকে কল করা হয়: ক্লায়েন্ট প্রসেস সার্ভার প্রসেস দ্বারা প্রয়োগ করা পদ্ধতিকে আহ্বান করে।
ওয়ান-ওয়ে HIDL পদ্ধতিতে প্রয়োগ করা হলে, এটি বোঝায় যে পদ্ধতিটি কোনও ভ্যালু রিটার্ন করে না এবং ব্লক করে না।
প্যাকেজ একটি ভার্সন শেয়ার করা ইন্টারফেস ও ডেটার ধরন সংগ্রহ করা।
পাসথ্রু HIDL-এর এমন মোড যেখানে সার্ভার হল শেয়ার করা লাইব্রেরি, dlopened ক্লায়েন্টের দ্বারা। পাসথ্রু মোডে, ক্লায়েন্ট ও সার্ভার একই প্রসেস হলেও আলাদা কোডবেস। শুধুমাত্র HIDL মডেলে লেগ্যাসি কোডবেস নিয়ে আসার জন্য ব্যবহার করা হয়। এছাড়াও বাইন্ডারাইজড দেখুন।
সার্ভার ইন্টারফেসের পদ্ধতি প্রয়োগ করে এমন প্রসেস। এছাড়াও, পাসথ্রু দেখুন।
পরিবহন HIDL পরিকাঠামো যা সার্ভার ও ক্লায়েন্টের মধ্যে ডেটা সরানোর কাজ করে।
ভার্সন প্যাকেজের ভার্সন। দুটি পূর্ণসংখ্যা, মেজর ও মাইনর নিয়ে গঠিত। মাইনর ভার্সন ইনক্রিমেন্ট, ধরন ও পদ্ধতি যোগ করতে পারে (কিন্তু পরিবর্তন করতে পারে না)।

HIDL ডিজাইন

HIDL-এর লক্ষ্য হল, HAL-কে আবার তৈরি না করেই Android ফ্রেমওয়ার্ককে পরিবর্তন করা যায়। HAL ভেন্ডর বা SOC প্রস্তুতকারক তৈরি করে এবং ডিভাইসের /vendor পার্টিশনে রাখে, যার ফলে Android ফ্রেমওয়ার্ক, নিজের পার্টিশনে, HAL রিকম্পাইল না করেই OTA-এর মাধ্যমে রিপ্লেস করা যায়।

HIDL ডিজাইন নিম্নলিখিত বিষয়গুলির মধ্যে ভারসাম্য বজায় রাখে:

  • ইন্টারঅপারেবিলিটি। বিভিন্ন আর্কিটেকচার, টুলচেন ও বিল্ড কনফিগারেশনের সাথে কম্পাইল করা হতে পারে এমন প্রসেসের মধ্যে নির্ভরযোগ্যভাবে ইন্টারঅপারেবল ইন্টারফেস তৈরি করুন। HIDL ইন্টারফেসের ভার্সন করা হয় এবং সেগুলি প্রকাশ করার পরে পরিবর্তন করা যায় না।
  • দক্ষতা। HIDL কপি অপারেশনের সংখ্যা কমানোর চেষ্টা করে। HIDL-এর মাধ্যমে সংজ্ঞায়িত ডেটা C++ স্ট্যান্ডার্ড লেআউট ডেটা স্ট্রাকচারে C++ কোডে ডেলিভার করা হয় যা আনপ্যাক না করেই ব্যবহার করা যায়। এছাড়াও, HIDL শেয়ার করা মেমরি ইন্টারফেস প্রদান করে এবং যেহেতু RPC কিছুটা ধীর গতির হয়, তাই RPC কল ব্যবহার না করেই ডেটা ট্রান্সফার করার জন্য HIDL দুটি পদ্ধত কাজ করে: শেয়ার করা মেমরি ও একটি ফাস্ট মেসেজ কিউ (FMQ)।
  • স্বজ্ঞাত। HIDL, RPC-এর জন্য শুধুমাত্র in প্যারামিটার ব্যবহার করে মেমরি মালিকানার জটিল সমস্যা এড়িয়ে যায় (Android ইন্টারফেস ডেফিনিশন ল্যাঙ্গুয়েজ (AIDL) দেখুন); যেসব ভ্যালু পদ্ধতি থেকে দক্ষতার সাথে ফিরিয়ে দেওয়া যায় না, সেগুলি কলব্যাক ফাংশনের মাধ্যমে ফিরিয়ে দেওয়া হয়। ট্রান্সফারের জন্য HIDL-এ ডেটা পাস করা বা HIDL থেকে ডেটা গ্রহণ করা, কোনওটিই ডেটার মালিকানা পরিবর্তন করে না—মালিকানা সবসময় কল করা ফাংশনের কাছেই থাকে। কল করা ফাংশনের সময়সীমা পর্যন্তই ডেটা সেভ করে রাখতে হবে এবং কল করা ফাংশন রিটার্ন করার সাথে সাথেই তা মুছে ফেলতে হবে।

পাসথ্রু মোড ব্যবহার করা

Android-এর পুরনো ভার্সন থেকে Android O-তে ডিভাইস আপডেট করতে, আপনি নতুন HIDL ইন্টারফেসে প্রচলিত (এবং লিগ্যাসি) HAL, দুটিই র‍্যাপ করতে পারবেন যা বাইন্ডারাইজড এবং একই-প্রসেস (পাসথ্রু) মোডে HAL পরিবেশন করে। এই র‍্যাপিং HAL ও Android ফ্রেমওয়ার্ক, দু'টির কাছেই ট্রান্সপারেন্ট।

পাসথ্রু মোড শুধুমাত্র C++ ক্লায়েন্ট ও ইমপ্লিমেন্টেশনের জন্য উপলভ্য। Android-এর আগের ভার্সন চলা ডিভাইসে Java-তে লেখা HAL থাকে না, তাই Java HAL স্বাভাবিকভাবেই বাইন্ডারাইজড হয়।

.hal ফাইল কম্পাইল করা হলে, বাইন্ডার কমিউনিকেশনের জন্য ব্যবহৃত হেডার ছাড়াও hidl-gen একটি অতিরিক্ত পাসথ্রু হেডার ফাইল BsFoo.h তৈরি করে; এই হেডার dlopen করার জন্য ফাংশন নির্ধারণ করে। পাসথ্রু HAL যেহেতু একই প্রসেসে রান করে যেখানে সেগুলি কল করা হয়, তাই বেশিরভাগ ক্ষেত্রে পাসথ্রু মেথড সরাসরি ফাংশন কল (একই থ্রেড) দ্বারা ইনভোক করা হয়। oneway পদ্ধতিগুলি নিজস্ব থ্রেডে রান করে কারণ HAL-এর সেগুলি প্রসেস করার জন্য অপেক্ষা করার কথা নয় (এর অর্থ হল, পাসথ্রু মোডে oneway পদ্ধতি ব্যবহার করে এমন যেকোনও HAL-কে থ্রেড-সেফ হতে হবে)।

IFoo.hal-এর ক্ষেত্রে, BsFoo.h HIDL-জেনারেটেড পদ্ধতিকে র‍্যাপ করে যাতে অতিরিক্ত ফিচার (যেমন, অন্য থ্রেডে oneway ট্রানজ্যাকশন চালানো) প্রদান করা যায়। এই ফাইলটি BpFoo.h-এর মতো, তবে বাইন্ডার ব্যবহার করে IPC-এর মাধ্যমে কল পাস করার পরিবর্তে, কাঙ্ক্ষিত ফাংশন সরাসরি ইনভোক করা হয়। HAL-এর ভবিষ্যৎ ইমপ্লিমেন্টেশন একাধিক ইমপ্লিমেন্টেশন প্রদান করতে পারে, যেমন FooFast HAL এবং একটি FooAccurate HAL। এই ধরনের ক্ষেত্রে, প্রতিটি অতিরিক্ত ইমপ্লিমেন্টেশনের জন্য একটি ফাইল তৈরি করা হবে (যেমন, PTFooFast.cpp এবং PTFooAccurate.cpp)।

বাইন্ডারাইজিং পাসথ্রু HAL

আপনি পাসথ্রু মোড কাজ করে এমন HAL প্রয়োগগুলিকে বাইন্ডারাইজ করতে পারবেন। একটি HAL ইন্টারফেস a.b.c.d@M.N::IFoo-এর জন্য দুটি প্যাকেজ তৈরি করা হয়:

  • a.b.c.d@M.N::IFoo-impl. HAL-এর প্রয়োগ করা আছে এবং ফাংশন IFoo* HIDL_FETCH_IFoo(const char* name) এক্সপোজ করে। পুরনো ডিভাইসে, এই প্যাকেজ dlopen করা হয় এবং HIDL_FETCH_IFoo ব্যবহার করে ইমপ্লিমেন্টেশন ইনস্ট্যান্টিয়েট করা হয়। আপনি hidl-gen, -Lc++-impl এবং -Landroidbp-impl ব্যবহার করে বেস কোড জেনারেট করতে পারবেন।
  • a.b.c.d@M.N::IFoo-service. পাসথ্রু HAL খোলে এবং নিজেকে বাইন্ডারাইজড পরিষেবা হিসেবে রেজিস্টার করে, এর ফলে একই HAL ইমপ্লিমেন্টেশন পাসথ্রু ও বাইন্ডারাইজড হিসেবে ব্যবহার করা যায়।

IFoo টাইপ দেওয়া থাকলে, IFoo-এর কোনও ইনস্ট্যান্স অ্যাক্সেস করতে আপনি sp<IFoo> IFoo::getService(string name, bool getStub)-কে কল করতে পারেন। getStub সত্য হলে, getService শুধুমাত্র পাসথ্রু মোডে HAL খোলার চেষ্টা করে। getStub false হলে, getService বাইন্ডারাইজড পরিষেবা খোঁজার চেষ্টা করে; সেটি ব্যর্থ হলে, পাসথ্রু পরিষেবা খোঁজার চেষ্টা করে। getStub প্যারামিটারটি defaultPassthroughServiceImplementation ছাড়া অন্য কোথাও ব্যবহার করা যাবে না। (যেসব ডিভাইস Android O-এর সাথে লঞ্চ করা হয় সেগুলি সম্পূর্ণ বাইন্ডারাইজড ডিভাইস, তাই পাসথ্রু মোডে কোনও পরিষেবা খোলা অনুমোদিত নয়।)

HIDL ব্যাকরণ

ডিজাইন অনুযায়ী, HIDL ভাষা C-এর মতো (তবে C প্রিপ্রসেসর ব্যবহার করে না)। নিচে বর্ণনা করা হয়নি এমন সব যতিচিহ্ন (= ও |-এর স্পষ্ট ব্যবহার বাদ দিয়ে) ব্যাকরণের অংশ।

মনে রাখবেন: HIDL কোড স্টাইল সম্পর্কে বিস্তারিত জানতে, কোড স্টাইল গাইড দেখুন।

  • /** */ ডকুমেন্টেশন কমেন্ট নির্দেশ করে। এগুলি শুধুমাত্র টাইপ, মেথড, ফিল্ড ও এনুম ভ্যালু ঘোষণার ক্ষেত্রে প্রয়োগ করা যেতে পারে।
  • /* */ দিয়ে মাল্টিলাইন কমেন্ট বোঝানো হয়।
  • // লাইনের শেষে কমেন্ট নির্দেশ করে। // ছাড়া, নিউলাইন হল অন্য যেকোনও হোয়াইটস্পেসের মতো।
  • নিচে দেওয়া ব্যাকরণের উদাহরণে, // থেকে লাইনের শেষ পর্যন্ত টেক্সট ব্যাকরণের অংশ নয়, বরং ব্যাকরণের উপর একটি কমেন্ট।
  • [empty] চিহ্নটির অর্থ হল, শব্দটি ফাঁকা থাকতে পারে।
  • ? কোনও আক্ষরিক অর্থ বা শব্দ অনুসরণ করার অর্থ হল এটি ঐচ্ছিক।
  • ...-এর মাধ্যমে এমন সিকোয়েন্স বোঝানো হয় যাতে শূন্য বা তার বেশি আইটেম থাকে এবং চিহ্ন দিয়ে বিচ্ছেদকারী যতিচিহ্ন দেখানো হয়। HIDL-এ কোনও ভেরিয়াডিক আর্গুমেন্ট নেই।
  • কমা দিয়ে সিকোয়েন্স এলিমেন্ট আলাদা করা হয়।
  • সেমিকোলন প্রতিটি এলিমেন্টকে শেষ করে, এর মধ্যে শেষ এলিমেন্টও অন্তর্ভুক্ত।
  • UPPERCASE হল একটি ননটার্মিনাল।
  • italics হল টোকেন ফ্যামিলি যেমন integer বা identifier (স্ট্যান্ডার্ড C পার্সিং নিয়ম)।
  • constexpr হল C স্টাইল কনস্ট্যান্ট এক্সপ্রেশন (যেমন 1 + 1 এবং 1L << 3)।
  • import_name হল একটি প্যাকেজ বা ইন্টারফেসের নাম, যা HIDL ভার্সনিং-এ বর্ণিত হিসাবে যোগ্য।
  • ছোট হাতের words হল লিটারেল টোকেন।

উদাহরণ:

ROOT =
    PACKAGE IMPORTS PREAMBLE { ITEM ITEM ... }  // not for types.hal
  | PACKAGE IMPORTS ITEM ITEM...  // only for types.hal; no method definitions

ITEM =
    ANNOTATIONS? oneway? identifier(FIELD, FIELD ...) GENERATES?;
  |  safe_union identifier { UFIELD; UFIELD; ...};
  |  struct identifier { SFIELD; SFIELD; ...};  // Note - no forward declarations
  |  union identifier { UFIELD; UFIELD; ...};
  |  enum identifier: TYPE { ENUM_ENTRY, ENUM_ENTRY ... }; // TYPE = enum or scalar
  |  typedef TYPE identifier;

VERSION = integer.integer;

PACKAGE = package android.hardware.identifier[.identifier[...]]@VERSION;

PREAMBLE = interface identifier EXTENDS

EXTENDS = <empty> | extends import_name  // must be interface, not package

GENERATES = generates (FIELD, FIELD ...)

// allows the Binder interface to be used as a type
// (similar to typedef'ing the final identifier)
IMPORTS =
   [empty]
  |  IMPORTS import import_name;

TYPE =
  uint8_t | int8_t | uint16_t | int16_t | uint32_t | int32_t | uint64_t | int64_t |
 float | double | bool | string
|  identifier  // must be defined as a typedef, struct, union, enum or import
               // including those defined later in the file
|  memory
|  pointer
|  vec<TYPE>
|  bitfield<TYPE>  // TYPE is user-defined enum
|  fmq_sync<TYPE>
|  fmq_unsync<TYPE>
|  TYPE[SIZE]

FIELD =
   TYPE identifier

UFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SFIELD =
   TYPE identifier
  |  safe_union identifier { FIELD; FIELD; ...};
  |  struct identifier { FIELD; FIELD; ...};
  |  union identifier { FIELD; FIELD; ...};
  |  safe_union identifier { FIELD; FIELD; ...} identifier;
  |  struct identifier { FIELD; FIELD; ...} identifier;
  |  union identifier { FIELD; FIELD; ...} identifier;

SIZE =  // Must be greater than zero
     constexpr

ANNOTATIONS =
     [empty]
  |  ANNOTATIONS ANNOTATION

ANNOTATION =
  |  @identifier
  |  @identifier(VALUE)
  |  @identifier(ANNO_ENTRY, ANNO_ENTRY  ...)

ANNO_ENTRY =
     identifier=VALUE

VALUE =
     "any text including \" and other escapes"
  |  constexpr
  |  {VALUE, VALUE ...}  // only in annotations

ENUM_ENTRY =
     identifier
  |  identifier = constexpr