1 /* 2 * Copyright (C) 2018 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 #ifndef IORAP_BINDER_AUTO_PARCELABLE_H_ 18 #define IORAP_BINDER_AUTO_PARCELABLE_H_ 19 20 #include "binder/Parcelable.h" 21 #include "binder/Parcel.h" 22 #include "binder/Status.h" 23 24 #include "common/introspection.h" 25 26 namespace iorap { 27 namespace binder { 28 29 // 30 // Implements the android::Parcelable interface (readFromParcel, writeToParcel) 31 // automatically by using compile-time introspection on T. 32 // 33 // Requires that 'T' implements introspection by using the IORAP_INTROSPECT_ADAPT_STRUCT macro. 34 // 35 template <typename T> 36 struct AutoParcelable : public ::android::Parcelable { 37 private: 38 using Status = android::binder::Status; 39 using Parcel = android::Parcel; 40 using Parcelable = android::Parcelable; 41 using status_t = android::status_t; 42 43 public: 44 // Write every (introspected) field to the parcel by automatically inferring the correct 45 // write method to invoke on the parcel from the member type. writeToParcelAutoParcelable46 status_t writeToParcel(Parcel* parcel) const override { 47 if (parcel == nullptr) { 48 return ::android::UNEXPECTED_NULL; 49 } 50 51 status_t result = android::NO_ERROR; 52 ::iorap::introspect::for_each_member_field_value(*Self(), [&](auto&& value) { 53 if (result == android::NO_ERROR) { 54 result = writeAnyToParcel(/*inout*/parcel, value); 55 } 56 }); 57 58 return result; 59 } 60 61 // Read every (introspected) field to the parcel by automatically inferring the correct 62 // read method to invoke on the parcel from the member type. 63 // 64 // Resilient to partial read failures: A return code other than NO_ERROR means that 65 // the current value is left unmodified. readFromParcelAutoParcelable66 status_t readFromParcel(const Parcel* parcel) override { 67 if (parcel == nullptr) { 68 return ::android::UNEXPECTED_NULL; 69 } 70 71 T tmp{*Self()}; 72 73 // Unpack all the parcelable data into a temporary copy. 74 // Parceling could fail halfway through, in which case 75 // the original object is unaffected. 76 77 status_t result = android::NO_ERROR; 78 ::iorap::introspect::for_each_member_field_set_value(tmp, [&](auto field_type) { 79 // type<?> field_type 80 81 using ValueT = typename decltype(field_type)::type; 82 83 if (result == android::NO_ERROR) { 84 auto&& [res, read_value] = readAnyFromParcel<ValueT>(/*inout*/parcel); 85 result = res; 86 return ::iorap::introspect::aliasing_forward<ValueT>(read_value); 87 } else { 88 // TODO: nice-to-have fold over members to early-out on failure. 89 return ValueT{}; 90 } 91 }); 92 93 if (result != android::NO_ERROR) { 94 return result; 95 } 96 97 // Success! Now we can copy all the data in a single step. 98 *Self() = std::move(tmp); 99 100 // TODO: nice-to-have some kind of invariants-checking after reading the parcel data. 101 102 return ::android::NO_ERROR; 103 } 104 105 private: 106 #define AUTO_PARCELABLE_BINDER_MAPPING(FN) \ 107 FN(Byte,int8_t)\ 108 FN(Int32,int32_t)\ 109 FN(Uint32,uint32_t)\ 110 FN(Int64,int64_t)\ 111 FN(Uint64,uint64_t)\ 112 FN(Float,float)\ 113 FN(Double,double)\ 114 FN(Bool,bool)\ 115 FN(CString,const char*)\ 116 FN(String16,const String16&)\ 117 FN(String16,const std::unique_ptr<String16>&)\ 118 FN(StrongBinder,const sp<IBinder>&)\ 119 FN(WeakBinder,const wp<IBinder>&)\ 120 121 template <typename F> writeAnyToParcelAutoParcelable122 static status_t writeAnyToParcel(Parcel* parcel, const F& value) { 123 using namespace android; // NOLINT 124 125 // 'F' is the original type of the field here, so it's safe to use it undecayed. 126 // However, to make matching easier we almost always want to match against the decayed type. 127 using D = std::decay_t<F>; // [const] [volatile] X[&][&] -> X 128 129 if constexpr (std::is_base_of_v<Parcelable, D>) { 130 return value.writeToParcel(parcel); 131 } else if constexpr (std::is_enum_v<D>) { 132 return writeAnyToParcel(parcel, static_cast<std::underlying_type_t<F>>(value)); 133 #define AUTO_PARCELABLE_WRITE_TO_PARCEL(fn_name, type_name) \ 134 } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \ 135 return parcel->write ## fn_name (value); 136 AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_WRITE_TO_PARCEL) 137 } else if constexpr (std::is_same_v<D, std::string>) { 138 return parcel->writeUtf8AsUtf16(value); 139 } else { 140 STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^"); 141 } 142 143 #undef AUTO_PARCELABLE_WRITE_TO_PARCEL 144 } 145 146 template <typename F> readAnyFromParcelAutoParcelable147 static auto readAnyFromParcel(const Parcel* parcel) { 148 // returns pair(status_t, ~F~) 149 using namespace android; 150 151 // Since 'F' is almost always an lvalue reference (due to F=decltype(auto&&), 152 // we should lose the references, and also any consts. 153 using D = std::decay_t<F>; 154 155 D value; 156 status_t result; 157 158 if constexpr (std::is_base_of_v<Parcelable, D>) { 159 status_t result = value.readFromParcel(/*in*/parcel); 160 } else if constexpr (std::is_enum_v<D>) { 161 auto&& [res, val] = readAnyFromParcel<std::underlying_type_t<D>>(parcel); 162 result = res; 163 value = static_cast<D>(val); 164 #define AUTO_PARCELABLE_READ_FROM_PARCEL(fn_name, type_name) \ 165 } else if constexpr (std::is_same_v<D, std::decay_t<type_name>>) { \ 166 result = parcel->read ## fn_name (/*out*/&value); 167 AUTO_PARCELABLE_BINDER_MAPPING(AUTO_PARCELABLE_READ_FROM_PARCEL) 168 } else if constexpr (std::is_same_v<D, std::string>) { 169 result = parcel->readUtf8FromUtf16(/*out*/&value); 170 } else { 171 STATIC_FAIL(D, "Unsupported type: Add more manual type conversions above^^^"); 172 } 173 #undef AUTO_PARCELABLE_READ_FROM_PARCEL 174 175 return std::make_pair(result, std::move(value)); 176 } 177 SelfAutoParcelable178 T* Self() { 179 return static_cast<T*>(this); 180 } SelfAutoParcelable181 const T* Self() const { 182 return static_cast<const T*>(this); 183 } 184 }; 185 186 } // namespace binder 187 } // namespace iorap 188 189 #endif // IORAP_BINDER_AUTO_PARCELABLE_H_ 190