blob: 7ef4f9638afc8e454b008d69958806a5ed89327c [file] [log] [blame]
Pawin Vongmasafbffe922017-03-01 02:25:36 -08001/*
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_HALTOKEN_H
18#define ANDROID_HALTOKEN_H
19
20#include <binder/Parcel.h>
21#include <hidl/HidlSupport.h>
22
23/**
24 * It is possible to pass a hidl interface via as a binder interface by
25 * providing an appropriate "wrapper" class.
26 *
27 * Terminology:
28 * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
29 * be compatible with `ITokenManager.hal`.
30 * - `HInterface`: The base type for a hidl interface. Currently, it is defined
31 * as `::android::hidl::base::V1_0::IBase`.
32 * - `HALINTERFACE`: The hidl interface that will be sent through binders.
33 * - `INTERFACE`: The binder interface that will be the wrapper of
34 * `HALINTERFACE`. `INTERFACE` is supposed to be similar to `HALINTERFACE`.
35 *
36 * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
37 * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
38 * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
39 * definition of `IFoo`. The usage is
40 * DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
41 * inside the body of `IFoo`.
42 * 2. Create a converter class that derives from
43 * `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
44 * 3. Add the following constructors in `H2BFoo` that call the corresponding
45 * constructors in `H2BConverter`:
46 * H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
47 * Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
48 * are member typedefs of `CBase`, so the above line can be copied verbatim
49 * into `H2BFoo`.
50 * 4. Add conversion functions inside `H2BFoo`. `H2BConverter` provides a
51 * protected `mBase` of type `sp<HFoo>` that can be used to access the HFoo
52 * instance. (There is also a public function named `getHalInterface()` that
53 * returns `mBase`.)
54 * 5. Create a hardware proxy class that derives from
55 * `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
56 * deviate. See step 8 below.)
57 * 6. Add the following constructor to `HpFoo`:
58 * HpFoo(const sp<IBinder>& base): PBase(base) {}
59 * Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
60 * equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
61 * copied verbatim into `HpFoo`.
62 * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
63 * `getHalToken` and `getHalInterface` to the protected member `mBase`,
64 * which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
65 * type `IFoo`. (There is also a public function named `getBaseInterface()`
66 * that returns `mBase`.)
67 * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
68 * `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
69 * exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
70 * An example usage is
71 * IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
72 *
73 * `GETTOKEN` Template Argument
74 * ============================
75 *
76 * Following the instructions above, `H2BConverter` and `HpInterface` would use
77 * `transact()` to send over tokens, with `code` (the first argument of
78 * `transact()`) equal to a 4-byte value of '_GTK'. If this value clashes with
79 * other values already in use in the `Bp` class, it can be changed by supplying
80 * the last optional template argument to `H2BConverter` and `HpInterface`.
81 *
82 */
83
84namespace android {
85
86typedef uint64_t HalToken;
87typedef ::android::hidl::base::V1_0::IBase HInterface;
88
89sp<HInterface> retrieveHalInterface(const HalToken& token);
90bool createHalToken(const sp<HInterface>& interface, HalToken* token);
91bool deleteHalToken(const HalToken& token);
92
93template <
94 typename HINTERFACE,
95 typename INTERFACE,
96 typename BNINTERFACE,
97 uint32_t GETTOKEN = '_GTK'>
98class H2BConverter : public BNINTERFACE {
99public:
100 typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase;
101 typedef INTERFACE BaseInterface;
102 typedef HINTERFACE HalInterface;
103 static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
104
105 H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
106 virtual status_t onTransact(uint32_t code,
107 const Parcel& data, Parcel* reply, uint32_t flags = 0);
108 sp<HalInterface> getHalInterface() override { return mBase; }
109 HalInterface* getBaseInterface() { return mBase.get(); }
110
111protected:
112 sp<HalInterface> mBase;
113};
114
115template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN = '_GTK'>
116class HpInterface : public BPINTERFACE {
117public:
118 typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
119 typedef typename CONVERTER::BaseInterface BaseInterface;
120 typedef typename CONVERTER::HalInterface HalInterface;
121 static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
122
123 explicit HpInterface(const sp<IBinder>& impl);
124 sp<HalInterface> getHalInterface() override { return mHal; }
125 BaseInterface* getBaseInterface() { return mBase.get(); }
126
127protected:
128 sp<BaseInterface> mBase;
129 sp<HalInterface> mHal;
130};
131
132// ----------------------------------------------------------------------
133
134#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL) \
135 static const ::android::String16 descriptor; \
136 static ::android::sp<I##INTERFACE> asInterface( \
137 const ::android::sp<::android::IBinder>& obj); \
138 virtual const ::android::String16& getInterfaceDescriptor() const; \
139 I##INTERFACE(); \
140 virtual ~I##INTERFACE(); \
141 virtual sp<HAL> getHalInterface(); \
142
143
144#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME) \
145 const ::android::String16 I##INTERFACE::descriptor(NAME); \
146 const ::android::String16& \
147 I##INTERFACE::getInterfaceDescriptor() const { \
148 return I##INTERFACE::descriptor; \
149 } \
150 ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
151 const ::android::sp<::android::IBinder>& obj) \
152 { \
153 ::android::sp<I##INTERFACE> intr; \
154 if (obj != NULL) { \
155 intr = static_cast<I##INTERFACE*>( \
156 obj->queryLocalInterface( \
157 I##INTERFACE::descriptor).get()); \
158 if (intr == NULL) { \
159 intr = new Hp##INTERFACE(obj); \
160 } \
161 } \
162 return intr; \
163 } \
164 I##INTERFACE::I##INTERFACE() { } \
165 I##INTERFACE::~I##INTERFACE() { } \
166 sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; } \
167
168// ----------------------------------------------------------------------
169
170template <
171 typename HINTERFACE,
172 typename INTERFACE,
173 typename BNINTERFACE,
174 uint32_t GETTOKEN>
175status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
176 onTransact(
177 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
178 if (code == GET_HAL_TOKEN) {
179 HalToken token;
180 bool result;
181 result = createHalToken(mBase, &token);
182 if (!result) {
183 ALOGE("H2BConverter: Failed to create HAL token.");
184 }
185 reply->writeBool(result);
186 reply->writeUint64(token);
187 return NO_ERROR;
188 }
189 return BNINTERFACE::onTransact(code, data, reply, flags);
190}
191
192template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
193HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
194 const sp<IBinder>& impl):
195 BPINTERFACE(impl),
196 mBase(nullptr) {
197
198 Parcel data, reply;
199 data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
200 if (this->remote()->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
201 bool tokenCreated = reply.readBool();
202 HalToken token = reply.readUint64();
203 if (!tokenCreated) {
204 ALOGE("HpInterface: Sender failed to create HAL token.");
205 mBase = this;
206 } else {
207 sp<HInterface> hInterface = retrieveHalInterface(token);
208 deleteHalToken(token);
209 if (hInterface != nullptr) {
210 mHal = static_cast<HalInterface*>(hInterface.get());
211 mBase = new CONVERTER(mHal);
212 } else {
213 ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
214 mBase = this;
215 }
216 }
217 } else {
218 mBase = this;
219 }
220}
221
222// ----------------------------------------------------------------------
223
224}; // namespace android
225
226#endif // ANDROID_HALTOKEN_H