Home | History | Annotate | Download | only in hidl
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_HYBRIDINTERFACE_H
     18 #define ANDROID_HYBRIDINTERFACE_H
     19 
     20 #include <vector>
     21 #include <mutex>
     22 
     23 #include <binder/Parcel.h>
     24 #include <hidl/HidlSupport.h>
     25 
     26 /**
     27  * Hybrid Interfaces
     28  * =================
     29  *
     30  * A hybrid interface is a binder interface that
     31  * 1. is implemented both traditionally and as a wrapper around a hidl
     32  *    interface, and allows querying whether the underlying instance comes from
     33  *    a hidl interface or not; and
     34  * 2. allows efficient calls to a hidl interface (if the underlying instance
     35  *    comes from a hidl interface) by automatically creating the wrapper in the
     36  *    process that calls it.
     37  *
     38  * Terminology:
     39  * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
     40  *   be compatible with `ITokenManager.hal`.
     41  * - `HInterface`: The base type for a hidl interface. Currently, it is defined
     42  *   as `::android::hidl::base::V1_0::IBase`.
     43  * - `HALINTERFACE`: The hidl interface that will be sent through binders.
     44  * - `INTERFACE`: The binder interface that will be the wrapper of
     45  *   `HALINTERFACE`. `INTERFACE` is supposed to be somewhat similar to
     46  *   `HALINTERFACE`.
     47  *
     48  * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
     49  * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
     50  * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
     51  *    definition of `IFoo`. The usage is
     52  *        DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
     53  *    inside the body of `IFoo`.
     54  * 2. Create a converter class that derives from
     55  *    `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
     56  * 3. Add the following constructor in `H2BFoo` that call the corresponding
     57  *    constructors in `H2BConverter`:
     58  *        H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
     59  *    Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
     60  *    are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
     61  *    line can be copied into `H2BFoo`.
     62  * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
     63  *    protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
     64  *    instance. (There is also a public function named `getHalInterface()` that
     65  *    returns `mBase`.)
     66  * 5. Create a hardware proxy class that derives from
     67  *    `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
     68  *    deviate. See step 8 below.)
     69  * 6. Add the following constructor to `HpFoo`:
     70  *        HpFoo(const sp<IBinder>& base): PBase(base) {}
     71  *    Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
     72  *    equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
     73  *    copied verbatim into `HpFoo`.
     74  * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
     75  *    `getHalInterface` to the protected member `mBase`,
     76  *    which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
     77  *    type `IFoo`. (There is also a public function named `getBaseInterface()`
     78  *    that returns `mBase`.)
     79  * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
     80  *    `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
     81  *    exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
     82  *    An example usage is
     83  *        IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
     84  *
     85  * `GETTOKEN` Template Argument
     86  * ============================
     87  *
     88  * Following the instructions above, `H2BConverter` and `HpInterface` would use
     89  * `transact()` to send over tokens, with `code` (the first argument of
     90  * `transact()`) equal to `DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE`. If this
     91  * value clashes with other values already in use in the `Bp` class, it can be
     92  * changed by supplying the last optional template argument to `H2BConverter`
     93  * and `HpInterface`.
     94  *
     95  */
     96 
     97 namespace android {
     98 
     99 typedef ::android::hardware::hidl_vec<uint8_t> HalToken;
    100 typedef ::android::hidl::base::V1_0::IBase HInterface;
    101 
    102 constexpr uint32_t DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE =
    103         B_PACK_CHARS('_', 'G', 'H', 'T');
    104 
    105 sp<HInterface> retrieveHalInterface(const HalToken& token);
    106 bool createHalToken(const sp<HInterface>& interface, HalToken* token);
    107 bool deleteHalToken(const HalToken& token);
    108 
    109 template <
    110         typename HINTERFACE,
    111         typename INTERFACE,
    112         typename BNINTERFACE,
    113         uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
    114 class H2BConverter : public BNINTERFACE {
    115 public:
    116     typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
    117     typedef INTERFACE BaseInterface;
    118     typedef HINTERFACE HalInterface;
    119     static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
    120 
    121     H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
    122     virtual status_t onTransact(uint32_t code,
    123             const Parcel& data, Parcel* reply, uint32_t flags = 0);
    124     virtual sp<HalInterface> getHalInterface() { return mBase; }
    125     HalInterface* getBaseInterface() { return mBase.get(); }
    126     virtual status_t linkToDeath(
    127             const sp<IBinder::DeathRecipient>& recipient,
    128             void* cookie = nullptr,
    129             uint32_t flags = 0);
    130     virtual status_t unlinkToDeath(
    131             const wp<IBinder::DeathRecipient>& recipient,
    132             void* cookie = nullptr,
    133             uint32_t flags = 0,
    134             wp<IBinder::DeathRecipient>* outRecipient = nullptr);
    135 
    136 protected:
    137     sp<HalInterface> mBase;
    138     struct Obituary : public hardware::hidl_death_recipient {
    139         wp<IBinder::DeathRecipient> recipient;
    140         void* cookie;
    141         uint32_t flags;
    142         wp<IBinder> who;
    143         Obituary(
    144                 const wp<IBinder::DeathRecipient>& r,
    145                 void* c, uint32_t f,
    146                 const wp<IBinder>& w) :
    147             recipient(r), cookie(c), flags(f), who(w) {
    148         }
    149         Obituary(const Obituary& o) :
    150             recipient(o.recipient),
    151             cookie(o.cookie),
    152             flags(o.flags),
    153             who(o.who) {
    154         }
    155         Obituary& operator=(const Obituary& o) {
    156             recipient = o.recipient;
    157             cookie = o.cookie;
    158             flags = o.flags;
    159             who = o.who;
    160             return *this;
    161         }
    162         void serviceDied(uint64_t, const wp<HInterface>&) override {
    163             sp<IBinder::DeathRecipient> dr = recipient.promote();
    164             if (dr != nullptr) {
    165                 dr->binderDied(who);
    166             }
    167         }
    168     };
    169     std::mutex mObituariesLock;
    170     std::vector<sp<Obituary> > mObituaries;
    171 };
    172 
    173 template <
    174         typename BPINTERFACE,
    175         typename CONVERTER,
    176         uint32_t GETTOKEN = DEFAULT_GET_HAL_TOKEN_TRANSACTION_CODE>
    177 class HpInterface : public CONVERTER::BaseInterface {
    178 public:
    179     typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
    180     typedef typename CONVERTER::BaseInterface BaseInterface;
    181     typedef typename CONVERTER::HalInterface HalInterface;
    182     static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
    183 
    184     explicit HpInterface(const sp<IBinder>& impl);
    185     virtual sp<HalInterface> getHalInterface() { return mHal; }
    186     BaseInterface* getBaseInterface() { return mBase.get(); }
    187 
    188 protected:
    189     IBinder* mImpl;
    190     sp<BPINTERFACE> mBp;
    191     sp<BaseInterface> mBase;
    192     sp<HalInterface> mHal;
    193     IBinder* onAsBinder() override { return mImpl; }
    194 };
    195 
    196 // ----------------------------------------------------------------------
    197 
    198 #define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL)                   \
    199     static const ::android::String16 descriptor;                        \
    200     static ::android::sp<I##INTERFACE> asInterface(                     \
    201             const ::android::sp<::android::IBinder>& obj);              \
    202     virtual const ::android::String16& getInterfaceDescriptor() const;  \
    203     I##INTERFACE();                                                     \
    204     virtual ~I##INTERFACE();                                            \
    205     virtual sp<HAL> getHalInterface();                                  \
    206 
    207 
    208 #define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME)           \
    209     const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    210     const ::android::String16&                                          \
    211             I##INTERFACE::getInterfaceDescriptor() const {              \
    212         return I##INTERFACE::descriptor;                                \
    213     }                                                                   \
    214     ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
    215             const ::android::sp<::android::IBinder>& obj)               \
    216     {                                                                   \
    217         ::android::sp<I##INTERFACE> intr;                               \
    218         if (obj != nullptr) {                                           \
    219             intr = static_cast<I##INTERFACE*>(                          \
    220                 obj->queryLocalInterface(                               \
    221                         I##INTERFACE::descriptor).get());               \
    222             if (intr == nullptr) {                                      \
    223                 intr = new Hp##INTERFACE(obj);                          \
    224             }                                                           \
    225         }                                                               \
    226         return intr;                                                    \
    227     }                                                                   \
    228     I##INTERFACE::I##INTERFACE() { }                                    \
    229     I##INTERFACE::~I##INTERFACE() { }                                   \
    230     sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; }         \
    231 
    232 // ----------------------------------------------------------------------
    233 
    234 template <
    235         typename HINTERFACE,
    236         typename INTERFACE,
    237         typename BNINTERFACE,
    238         uint32_t GETTOKEN>
    239 status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
    240         onTransact(
    241         uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
    242     if (code == GET_HAL_TOKEN) {
    243         HalToken token;
    244         bool result;
    245         result = createHalToken(mBase, &token);
    246         if (!result) {
    247             ALOGE("H2BConverter: Failed to create HAL token.");
    248         }
    249         reply->writeBool(result);
    250         reply->writeByteArray(token.size(), token.data());
    251         return NO_ERROR;
    252     }
    253     return BNINTERFACE::onTransact(code, data, reply, flags);
    254 }
    255 
    256 template <
    257         typename HINTERFACE,
    258         typename INTERFACE,
    259         typename BNINTERFACE,
    260         uint32_t GETTOKEN>
    261 status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
    262         linkToDeath(
    263         const sp<IBinder::DeathRecipient>& recipient,
    264         void* cookie, uint32_t flags) {
    265     LOG_ALWAYS_FATAL_IF(recipient == nullptr,
    266             "linkToDeath(): recipient must be non-nullptr");
    267     {
    268         std::lock_guard<std::mutex> lock(mObituariesLock);
    269         mObituaries.push_back(new Obituary(recipient, cookie, flags, this));
    270         if (!mBase->linkToDeath(mObituaries.back(), 0)) {
    271            return DEAD_OBJECT;
    272         }
    273     }
    274     return NO_ERROR;
    275 }
    276 
    277 template <
    278         typename HINTERFACE,
    279         typename INTERFACE,
    280         typename BNINTERFACE,
    281         uint32_t GETTOKEN>
    282 status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
    283         unlinkToDeath(
    284         const wp<IBinder::DeathRecipient>& recipient,
    285         void* cookie, uint32_t flags,
    286         wp<IBinder::DeathRecipient>* outRecipient) {
    287     std::lock_guard<std::mutex> lock(mObituariesLock);
    288     for (auto i = mObituaries.begin(); i != mObituaries.end(); ++i) {
    289         if ((flags = (*i)->flags) && (
    290                 (recipient == (*i)->recipient) ||
    291                 ((recipient == nullptr) && (cookie == (*i)->cookie)))) {
    292             if (outRecipient != nullptr) {
    293                 *outRecipient = (*i)->recipient;
    294             }
    295             bool success = mBase->unlinkToDeath(*i);
    296             mObituaries.erase(i);
    297             return success ? NO_ERROR : DEAD_OBJECT;
    298         }
    299     }
    300     return NAME_NOT_FOUND;
    301 }
    302 
    303 template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
    304 HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
    305         const sp<IBinder>& impl) :
    306     mImpl(impl.get()),
    307     mBp(new BPINTERFACE(impl)) {
    308     mBase = mBp;
    309     if (mImpl->remoteBinder() == nullptr) {
    310         return;
    311     }
    312     Parcel data, reply;
    313     data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
    314     if (mImpl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
    315         bool tokenCreated = reply.readBool();
    316 
    317         std::vector<uint8_t> tokenVector;
    318         reply.readByteVector(&tokenVector);
    319         HalToken token = HalToken(tokenVector);
    320 
    321         if (tokenCreated) {
    322             sp<HInterface> hBase = retrieveHalInterface(token);
    323             if (hBase != nullptr) {
    324                 mHal = HalInterface::castFrom(hBase);
    325                 if (mHal != nullptr) {
    326                     mBase = new CONVERTER(mHal);
    327                 } else {
    328                     ALOGE("HpInterface: Wrong interface type.");
    329                 }
    330             } else {
    331                 ALOGE("HpInterface: Invalid HAL token.");
    332             }
    333             deleteHalToken(token);
    334         }
    335     }
    336 }
    337 
    338 // ----------------------------------------------------------------------
    339 
    340 }; // namespace android
    341 
    342 #endif // ANDROID_HYBRIDINTERFACE_H
    343