1 /* 2 * Copyright (C) 2020 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 /** 18 * @addtogroup NdkBinder 19 * @{ 20 */ 21 22 /** 23 * @file binder_parcelable_utils.h 24 * @brief Helper for parcelable. 25 */ 26 27 #pragma once 28 #include <android/binder_parcel_utils.h> 29 #include <optional> 30 31 namespace ndk { 32 // Also see Parcelable.h in libbinder. 33 typedef int32_t parcelable_stability_t; 34 enum { 35 STABILITY_LOCAL, 36 STABILITY_VINTF, // corresponds to @VintfStability 37 }; 38 #define RETURN_ON_FAILURE(expr) \ 39 do { \ 40 binder_status_t _status = (expr); \ 41 if (_status != STATUS_OK) return _status; \ 42 } while (false) 43 44 // AParcelableHolder has been introduced in 31. 45 #if __ANDROID_API__ >= 31 46 class AParcelableHolder { 47 public: 48 AParcelableHolder() = delete; AParcelableHolder(parcelable_stability_t stability)49 explicit AParcelableHolder(parcelable_stability_t stability) 50 : mParcel(AParcel_create()), mStability(stability) {} 51 AParcelableHolder(const AParcelableHolder & other)52 AParcelableHolder(const AParcelableHolder& other) 53 : mParcel(AParcel_create()), mStability(other.mStability) { 54 AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0, 55 AParcel_getDataSize(other.mParcel.get())); 56 } 57 58 AParcelableHolder(AParcelableHolder&& other) = default; 59 virtual ~AParcelableHolder() = default; 60 writeToParcel(AParcel * parcel)61 binder_status_t writeToParcel(AParcel* parcel) const { 62 RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability))); 63 int32_t size = AParcel_getDataSize(this->mParcel.get()); 64 RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size)); 65 size = AParcel_getDataSize(this->mParcel.get()); 66 RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size)); 67 return STATUS_OK; 68 } 69 readFromParcel(const AParcel * parcel)70 binder_status_t readFromParcel(const AParcel* parcel) { 71 AParcel_reset(mParcel.get()); 72 73 parcelable_stability_t wireStability; 74 RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability)); 75 if (this->mStability != wireStability) { 76 return STATUS_BAD_VALUE; 77 } 78 79 int32_t dataSize; 80 binder_status_t status = AParcel_readInt32(parcel, &dataSize); 81 82 if (status != STATUS_OK || dataSize < 0) { 83 return status != STATUS_OK ? status : STATUS_BAD_VALUE; 84 } 85 86 int32_t dataStartPos = AParcel_getDataPosition(parcel); 87 88 if (dataStartPos > INT32_MAX - dataSize) { 89 return STATUS_BAD_VALUE; 90 } 91 92 status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize); 93 if (status != STATUS_OK) { 94 return status; 95 } 96 return AParcel_setDataPosition(parcel, dataStartPos + dataSize); 97 } 98 99 template <typename T> setParcelable(const T & p)100 binder_status_t setParcelable(const T& p) { 101 if (this->mStability > T::_aidl_stability) { 102 return STATUS_BAD_VALUE; 103 } 104 AParcel_reset(mParcel.get()); 105 AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor)); 106 p.writeToParcel(mParcel.get()); 107 return STATUS_OK; 108 } 109 110 template <typename T> getParcelable(std::optional<T> * ret)111 binder_status_t getParcelable(std::optional<T>* ret) const { 112 const std::string parcelableDesc(T::descriptor); 113 AParcel_setDataPosition(mParcel.get(), 0); 114 if (AParcel_getDataSize(mParcel.get()) == 0) { 115 *ret = std::nullopt; 116 return STATUS_OK; 117 } 118 std::string parcelableDescInParcel; 119 binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel); 120 if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) { 121 *ret = std::nullopt; 122 return status; 123 } 124 *ret = std::make_optional<T>(); 125 status = (*ret)->readFromParcel(this->mParcel.get()); 126 if (status != STATUS_OK) { 127 *ret = std::nullopt; 128 return status; 129 } 130 return STATUS_OK; 131 } 132 reset()133 void reset() { AParcel_reset(mParcel.get()); } 134 135 inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; } 136 inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; } 137 inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; } 138 inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; } 139 inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; } 140 inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; } 141 inline AParcelableHolder& operator=(const AParcelableHolder& rhs) { 142 this->reset(); 143 if (this->mStability != rhs.mStability) { 144 syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!", 145 this->mStability, rhs.mStability); 146 abort(); 147 } 148 AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0, 149 AParcel_getDataSize(rhs.mParcel.get())); 150 return *this; 151 } 152 153 private: 154 mutable ndk::ScopedAParcel mParcel; 155 parcelable_stability_t mStability; 156 }; 157 #endif // __ANDROID_API__ >= 31 158 159 #undef RETURN_ON_FAILURE 160 } // namespace ndk 161 162 /** @} */ 163