| /* |
| * 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 |