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 class AParcelableHolder { 45 public: 46 AParcelableHolder() = delete; AParcelableHolder(parcelable_stability_t stability)47 explicit AParcelableHolder(parcelable_stability_t stability) 48 : mParcel(AParcel_create()), mStability(stability) {} 49 50 virtual ~AParcelableHolder() = default; 51 writeToParcel(AParcel * parcel)52 binder_status_t writeToParcel(AParcel* parcel) const { 53 RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability))); 54 if (__builtin_available(android 31, *)) { 55 int32_t size = AParcel_getDataSize(this->mParcel.get()); 56 RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size)); 57 } else { 58 return STATUS_INVALID_OPERATION; 59 } 60 if (__builtin_available(android 31, *)) { 61 int32_t size = AParcel_getDataSize(this->mParcel.get()); 62 RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size)); 63 } else { 64 return STATUS_INVALID_OPERATION; 65 } 66 return STATUS_OK; 67 } 68 readFromParcel(const AParcel * parcel)69 binder_status_t readFromParcel(const AParcel* parcel) { 70 if (__builtin_available(android 31, *)) { 71 AParcel_reset(mParcel.get()); 72 } else { 73 return STATUS_INVALID_OPERATION; 74 } 75 76 RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability)); 77 int32_t dataSize; 78 binder_status_t status = AParcel_readInt32(parcel, &dataSize); 79 80 if (status != STATUS_OK || dataSize < 0) { 81 return status != STATUS_OK ? status : STATUS_BAD_VALUE; 82 } 83 84 int32_t dataStartPos = AParcel_getDataPosition(parcel); 85 86 if (dataStartPos > INT32_MAX - dataSize) { 87 return STATUS_BAD_VALUE; 88 } 89 90 if (__builtin_available(android 31, *)) { 91 status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize); 92 } else { 93 status = STATUS_INVALID_OPERATION; 94 } 95 if (status != STATUS_OK) { 96 return status; 97 } 98 return AParcel_setDataPosition(parcel, dataStartPos + dataSize); 99 } 100 101 template <typename T> setParcelable(const T & p)102 binder_status_t setParcelable(const T& p) { 103 if (this->mStability > T::_aidl_stability) { 104 return STATUS_BAD_VALUE; 105 } 106 if (__builtin_available(android 31, *)) { 107 AParcel_reset(mParcel.get()); 108 } else { 109 return STATUS_INVALID_OPERATION; 110 } 111 AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor)); 112 p.writeToParcel(mParcel.get()); 113 return STATUS_OK; 114 } 115 116 template <typename T> getParcelable(std::optional<T> * ret)117 binder_status_t getParcelable(std::optional<T>* ret) const { 118 const std::string parcelableDesc(T::descriptor); 119 AParcel_setDataPosition(mParcel.get(), 0); 120 if (__builtin_available(android 31, *)) { 121 if (AParcel_getDataSize(mParcel.get()) == 0) { 122 *ret = std::nullopt; 123 return STATUS_OK; 124 } 125 } else { 126 return STATUS_INVALID_OPERATION; 127 } 128 std::string parcelableDescInParcel; 129 binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel); 130 if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) { 131 *ret = std::nullopt; 132 return status; 133 } 134 *ret = std::make_optional<T>(); 135 status = (*ret)->readFromParcel(this->mParcel.get()); 136 if (status != STATUS_OK) { 137 *ret = std::nullopt; 138 return status; 139 } 140 return STATUS_OK; 141 } 142 reset()143 void reset() { 144 if (__builtin_available(android 31, *)) { 145 AParcel_reset(mParcel.get()); 146 } 147 } 148 149 inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; } 150 inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; } 151 inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; } 152 inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; } 153 inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; } 154 inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; } 155 156 private: 157 mutable ndk::ScopedAParcel mParcel; 158 parcelable_stability_t mStability; 159 }; 160 161 #undef RETURN_ON_FAILURE 162 } // namespace ndk 163 164 /** @} */ 165