diff options
author | 2020-08-26 23:38:03 +0900 | |
---|---|---|
committer | 2020-09-11 15:19:14 +0900 | |
commit | 8cb2345ef06fa993c257f9be513a5f476dc8e328 (patch) | |
tree | e0efc297b484ef0495412aab4ed7b4645eb692d0 | |
parent | e51e48b0f04d5ef2350308dde2a118cad690723b (diff) |
Add ParcelableHolder
Add the implementation of ParcelableHolder which helps Parcelable to be
extendable.
It is equivalent to ParcelableHolder.java
Bug: 146611855
Test: atest aidl_integration_test aidl_unittests
Change-Id: I581fd2c2794744d30c51bd26f2289d96f960bc67
-rw-r--r-- | libs/binder/Android.bp | 1 | ||||
-rw-r--r-- | libs/binder/ParcelableHolder.cpp | 97 | ||||
-rw-r--r-- | libs/binder/include/binder/Parcelable.h | 2 | ||||
-rw-r--r-- | libs/binder/include/binder/ParcelableHolder.h | 141 |
4 files changed, 240 insertions, 1 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 9675a5321e..d363ee9ea4 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -99,6 +99,7 @@ cc_library { "MemoryDealer.cpp", "MemoryHeapBase.cpp", "Parcel.cpp", + "ParcelableHolder.cpp", "ParcelFileDescriptor.cpp", "PersistableBundle.cpp", "ProcessState.cpp", diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp new file mode 100644 index 0000000000..e9df27976c --- /dev/null +++ b/libs/binder/ParcelableHolder.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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. + */ + +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <binder/ParcelableHolder.h> + +#define RETURN_ON_FAILURE(expr) \ + do { \ + android::status_t _status = (expr); \ + if (_status != android::OK) return _status; \ + } while (false) + +namespace android { +namespace os { +status_t ParcelableHolder::writeToParcel(Parcel* p) const { + std::lock_guard<std::mutex> l(mMutex); + RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability()))); + if (this->mParcelPtr) { + RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize())); + RETURN_ON_FAILURE(p->appendFrom(this->mParcelPtr.get(), 0, this->mParcelPtr->dataSize())); + return OK; + } + if (this->mParcelable) { + size_t sizePos = p->dataPosition(); + RETURN_ON_FAILURE(p->writeInt32(0)); + size_t dataStartPos = p->dataPosition(); + RETURN_ON_FAILURE(p->writeUtf8AsUtf16(this->mParcelableName)); + this->mParcelable->writeToParcel(p); + size_t dataSize = p->dataPosition() - dataStartPos; + + p->setDataPosition(sizePos); + RETURN_ON_FAILURE(p->writeInt32(dataSize)); + p->setDataPosition(p->dataPosition() + dataSize); + return OK; + } + + RETURN_ON_FAILURE(p->writeInt32(0)); + return OK; +} + +status_t ParcelableHolder::readFromParcel(const Parcel* p) { + std::lock_guard<std::mutex> l(mMutex); + this->mStability = static_cast<Stability>(p->readInt32()); + this->mParcelable = nullptr; + this->mParcelableName = std::nullopt; + int32_t rawDataSize; + + status_t status = p->readInt32(&rawDataSize); + if (status != android::OK || rawDataSize < 0) { + this->mParcelPtr = nullptr; + return status != android::OK ? status : BAD_VALUE; + } + if (rawDataSize == 0) { + if (this->mParcelPtr) { + this->mParcelPtr = nullptr; + } + return OK; + } + + size_t dataSize = rawDataSize; + + size_t dataStartPos = p->dataPosition(); + + if (dataStartPos > SIZE_MAX - dataSize) { + this->mParcelPtr = nullptr; + return BAD_VALUE; + } + + if (!this->mParcelPtr) { + this->mParcelPtr = std::make_unique<Parcel>(); + } + this->mParcelPtr->freeData(); + + status = this->mParcelPtr->appendFrom(p, dataStartPos, dataSize); + if (status != android::OK) { + this->mParcelPtr = nullptr; + return status; + } + p->setDataPosition(dataStartPos + dataSize); + return OK; +} +} // namespace os +} // namespace android diff --git a/libs/binder/include/binder/Parcelable.h b/libs/binder/include/binder/Parcelable.h index 83c2f1991d..a6e610ca19 100644 --- a/libs/binder/include/binder/Parcelable.h +++ b/libs/binder/include/binder/Parcelable.h @@ -56,7 +56,7 @@ public: // WARNING: for use by auto-generated code only (AIDL). Should not be used // manually, or there is a risk of breaking CTS, GTS, VTS, or CTS-on-GSI // tests. - enum class Stability { + enum class Stability : int32_t { STABILITY_LOCAL, STABILITY_VINTF, // corresponds to @VintfStability }; diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h new file mode 100644 index 0000000000..b6814aa5fe --- /dev/null +++ b/libs/binder/include/binder/ParcelableHolder.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include <binder/Parcel.h> +#include <binder/Parcelable.h> +#include <mutex> +#include <optional> +#include <tuple> + +namespace android { +namespace os { +/* + * C++ implementation of the Java class android.os.ParcelableHolder + */ +class ParcelableHolder : public android::Parcelable { +public: + ParcelableHolder() = delete; + explicit ParcelableHolder(Stability stability) : mStability(stability){}; + virtual ~ParcelableHolder() = default; + ParcelableHolder(const ParcelableHolder& other) { + mParcelable = other.mParcelable; + mParcelableName = other.mParcelableName; + if (other.mParcelPtr) { + mParcelPtr = std::make_unique<Parcel>(); + mParcelPtr->appendFrom(other.mParcelPtr.get(), 0, other.mParcelPtr->dataSize()); + } + mStability = other.mStability; + }; + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + void reset() { + this->mParcelable = nullptr; + this->mParcelableName = std::nullopt; + this->mParcelPtr = nullptr; + } + + template <typename T> + bool setParcelable(T&& p) { + using Tt = typename std::decay<T>::type; + return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p))); + } + + template <typename T> + bool setParcelable(std::shared_ptr<T> p) { + std::lock_guard<std::mutex> l(mMutex); + static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable"); + if (p && this->getStability() > p->getStability()) { + return false; + } + this->mParcelable = p; + this->mParcelableName = T::getParcelableDescriptor(); + this->mParcelPtr = nullptr; + return true; + } + + template <typename T> + std::shared_ptr<T> getParcelable() const { + static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable"); + std::lock_guard<std::mutex> l(mMutex); + const std::string& parcelableDesc = T::getParcelableDescriptor(); + if (!this->mParcelPtr) { + if (!this->mParcelable || !this->mParcelableName) { + ALOGD("empty ParcelableHolder"); + return nullptr; + } else if (parcelableDesc != *mParcelableName) { + ALOGD("extension class name mismatch expected:%s actual:%s", + mParcelableName->c_str(), parcelableDesc.c_str()); + return nullptr; + } + return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get())); + } + this->mParcelPtr->setDataPosition(0); + status_t status = this->mParcelPtr->readUtf8FromUtf16(&this->mParcelableName); + if (status != android::OK || parcelableDesc != this->mParcelableName) { + this->mParcelableName = std::nullopt; + return nullptr; + } + this->mParcelable = std::make_shared<T>(); + status = mParcelable.get()->readFromParcel(this->mParcelPtr.get()); + if (status != android::OK) { + this->mParcelableName = std::nullopt; + this->mParcelable = nullptr; + return nullptr; + } + this->mParcelPtr = nullptr; + return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get())); + } + + Stability getStability() const override { return mStability; }; + + inline bool operator!=(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) != + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + inline bool operator<(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) < + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + inline bool operator<=(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) <= + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + inline bool operator==(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) == + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + inline bool operator>(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) > + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + inline bool operator>=(const ParcelableHolder& rhs) const { + return std::tie(mParcelable, mParcelPtr, mStability) >= + std::tie(rhs.mParcelable, rhs.mParcelPtr, rhs.mStability); + } + +private: + mutable std::shared_ptr<Parcelable> mParcelable; + mutable std::optional<std::string> mParcelableName; + mutable std::unique_ptr<Parcel> mParcelPtr; + Stability mStability; + mutable std::mutex mMutex; +}; +} // namespace os +} // namespace android |