HIDL Java

Android 8.0 में, Android OS को फिर से डिज़ाइन किया गया था, ताकि डिवाइस पर काम करने वाले Android प्लैटफ़ॉर्म और डिवाइस और वेंडर के हिसाब से बने कोड के बीच साफ़ इंटरफ़ेस तय किए जा सकें. Android ने पहले से ही एचएएल इंटरफ़ेस के तौर पर ऐसे कई इंटरफ़ेस तय किए हैं. इन्हें hardware/libhardware में C हेडर के तौर पर तय किया गया है. HIDL ने इन एचएएल इंटरफ़ेस को, वर्शन वाले स्टेबल इंटरफ़ेस से बदल दिया है. ये इंटरफ़ेस, Java में हो सकते हैं (इसके बारे में नीचे बताया गया है) या C++ में क्लाइंट- और सर्वर-साइड HIDL इंटरफ़ेस हो सकते हैं.

HIDL इंटरफ़ेस का इस्तेमाल मुख्य रूप से नेटिव कोड से किया जाता है. इसलिए, HIDL का मकसद C++ में बेहतर कोड को अपने-आप जनरेट करना है. हालांकि, HIDL इंटरफ़ेस को सीधे Java से इस्तेमाल करने के लिए भी उपलब्ध होना चाहिए, क्योंकि कुछ Android सबसिस्टम (जैसे, टेलीफ़ोन) में Java HIDL इंटरफ़ेस होते हैं.

इस सेक्शन के पेजों पर, HIDL इंटरफ़ेस के लिए Java फ़्रंटएंड के बारे में बताया गया है. साथ ही, सेवाएं बनाने, रजिस्टर करने, और इस्तेमाल करने का तरीका भी बताया गया है. साथ ही, यह भी बताया गया है कि Java में लिखे गए एचएएल और एचएएल क्लाइंट, HIDL आरपीसी सिस्टम के साथ कैसे इंटरैक्ट करते हैं.

क्लाइंट का उदाहरण

यह पैकेजandroid.hardware.foo@1.0 में मौजूद इंटरफ़ेस IFoo के लिए क्लाइंट का उदाहरण है. इसे सेवा के नामdefault के तौर पर रजिस्टर किया गया है. साथ ही, इसमें कस्टम सेवा के नामsecond_impl वाली एक अतिरिक्त सेवा भी है.

लाइब्रेरी जोड़ना

अगर आपको इसका इस्तेमाल करना है, तो आपको उससे जुड़ी HIDL स्टब लाइब्रेरी पर डिपेंडेंसी जोड़नी होंगी. आम तौर पर, यह एक स्टैटिक लाइब्रेरी होती है:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

अगर आपको पता है कि आपने पहले से ही इन लाइब्रेरी की डिपेंडेंसी शामिल कर ली हैं, तो शेयर किए गए लिंक का इस्तेमाल भी किया जा सकता है:

// in Android.bp
libs: [ "android.hardware.foo-V1.0-java", ],
// in Android.mk
LOCAL_JAVA_LIBRARIES += android.hardware.foo-V1.0-java

Android 10 में लाइब्रेरी जोड़ने के लिए अन्य बातें

अगर आपके पास कोई ऐसा सिस्टम या वेंडर ऐप्लिकेशन है जो Android 10 या उसके बाद के वर्शन को टारगेट करता है, तो इन लाइब्रेरी को स्टैटिक तौर पर शामिल किया जा सकता है. डिवाइस पर इंस्टॉल किए गए कस्टम JAR से, सिर्फ़ HIDL क्लास का इस्तेमाल भी किया जा सकता है. इसके लिए, सिस्टम ऐप्लिकेशन के लिए मौजूदा uses-library तरीके का इस्तेमाल करके, स्थिर Java API उपलब्ध कराए जाते हैं. ज़्यादा जानकारी के लिए, Java SDK लाइब्रेरी लागू करना लेख पढ़ें. हालांकि, पुराने ऐप्लिकेशन के लिए, पुराना तरीका ही लागू रहेगा.

