You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
375 lines
12 KiB
375 lines
12 KiB
/* |
|
* Copyright (C) 2016 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#ifndef ANDROID_HIDL_BINDER_SUPPORT_H |
|
#define ANDROID_HIDL_BINDER_SUPPORT_H |
|
|
|
#include <sys/types.h> |
|
|
|
#include <android/hidl/base/1.0/BnHwBase.h> |
|
#include <android/hidl/base/1.0/IBase.h> |
|
#include <hidl/HidlSupport.h> |
|
#include <hidl/HidlTransportUtils.h> |
|
#include <hidl/MQDescriptor.h> |
|
#include <hidl/Static.h> |
|
#include <hwbinder/IBinder.h> |
|
#include <hwbinder/IPCThreadState.h> |
|
#include <hwbinder/Parcel.h> |
|
#include <hwbinder/ProcessState.h> |
|
// Defines functions for hidl_string, hidl_version, Status, hidl_vec, MQDescriptor, |
|
// etc. to interact with Parcel. |
|
|
|
namespace android { |
|
namespace hardware { |
|
|
|
// hidl_binder_death_recipient wraps a transport-independent |
|
// hidl_death_recipient, and implements the binder-specific |
|
// DeathRecipient interface. |
|
struct hidl_binder_death_recipient : IBinder::DeathRecipient { |
|
hidl_binder_death_recipient(const sp<hidl_death_recipient> &recipient, |
|
uint64_t cookie, const sp<::android::hidl::base::V1_0::IBase> &base); |
|
virtual void binderDied(const wp<IBinder>& /*who*/); |
|
wp<hidl_death_recipient> getRecipient(); |
|
private: |
|
wp<hidl_death_recipient> mRecipient; |
|
uint64_t mCookie; |
|
wp<::android::hidl::base::V1_0::IBase> mBase; |
|
}; |
|
|
|
// ---------------------- hidl_memory |
|
|
|
status_t readEmbeddedFromParcel(const hidl_memory &memory, |
|
const Parcel &parcel, size_t parentHandle, size_t parentOffset); |
|
|
|
status_t writeEmbeddedToParcel(const hidl_memory &memory, |
|
Parcel *parcel, size_t parentHandle, size_t parentOffset); |
|
|
|
// ---------------------- hidl_string |
|
|
|
status_t readEmbeddedFromParcel(const hidl_string &string, |
|
const Parcel &parcel, size_t parentHandle, size_t parentOffset); |
|
|
|
status_t writeEmbeddedToParcel(const hidl_string &string, |
|
Parcel *parcel, size_t parentHandle, size_t parentOffset); |
|
|
|
// ---------------------- hidl_version |
|
|
|
status_t writeToParcel(const hidl_version &version, android::hardware::Parcel& parcel); |
|
|
|
// Caller is responsible for freeing the returned object. |
|
hidl_version* readFromParcel(const android::hardware::Parcel& parcel); |
|
|
|
// ---------------------- Status |
|
|
|
// Bear in mind that if the client or service is a Java endpoint, this |
|
// is not the logic which will provide/interpret the data here. |
|
status_t readFromParcel(Status *status, const Parcel& parcel); |
|
status_t writeToParcel(const Status &status, Parcel* parcel); |
|
|
|
// ---------------------- hidl_vec |
|
|
|
template<typename T> |
|
status_t readEmbeddedFromParcel( |
|
const hidl_vec<T> &vec, |
|
const Parcel &parcel, |
|
size_t parentHandle, |
|
size_t parentOffset, |
|
size_t *handle) { |
|
const void *out; |
|
return parcel.readNullableEmbeddedBuffer( |
|
vec.size() * sizeof(T), |
|
handle, |
|
parentHandle, |
|
parentOffset + hidl_vec<T>::kOffsetOfBuffer, |
|
&out); |
|
} |
|
|
|
template<typename T> |
|
status_t writeEmbeddedToParcel( |
|
const hidl_vec<T> &vec, |
|
Parcel *parcel, |
|
size_t parentHandle, |
|
size_t parentOffset, |
|
size_t *handle) { |
|
return parcel->writeEmbeddedBuffer( |
|
vec.data(), |
|
sizeof(T) * vec.size(), |
|
handle, |
|
parentHandle, |
|
parentOffset + hidl_vec<T>::kOffsetOfBuffer); |
|
} |
|
|
|
template<typename T> |
|
status_t findInParcel(const hidl_vec<T> &vec, const Parcel &parcel, size_t *handle) { |
|
return parcel.quickFindBuffer(vec.data(), handle); |
|
} |
|
|
|
// ---------------------- MQDescriptor |
|
|
|
template<typename T, MQFlavor flavor> |
|
::android::status_t readEmbeddedFromParcel( |
|
MQDescriptor<T, flavor> &obj, |
|
const ::android::hardware::Parcel &parcel, |
|
size_t parentHandle, |
|
size_t parentOffset) { |
|
::android::status_t _hidl_err = ::android::OK; |
|
|
|
size_t _hidl_grantors_child; |
|
|
|
_hidl_err = ::android::hardware::readEmbeddedFromParcel( |
|
obj.grantors(), |
|
parcel, |
|
parentHandle, |
|
parentOffset + MQDescriptor<T, flavor>::kOffsetOfGrantors, |
|
&_hidl_grantors_child); |
|
|
|
if (_hidl_err != ::android::OK) { return _hidl_err; } |
|
|
|
const native_handle_t *_hidl_mq_handle_ptr; |
|
_hidl_err = parcel.readNullableEmbeddedNativeHandle( |
|
parentHandle, |
|
parentOffset + MQDescriptor<T, flavor>::kOffsetOfHandle, |
|
&_hidl_mq_handle_ptr); |
|
|
|
if (_hidl_err != ::android::OK) { return _hidl_err; } |
|
|
|
return _hidl_err; |
|
} |
|
|
|
template<typename T, MQFlavor flavor> |
|
::android::status_t writeEmbeddedToParcel( |
|
const MQDescriptor<T, flavor> &obj, |
|
::android::hardware::Parcel *parcel, |
|
size_t parentHandle, |
|
size_t parentOffset) { |
|
::android::status_t _hidl_err = ::android::OK; |
|
|
|
size_t _hidl_grantors_child; |
|
|
|
_hidl_err = ::android::hardware::writeEmbeddedToParcel( |
|
obj.grantors(), |
|
parcel, |
|
parentHandle, |
|
parentOffset + MQDescriptor<T, flavor>::kOffsetOfGrantors, |
|
&_hidl_grantors_child); |
|
|
|
if (_hidl_err != ::android::OK) { return _hidl_err; } |
|
|
|
_hidl_err = parcel->writeEmbeddedNativeHandle( |
|
obj.handle(), |
|
parentHandle, |
|
parentOffset + MQDescriptor<T, flavor>::kOffsetOfHandle); |
|
|
|
if (_hidl_err != ::android::OK) { return _hidl_err; } |
|
|
|
return _hidl_err; |
|
} |
|
|
|
// ---------------------- pointers for HIDL |
|
|
|
template <typename T> |
|
static status_t readEmbeddedReferenceFromParcel( |
|
T const* * /* bufptr */, |
|
const Parcel & parcel, |
|
size_t parentHandle, |
|
size_t parentOffset, |
|
size_t *handle, |
|
bool *shouldResolveRefInBuffer |
|
) { |
|
// *bufptr is ignored because, if I am embedded in some |
|
// other buffer, the kernel should have fixed me up already. |
|
bool isPreviouslyWritten; |
|
status_t result = parcel.readEmbeddedReference( |
|
nullptr, // ignored, not written to bufptr. |
|
handle, |
|
parentHandle, |
|
parentOffset, |
|
&isPreviouslyWritten); |
|
// tell caller to run T::readEmbeddedToParcel and |
|
// T::readEmbeddedReferenceToParcel if necessary. |
|
// It is not called here because we don't know if these two are valid methods. |
|
*shouldResolveRefInBuffer = !isPreviouslyWritten; |
|
return result; |
|
} |
|
|
|
template <typename T> |
|
static status_t writeEmbeddedReferenceToParcel( |
|
T const* buf, |
|
Parcel *parcel, size_t parentHandle, size_t parentOffset, |
|
size_t *handle, |
|
bool *shouldResolveRefInBuffer |
|
) { |
|
|
|
if(buf == nullptr) { |
|
*shouldResolveRefInBuffer = false; |
|
return parcel->writeEmbeddedNullReference(handle, parentHandle, parentOffset); |
|
} |
|
|
|
// find whether the buffer exists |
|
size_t childHandle, childOffset; |
|
status_t result; |
|
bool found; |
|
|
|
result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset); |
|
|
|
// tell caller to run T::writeEmbeddedToParcel and |
|
// T::writeEmbeddedReferenceToParcel if necessary. |
|
// It is not called here because we don't know if these two are valid methods. |
|
*shouldResolveRefInBuffer = !found; |
|
|
|
if(result != OK) { |
|
return result; // bad pointers and length given |
|
} |
|
if(!found) { // did not find it. |
|
return parcel->writeEmbeddedBuffer(buf, sizeof(T), handle, |
|
parentHandle, parentOffset); |
|
} |
|
// found the buffer. easy case. |
|
return parcel->writeEmbeddedReference( |
|
handle, |
|
childHandle, |
|
childOffset, |
|
parentHandle, |
|
parentOffset); |
|
} |
|
|
|
template <typename T> |
|
static status_t readReferenceFromParcel( |
|
T const* *bufptr, |
|
const Parcel & parcel, |
|
size_t *handle, |
|
bool *shouldResolveRefInBuffer |
|
) { |
|
bool isPreviouslyWritten; |
|
status_t result = parcel.readReference(reinterpret_cast<void const* *>(bufptr), |
|
handle, &isPreviouslyWritten); |
|
// tell caller to run T::readEmbeddedToParcel and |
|
// T::readEmbeddedReferenceToParcel if necessary. |
|
// It is not called here because we don't know if these two are valid methods. |
|
*shouldResolveRefInBuffer = !isPreviouslyWritten; |
|
return result; |
|
} |
|
|
|
template <typename T> |
|
static status_t writeReferenceToParcel( |
|
T const *buf, |
|
Parcel * parcel, |
|
size_t *handle, |
|
bool *shouldResolveRefInBuffer |
|
) { |
|
|
|
if(buf == nullptr) { |
|
*shouldResolveRefInBuffer = false; |
|
return parcel->writeNullReference(handle); |
|
} |
|
|
|
// find whether the buffer exists |
|
size_t childHandle, childOffset; |
|
status_t result; |
|
bool found; |
|
|
|
result = parcel->findBuffer(buf, sizeof(T), &found, &childHandle, &childOffset); |
|
|
|
// tell caller to run T::writeEmbeddedToParcel and |
|
// T::writeEmbeddedReferenceToParcel if necessary. |
|
// It is not called here because we don't know if these two are valid methods. |
|
*shouldResolveRefInBuffer = !found; |
|
|
|
if(result != OK) { |
|
return result; // bad pointers and length given |
|
} |
|
if(!found) { // did not find it. |
|
return parcel->writeBuffer(buf, sizeof(T), handle); |
|
} |
|
// found the buffer. easy case. |
|
return parcel->writeReference(handle, |
|
childHandle, childOffset); |
|
} |
|
|
|
// ---------------------- support for casting interfaces |
|
|
|
// Construct a smallest possible binder from the given interface. |
|
// If it is remote, then its remote() will be retrieved. |
|
// Otherwise, the smallest possible BnChild is found where IChild is a subclass of IType |
|
// and iface is of class IChild. BnChild will be used to wrapped the given iface. |
|
// Return nullptr if iface is null or any failure. |
|
template <typename IType> |
|
sp<IBinder> toBinder(sp<IType> iface) { |
|
IType *ifacePtr = iface.get(); |
|
if (ifacePtr == nullptr) { |
|
return nullptr; |
|
} |
|
if (ifacePtr->isRemote()) { |
|
return ::android::hardware::IInterface::asBinder( |
|
static_cast<BpInterface<IType>*>(ifacePtr)); |
|
} else { |
|
std::string myDescriptor = details::getDescriptor(ifacePtr); |
|
if (myDescriptor.empty()) { |
|
// interfaceDescriptor fails |
|
return nullptr; |
|
} |
|
|
|
// for get + set |
|
std::unique_lock<std::mutex> _lock = details::gBnMap.lock(); |
|
|
|
wp<BHwBinder> wBnObj = details::gBnMap.getLocked(ifacePtr, nullptr); |
|
sp<IBinder> sBnObj = wBnObj.promote(); |
|
|
|
if (sBnObj == nullptr) { |
|
auto func = details::gBnConstructorMap.get(myDescriptor, nullptr); |
|
if (!func) { |
|
return nullptr; |
|
} |
|
|
|
sBnObj = sp<IBinder>(func(static_cast<void*>(ifacePtr))); |
|
|
|
if (sBnObj != nullptr) { |
|
details::gBnMap.setLocked(ifacePtr, static_cast<BHwBinder*>(sBnObj.get())); |
|
} |
|
} |
|
|
|
return sBnObj; |
|
} |
|
} |
|
|
|
template <typename IType, typename ProxyType, typename StubType> |
|
sp<IType> fromBinder(const sp<IBinder>& binderIface) { |
|
using ::android::hidl::base::V1_0::IBase; |
|
using ::android::hidl::base::V1_0::BnHwBase; |
|
|
|
if (binderIface.get() == nullptr) { |
|
return nullptr; |
|
} |
|
if (binderIface->localBinder() == nullptr) { |
|
return new ProxyType(binderIface); |
|
} |
|
sp<IBase> base = static_cast<BnHwBase*>(binderIface.get())->getImpl(); |
|
if (details::canCastInterface(base.get(), IType::descriptor)) { |
|
StubType* stub = static_cast<StubType*>(binderIface.get()); |
|
return stub->getImpl(); |
|
} else { |
|
return nullptr; |
|
} |
|
} |
|
|
|
void configureBinderRpcThreadpool(size_t maxThreads, bool callerWillJoin); |
|
void joinBinderRpcThreadpool(); |
|
|
|
} // namespace hardware |
|
} // namespace android |
|
|
|
|
|
#endif // ANDROID_HIDL_BINDER_SUPPORT_H
|
|
|