HidlBinderSupport.h revision 6bf733ec867a5d46ea05ae5c280a27b051f5018c
1/*
2 * Copyright (C) 2016 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_HIDL_BINDER_SUPPORT_H
18#define ANDROID_HIDL_BINDER_SUPPORT_H
19
20#include <hidl/HidlSupport.h>
21#include <hidl/HidlTransportUtils.h>
22#include <hidl/MQDescriptor.h>
23#include <hidl/Static.h>
24#include <hwbinder/IBinder.h>
25#include <hwbinder/Parcel.h>
26#include <android/hidl/base/1.0/BnBase.h>
27// Defines functions for hidl_string, hidl_version, Status, hidl_vec, MQDescriptor,
28// etc. to interact with Parcel.
29
30namespace android {
31namespace hardware {
32
33// ---------------------- hidl_memory
34
35status_t readEmbeddedFromParcel(hidl_memory *memory,
36        const Parcel &parcel, size_t parentHandle, size_t parentOffset);
37
38status_t writeEmbeddedToParcel(const hidl_memory &memory,
39        Parcel *parcel, size_t parentHandle, size_t parentOffset);
40
41// ---------------------- hidl_string
42
43status_t readEmbeddedFromParcel(hidl_string *string,
44        const Parcel &parcel, size_t parentHandle, size_t parentOffset);
45
46status_t writeEmbeddedToParcel(const hidl_string &string,
47        Parcel *parcel, size_t parentHandle, size_t parentOffset);
48
49// ---------------------- hidl_version
50
51status_t writeToParcel(const hidl_version &version, android::hardware::Parcel& parcel);
52
53// Caller is responsible for freeing the returned object.
54hidl_version* readFromParcel(const android::hardware::Parcel& parcel);
55
56// ---------------------- Status
57
58// Bear in mind that if the client or service is a Java endpoint, this
59// is not the logic which will provide/interpret the data here.
60status_t readFromParcel(Status *status, const Parcel& parcel);
61status_t writeToParcel(const Status &status, Parcel* parcel);
62
63// ---------------------- hidl_vec
64
65template<typename T>
66status_t readEmbeddedFromParcel(
67        hidl_vec<T> * /*vec*/,
68        const Parcel &parcel,
69        size_t parentHandle,
70        size_t parentOffset,
71        size_t *handle) {
72    const void *ptr = parcel.readEmbeddedBuffer(
73            handle,
74            parentHandle,
75            parentOffset + hidl_vec<T>::kOffsetOfBuffer);
76
77    return ptr != NULL ? OK : UNKNOWN_ERROR;
78}
79
80template<typename T>
81status_t writeEmbeddedToParcel(
82        const hidl_vec<T> &vec,
83        Parcel *parcel,
84        size_t parentHandle,
85        size_t parentOffset,
86        size_t *handle) {
87    return parcel->writeEmbeddedBuffer(
88            vec.data(),
89            sizeof(T) * vec.size(),
90            handle,
91            parentHandle,
92            parentOffset + hidl_vec<T>::kOffsetOfBuffer);
93}
94
95template<typename T>
96status_t findInParcel(const hidl_vec<T> &vec, const Parcel &parcel, size_t *handle) {
97    return parcel.quickFindBuffer(vec.data(), handle);
98}
99
100// ---------------------- MQDescriptor
101
102template<MQFlavor flavor>
103::android::status_t readEmbeddedFromParcel(
104        MQDescriptor<flavor> *obj,
105        const ::android::hardware::Parcel &parcel,
106        size_t parentHandle,
107        size_t parentOffset) {
108    ::android::status_t _hidl_err = ::android::OK;
109
110    size_t _hidl_grantors_child;
111
112    _hidl_err = ::android::hardware::readEmbeddedFromParcel(
113                &obj->grantors(),
114                parcel,
115                parentHandle,
116                parentOffset + MQDescriptor<flavor>::kOffsetOfGrantors,
117                &_hidl_grantors_child);
118
119    if (_hidl_err != ::android::OK) { return _hidl_err; }
120
121    const native_handle_t *_hidl_mq_handle_ptr = parcel.readEmbeddedNativeHandle(
122            parentHandle,
123            parentOffset + MQDescriptor<flavor>::kOffsetOfHandle);
124
125    if (_hidl_mq_handle_ptr == nullptr) {
126        _hidl_err = ::android::UNKNOWN_ERROR;
127        return _hidl_err;
128    }
129
130    return _hidl_err;
131}
132
133template<MQFlavor flavor>
134::android::status_t writeEmbeddedToParcel(
135        const MQDescriptor<flavor> &obj,
136        ::android::hardware::Parcel *parcel,
137        size_t parentHandle,
138        size_t parentOffset) {
139    ::android::status_t _hidl_err = ::android::OK;
140
141    size_t _hidl_grantors_child;
142
143    _hidl_err = ::android::hardware::writeEmbeddedToParcel(
144            obj.grantors(),
145            parcel,
146            parentHandle,
147            parentOffset + MQDescriptor<flavor>::kOffsetOfGrantors,
148            &_hidl_grantors_child);
149
150    if (_hidl_err != ::android::OK) { return _hidl_err; }
151
152    _hidl_err = parcel->writeEmbeddedNativeHandle(
153            obj.handle(),
154            parentHandle,
155            parentOffset + MQDescriptor<flavor>::kOffsetOfHandle);
156
157    if (_hidl_err != ::android::OK) { return _hidl_err; }
158
159    return _hidl_err;
160}
161
162// ---------------------- pointers for HIDL
163
164template <typename T>
165static status_t readEmbeddedReferenceFromParcel(
166        T const* * /* bufptr */,
167        const Parcel & parcel,
168        size_t parentHandle,
169        size_t parentOffset,
170        size_t *handle,
171        bool *shouldResolveRefInBuffer
172    ) {
173    // *bufptr is ignored because, if I am embedded in some
174    // other buffer, the kernel should have fixed me up already.
175    bool isPreviouslyWritten;
176    status_t result = parcel.readEmbeddedReference(
177        nullptr, // ignored, not written to bufptr.
178        handle,
179        parentHandle,
180        parentOffset,
181        &isPreviouslyWritten);
182    // tell caller to run T::readEmbeddedToParcel and
183    // T::readEmbeddedReferenceToParcel if necessary.
184    // It is not called here because we don't know if these two are valid methods.
185    *shouldResolveRefInBuffer = !isPreviouslyWritten;
186    return result;
187}
188
189template <typename T>
190static status_t writeEmbeddedReferenceToParcel(
191        T const* buf,
192        Parcel *parcel, size_t parentHandle, size_t parentOffset,
193        size_t *handle,
194        bool *shouldResolveRefInBuffer
195        ) {
196
197    if(buf == nullptr) {
198        *shouldResolveRefInBuffer = false;
199        return parcel->writeEmbeddedNullReference(handle, parentHandle, parentOffset);
200    }
201
202    // find whether the buffer exists
203    size_t childHandle, childOffset;
204    status_t result;
205    bool found;
206
207    result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
208
209    // tell caller to run T::writeEmbeddedToParcel and
210    // T::writeEmbeddedReferenceToParcel if necessary.
211    // It is not called here because we don't know if these two are valid methods.
212    *shouldResolveRefInBuffer = !found;
213
214    if(result != OK) {
215        return result; // bad pointers and length given
216    }
217    if(!found) { // did not find it.
218        return parcel->writeEmbeddedBuffer(buf, sizeof(T), handle,
219                parentHandle, parentOffset);
220    }
221    // found the buffer. easy case.
222    return parcel->writeEmbeddedReference(
223            handle,
224            childHandle,
225            childOffset,
226            parentHandle,
227            parentOffset);
228}
229
230template <typename T>
231static status_t readReferenceFromParcel(
232        T const* *bufptr,
233        const Parcel & parcel,
234        size_t *handle,
235        bool *shouldResolveRefInBuffer
236    ) {
237    bool isPreviouslyWritten;
238    status_t result = parcel.readReference(reinterpret_cast<void const* *>(bufptr),
239            handle, &isPreviouslyWritten);
240    // tell caller to run T::readEmbeddedToParcel and
241    // T::readEmbeddedReferenceToParcel if necessary.
242    // It is not called here because we don't know if these two are valid methods.
243    *shouldResolveRefInBuffer = !isPreviouslyWritten;
244    return result;
245}
246
247template <typename T>
248static status_t writeReferenceToParcel(
249        T const *buf,
250        Parcel * parcel,
251        size_t *handle,
252        bool *shouldResolveRefInBuffer
253    ) {
254
255    if(buf == nullptr) {
256        *shouldResolveRefInBuffer = false;
257        return parcel->writeNullReference(handle);
258    }
259
260    // find whether the buffer exists
261    size_t childHandle, childOffset;
262    status_t result;
263    bool found;
264
265    result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset);
266
267    // tell caller to run T::writeEmbeddedToParcel and
268    // T::writeEmbeddedReferenceToParcel if necessary.
269    // It is not called here because we don't know if these two are valid methods.
270    *shouldResolveRefInBuffer = !found;
271
272    if(result != OK) {
273        return result; // bad pointers and length given
274    }
275    if(!found) { // did not find it.
276        return parcel->writeBuffer(buf, sizeof(T), handle);
277    }
278    // found the buffer. easy case.
279    return parcel->writeReference(handle,
280        childHandle, childOffset);
281}
282
283// ---------------------- support for casting interfaces
284
285// Construct a smallest possible binder from the given interface.
286// If it is remote, then its remote() will be retrieved.
287// Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType
288// and iface is of class IChild. BnChild will be used to wrapped the given iface.
289// Return nullptr if iface is null or any failure.
290template <typename IType, typename ProxyType>
291sp<IBinder> toBinder(sp<IType> iface) {
292    IType *ifacePtr = iface.get();
293    if (ifacePtr == nullptr) {
294        return nullptr;
295    }
296    if (ifacePtr->isRemote()) {
297        return ::android::hardware::IInterface::asBinder(static_cast<ProxyType *>(ifacePtr));
298    } else {
299        std::string myDescriptor = getDescriptor(ifacePtr);
300        if (myDescriptor.empty()) {
301            // interfaceChain fails
302            return nullptr;
303        }
304        auto iter = gBnConstructorMap.find(myDescriptor);
305        if (iter == gBnConstructorMap.end()) {
306            return nullptr;
307        }
308        return sp<IBinder>((iter->second)(reinterpret_cast<void *>(ifacePtr)));
309    }
310}
311
312template <typename IType, typename ProxyType, typename StubType>
313sp<IType> fromBinder(const sp<IBinder>& binderIface) {
314    using ::android::hidl::base::V1_0::IBase;
315    using ::android::hidl::base::V1_0::BnBase;
316
317    if (binderIface.get() == nullptr) {
318        return nullptr;
319    }
320    if (binderIface->localBinder() == nullptr) {
321        return new ProxyType(binderIface);
322    }
323    sp<IBase> base = static_cast<BnBase*>(binderIface.get())->getImpl();
324    if (canCastInterface(base.get(), IType::descriptor)) {
325        StubType* stub = static_cast<StubType*>(binderIface.get());
326        return stub->getImpl();
327    } else {
328        return nullptr;
329    }
330}
331
332}  // namespace hardware
333}  // namespace android
334
335
336#endif  // ANDROID_HIDL_BINDER_SUPPORT_H
337