Android 10 से, इन लाइब्रेरी के "शैलो" वर्शन भी उपलब्ध हैं. इनमें वह क्लास शामिल होती है जिसकी जांच की जा रही है, लेकिन इनमें डिपेंडेंट क्लास शामिल नहीं होती हैं. उदाहरण के लिए, android.hardware.foo-V1.0-java-shallow में foo पैकेज की क्लास शामिल हैं, लेकिन इसमें android.hidl.base-V1.0-java की क्लास शामिल नहीं हैं. android.hidl.base-V1.0-java में सभी HIDL इंटरफ़ेस की बेस क्लास शामिल होती है. अगर कोई ऐसी लाइब्रेरी बनाई जा रही है जिसमें पहले से ही, डिपेंडेंसी के तौर पर पसंदीदा इंटरफ़ेस की बुनियादी क्लास उपलब्ध हैं, तो इनका इस्तेमाल किया जा सकता है:

// in Android.bp
static_libs: [ "android.hardware.foo-V1.0-java-shallow", ],
// in Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += android.hardware.foo-V1.0-java-shallow

ऐप्लिकेशन के लिए, अब बूट क्लासपाथ पर HIDL बेस और मैनेजर लाइब्रेरी भी उपलब्ध नहीं हैं. पहले, Android के डिलीगेट-फ़र्स्ट क्लासलोडर की वजह से, इनका इस्तेमाल कभी-कभी छिपे हुए एपीआई के तौर पर किया जाता था. इसके बजाय, उन्हें jarjar के साथ एक नए नेमस्पेस में ले जाया गया है. साथ ही, इनका इस्तेमाल करने वाले ऐप्लिकेशन (ज़रूरी रूप से निजी ऐप्लिकेशन) के पास उनकी अलग-अलग कॉपी होनी चाहिए. HIDL का इस्तेमाल करने वाले, बूट क्लासपाथ पर मौजूद मॉड्यूल को इन Java लाइब्रेरी के शैलो वैरिएंट का इस्तेमाल करना होगा. साथ ही, बूट क्लासपाथ में मौजूद इन लाइब्रेरी के वर्शन का इस्तेमाल करने के लिए, अपने Android.bp में jarjar_rules: ":framework-jarjar-rules" जोड़ना होगा.

अपने Java सोर्स में बदलाव करना

इस सेवा का सिर्फ़ एक वर्शन (@1.0) है, इसलिए यह कोड सिर्फ़ उस वर्शन को फिर से पाता है. सेवा के कई अलग-अलग वर्शन को मैनेज करने का तरीका जानने के लिए, इंटरफ़ेस एक्सटेंशन देखें.

import android.hardware.foo.V1_0.IFoo;
...
// retry to wait until the service starts up if it is in the manifest
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IFoo anotherServer = IFoo.getService("second_impl", true /* retry */);
server.doSomething(…);

कोई सेवा उपलब्ध कराना

Java में फ़्रेमवर्क कोड को इंटरफ़ेस दिखाने की ज़रूरत पड़ सकती है, ताकि एचएएल से असाइनोक्रोनस कॉलबैक मिल सकें.

android.hardware.foo पैकेज के 1.0 वर्शन में IFooCallback इंटरफ़ेस के लिए, यहां दिए गए तरीके का इस्तेमाल करके, अपने इंटरफ़ेस को Java में लागू किया जा सकता है:

  1. HIDL में अपना इंटरफ़ेस तय करें.
  2. /tmp/android/hardware/foo/IFooCallback.java को रेफ़रंस के तौर पर खोलें.
  3. Java लागू करने के लिए, एक नया मॉड्यूल बनाएं.
  4. ऐब्स्ट्रैक्ट क्लास android.hardware.foo.V1_0.IFooCallback.Stub की जांच करें. इसके बाद, उसे एक्सटेंड करने और ऐब्स्ट्रैक्ट तरीके लागू करने के लिए, एक नई क्लास लिखें.

अपने-आप जनरेट हुई फ़ाइलें देखना

