Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cb2345e authored by Jeongik Cha's avatar Jeongik Cha
Browse files

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
parent e51e48b0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ cc_library {
        "MemoryDealer.cpp",
        "MemoryHeapBase.cpp",
        "Parcel.cpp",
        "ParcelableHolder.cpp",
        "ParcelFileDescriptor.cpp",
        "PersistableBundle.cpp",
        "ProcessState.cpp",
+97 −0
Original line number Diff line number Diff line
/*
 * 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
+1 −1
Original line number Diff line number Diff line
@@ -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
    };
+141 −0
Original line number Diff line number Diff line
/*
 * 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