अपने-आप जनरेट हुई फ़ाइलें देखने के लिए, यह चलाएं:

hidl-gen -o /tmp -Ljava \
  -randroid.hardware:hardware/interfaces \
  -randroid.hidl:system/libhidl/transport android.hardware.foo@1.0

ये निर्देश डायरेक्ट्री /tmp/android/hardware/foo/1.0 जनरेट करते हैं. यह फ़ाइल hardware/interfaces/foo/1.0/IFooCallback.hal के लिए, फ़ाइल /tmp/android/hardware/foo/1.0/IFooCallback.java जनरेट करती है. इसमें Java इंटरफ़ेस, प्रॉक्सी कोड, और स्टब शामिल होते हैं. प्रॉक्सी और स्टब, दोनों इंटरफ़ेस के मुताबिक होते हैं.

-Lmakefile, ऐसे नियम जनरेट करता है जो बिल्ड के समय इस कमांड को चलाते हैं. साथ ही, आपको android.hardware.foo-V1.0-java को शामिल करने और सही फ़ाइलों से लिंक करने की अनुमति देते हैं. इंटरफ़ेस से भरे प्रोजेक्ट के लिए, यह काम अपने-आप करने वाली स्क्रिप्ट hardware/interfaces/update-makefiles.sh पर देखी जा सकती है. इस उदाहरण में दिए गए पाथ, रिलेटिव हैं. हार्डवेयर/इंटरफ़ेस, आपके कोड ट्री में एक अस्थायी डायरेक्ट्री हो सकती है, ताकि आप इसे पब्लिश करने से पहले HAL डेवलप कर सकें.

कोई सेवा चलाना

एचएएल, IFoo इंटरफ़ेस उपलब्ध कराता है. इसे IFooCallback इंटरफ़ेस के ज़रिए, फ़्रेमवर्क को असाइनोक्रोनस कॉलबैक करना होगा. IFooCallback इंटरफ़ेस को, खोजी जा सकने वाली सेवा के तौर पर नाम से रजिस्टर नहीं किया जाता. इसके बजाय, IFoo में setFooCallback(IFooCallback x) जैसा कोई तरीका होना चाहिए.

android.hardware.foo पैकेज के वर्शन 1.0 से IFooCallback को सेट अप करने के लिए, Android.mk में android.hardware.foo-V1.0-java जोड़ें. सेवा को चलाने के लिए कोड यह है:

import android.hardware.foo.V1_0.IFoo;
import android.hardware.foo.V1_0.IFooCallback.Stub;
....
class FooCallback extends IFooCallback.Stub {
    // implement methods
}
....
// Get the service from which you will be receiving callbacks.
// This also starts the threadpool for your callback service.
IFoo server = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
....
// This must be a persistent instance variable, not local,
//   to avoid premature garbage collection.
FooCallback mFooCallback = new FooCallback();
....
// Do this once to create the callback service and tell the "foo-bar" service
server.setFooCallback(mFooCallback);

इंटरफ़ेस एक्सटेंशन

मान लें कि कोई सेवा सभी डिवाइसों पर IFoo इंटरफ़ेस लागू करती है, तो हो सकता है कि किसी डिवाइस पर वह सेवा, इंटरफ़ेस एक्सटेंशन IBetterFoo में लागू की गई अतिरिक्त सुविधाएं उपलब्ध कराए. ऐसा इन तरीकों से किया जा सकता है:

interface IFoo {
   ...
};

interface IBetterFoo extends IFoo {
   ...
};

एक्सटेंडेड इंटरफ़ेस के बारे में जानने वाला कोड, castFrom() Java तरीके का इस्तेमाल करके, बेस इंटरफ़ेस को एक्सटेंडेड इंटरफ़ेस में सुरक्षित तरीके से कास्ट कर सकता है:

IFoo baseService = IFoo.getService(true /* retry */); // throws NoSuchElementException if not available
IBetterFoo extendedService = IBetterFoo.castFrom(baseService);
if (extendedService != null) {
  // The service implements the extended interface.
} else {
  // The service implements only the base interface.
}