1 /* 2 * Copyright 2016 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 #pragma once 18 19 #include <binder/IInterface.h> 20 #include <binder/Parcel.h> 21 #include <cutils/compiler.h> 22 23 // Set to 1 to enable CallStacks when logging errors 24 #define SI_DUMP_CALLSTACKS 0 25 #if SI_DUMP_CALLSTACKS 26 #include <utils/CallStack.h> 27 #endif 28 29 #include <utils/NativeHandle.h> 30 31 #include <functional> 32 #include <type_traits> 33 34 namespace android { 35 namespace SafeInterface { 36 37 // ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way 38 class ParcelHandler { 39 public: ParcelHandler(const char * logTag)40 explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {} 41 42 // Specializations for types with dedicated handling in Parcel read(const Parcel & parcel,bool * b)43 status_t read(const Parcel& parcel, bool* b) const { 44 return callParcel("readBool", [&]() { return parcel.readBool(b); }); 45 } write(Parcel * parcel,bool b)46 status_t write(Parcel* parcel, bool b) const { 47 return callParcel("writeBool", [&]() { return parcel->writeBool(b); }); 48 } 49 template <typename E> read(const Parcel & parcel,E * e)50 typename std::enable_if<std::is_enum<E>::value, status_t>::type read(const Parcel& parcel, 51 E* e) const { 52 typename std::underlying_type<E>::type u{}; 53 status_t result = read(parcel, &u); 54 *e = static_cast<E>(u); 55 return result; 56 } 57 template <typename E> write(Parcel * parcel,E e)58 typename std::enable_if<std::is_enum<E>::value, status_t>::type write(Parcel* parcel, 59 E e) const { 60 return write(parcel, static_cast<typename std::underlying_type<E>::type>(e)); 61 } 62 template <typename T> read(const Parcel & parcel,T * t)63 typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read( 64 const Parcel& parcel, T* t) const { 65 return callParcel("read(Flattenable)", [&]() { return parcel.read(*t); }); 66 } 67 template <typename T> write(Parcel * parcel,const T & t)68 typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write( 69 Parcel* parcel, const T& t) const { 70 return callParcel("write(Flattenable)", [&]() { return parcel->write(t); }); 71 } 72 template <typename T> read(const Parcel & parcel,sp<T> * t)73 typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read( 74 const Parcel& parcel, sp<T>* t) const { 75 *t = new T{}; 76 return callParcel("read(sp<Flattenable>)", [&]() { return parcel.read(*(t->get())); }); 77 } 78 template <typename T> write(Parcel * parcel,const sp<T> & t)79 typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write( 80 Parcel* parcel, const sp<T>& t) const { 81 return callParcel("write(sp<Flattenable>)", [&]() { return parcel->write(*(t.get())); }); 82 } 83 template <typename T> read(const Parcel & parcel,T * t)84 typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read( 85 const Parcel& parcel, T* t) const { 86 return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); }); 87 } 88 template <typename T> write(Parcel * parcel,const T & t)89 typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write( 90 Parcel* parcel, const T& t) const { 91 return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); }); 92 } 93 template <typename NH> read(const Parcel & parcel,NH * nh)94 typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type read( 95 const Parcel& parcel, NH* nh) { 96 *nh = NativeHandle::create(parcel.readNativeHandle(), true); 97 return NO_ERROR; 98 } 99 template <typename NH> write(Parcel * parcel,const NH & nh)100 typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type write( 101 Parcel* parcel, const NH& nh) { 102 return callParcel("write(sp<NativeHandle>)", 103 [&]() { return parcel->writeNativeHandle(nh->handle()); }); 104 } 105 template <typename T> read(const Parcel & parcel,T * t)106 typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read( 107 const Parcel& parcel, T* t) const { 108 return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); }); 109 } 110 template <typename T> write(Parcel * parcel,const T & t)111 typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write( 112 Parcel* parcel, const T& t) const { 113 return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); }); 114 } read(const Parcel & parcel,String8 * str)115 status_t read(const Parcel& parcel, String8* str) const { 116 return callParcel("readString8", [&]() { return parcel.readString8(str); }); 117 } write(Parcel * parcel,const String8 & str)118 status_t write(Parcel* parcel, const String8& str) const { 119 return callParcel("writeString8", [&]() { return parcel->writeString8(str); }); 120 } 121 template <typename T> read(const Parcel & parcel,sp<T> * pointer)122 typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type read( 123 const Parcel& parcel, sp<T>* pointer) const { 124 return callParcel("readNullableStrongBinder", 125 [&]() { return parcel.readNullableStrongBinder(pointer); }); 126 } 127 template <typename T> write(Parcel * parcel,const sp<T> & pointer)128 typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write( 129 Parcel* parcel, const sp<T>& pointer) const { 130 return callParcel("writeStrongBinder", 131 [&]() { return parcel->writeStrongBinder(pointer); }); 132 } 133 template <typename T> read(const Parcel & parcel,sp<T> * pointer)134 typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type read( 135 const Parcel& parcel, sp<T>* pointer) const { 136 return callParcel("readNullableStrongBinder[IInterface]", 137 [&]() { return parcel.readNullableStrongBinder(pointer); }); 138 } 139 template <typename T> write(Parcel * parcel,const sp<T> & interface)140 typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write( 141 Parcel* parcel, const sp<T>& interface) const { 142 return write(parcel, IInterface::asBinder(interface)); 143 } 144 template <typename T> read(const Parcel & parcel,std::vector<T> * v)145 typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read( 146 const Parcel& parcel, std::vector<T>* v) const { 147 return callParcel("readParcelableVector", [&]() { return parcel.readParcelableVector(v); }); 148 } 149 template <typename T> write(Parcel * parcel,const std::vector<T> & v)150 typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write( 151 Parcel* parcel, const std::vector<T>& v) const { 152 return callParcel("writeParcelableVector", 153 [&]() { return parcel->writeParcelableVector(v); }); 154 } read(const Parcel & parcel,float * f)155 status_t read(const Parcel& parcel, float* f) const { 156 return callParcel("readFloat", [&]() { return parcel.readFloat(f); }); 157 } write(Parcel * parcel,float f)158 status_t write(Parcel* parcel, float f) const { 159 return callParcel("writeFloat", [&]() { return parcel->writeFloat(f); }); 160 } 161 162 // Templates to handle integral types. We use a struct template to require that the called 163 // function exactly matches the signedness and size of the argument (e.g., the argument isn't 164 // silently widened). 165 template <bool isSigned, size_t size, typename I> 166 struct HandleInt; 167 template <typename I> 168 struct HandleInt<true, 4, I> { 169 static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { 170 return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); }); 171 } 172 static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { 173 return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); }); 174 } 175 }; 176 template <typename I> 177 struct HandleInt<false, 4, I> { 178 static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { 179 return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); }); 180 } 181 static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { 182 return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); }); 183 } 184 }; 185 template <typename I> 186 struct HandleInt<true, 8, I> { 187 static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { 188 return handler.callParcel("readInt64", [&]() { return parcel.readInt64(i); }); 189 } 190 static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { 191 return handler.callParcel("writeInt64", [&]() { return parcel->writeInt64(i); }); 192 } 193 }; 194 template <typename I> 195 struct HandleInt<false, 8, I> { 196 static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) { 197 return handler.callParcel("readUint64", [&]() { return parcel.readUint64(i); }); 198 } 199 static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) { 200 return handler.callParcel("writeUint64", [&]() { return parcel->writeUint64(i); }); 201 } 202 }; 203 template <typename I> 204 typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel, 205 I* i) const { 206 return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i); 207 } 208 template <typename I> 209 typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel, 210 I i) const { 211 return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i); 212 } 213 214 private: 215 const char* const mLogTag; 216 217 // Helper to encapsulate error handling while calling the various Parcel methods 218 template <typename Function> 219 status_t callParcel(const char* name, Function f) const { 220 status_t error = f(); 221 if (CC_UNLIKELY(error != NO_ERROR)) { 222 ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error)); 223 #if SI_DUMP_CALLSTACKS 224 CallStack callStack(mLogTag); 225 #endif 226 } 227 return error; 228 } 229 }; 230 231 // Utility struct template which allows us to retrieve the types of the parameters of a member 232 // function pointer 233 template <typename T> 234 struct ParamExtractor; 235 template <typename Class, typename Return, typename... Params> 236 struct ParamExtractor<Return (Class::*)(Params...)> { 237 using ParamTuple = std::tuple<Params...>; 238 }; 239 template <typename Class, typename Return, typename... Params> 240 struct ParamExtractor<Return (Class::*)(Params...) const> { 241 using ParamTuple = std::tuple<Params...>; 242 }; 243 244 } // namespace SafeInterface 245 246 template <typename Interface> 247 class SafeBpInterface : public BpInterface<Interface> { 248 protected: 249 SafeBpInterface(const sp<IBinder>& impl, const char* logTag) 250 : BpInterface<Interface>(impl), mLogTag(logTag) {} 251 ~SafeBpInterface() override = default; 252 253 // callRemote is used to invoke a synchronous procedure call over Binder 254 template <typename Method, typename TagType, typename... Args> 255 status_t callRemote(TagType tag, Args&&... args) const { 256 static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t"); 257 258 // Verify that the arguments are compatible with the parameters 259 using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; 260 static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value, 261 "Invalid argument type"); 262 263 // Write the input arguments to the data Parcel 264 Parcel data; 265 data.writeInterfaceToken(this->getInterfaceDescriptor()); 266 267 status_t error = writeInputs(&data, std::forward<Args>(args)...); 268 if (CC_UNLIKELY(error != NO_ERROR)) { 269 // A message will have been logged by writeInputs 270 return error; 271 } 272 273 // Send the data Parcel to the remote and retrieve the reply parcel 274 Parcel reply; 275 error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply); 276 if (CC_UNLIKELY(error != NO_ERROR)) { 277 ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); 278 #if SI_DUMP_CALLSTACKS 279 CallStack callStack(mLogTag); 280 #endif 281 return error; 282 } 283 284 // Read the outputs from the reply Parcel into the output arguments 285 error = readOutputs(reply, std::forward<Args>(args)...); 286 if (CC_UNLIKELY(error != NO_ERROR)) { 287 // A message will have been logged by readOutputs 288 return error; 289 } 290 291 // Retrieve the result code from the reply Parcel 292 status_t result = NO_ERROR; 293 error = reply.readInt32(&result); 294 if (CC_UNLIKELY(error != NO_ERROR)) { 295 ALOG(LOG_ERROR, mLogTag, "Failed to obtain result"); 296 #if SI_DUMP_CALLSTACKS 297 CallStack callStack(mLogTag); 298 #endif 299 return error; 300 } 301 return result; 302 } 303 304 // callRemoteAsync is used to invoke an asynchronous procedure call over Binder 305 template <typename Method, typename TagType, typename... Args> 306 void callRemoteAsync(TagType tag, Args&&... args) const { 307 static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t"); 308 309 // Verify that the arguments are compatible with the parameters 310 using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; 311 static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value, 312 "Invalid argument type"); 313 314 // Write the input arguments to the data Parcel 315 Parcel data; 316 data.writeInterfaceToken(this->getInterfaceDescriptor()); 317 status_t error = writeInputs(&data, std::forward<Args>(args)...); 318 if (CC_UNLIKELY(error != NO_ERROR)) { 319 // A message will have been logged by writeInputs 320 return; 321 } 322 323 // There will be no data in the reply Parcel since the call is one-way 324 Parcel reply; 325 error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply, 326 IBinder::FLAG_ONEWAY); 327 if (CC_UNLIKELY(error != NO_ERROR)) { 328 ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); 329 #if SI_DUMP_CALLSTACKS 330 CallStack callStack(mLogTag); 331 #endif 332 } 333 } 334 335 private: 336 const char* const mLogTag; 337 338 // This struct provides information on whether the decayed types of the elements at Index in the 339 // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references, 340 // and a few other less common operations) are the same 341 template <size_t Index, typename T, typename U> 342 struct DecayedElementsMatch { 343 private: 344 using FirstT = typename std::tuple_element<Index, T>::type; 345 using DecayedT = typename std::decay<FirstT>::type; 346 using FirstU = typename std::tuple_element<Index, U>::type; 347 using DecayedU = typename std::decay<FirstU>::type; 348 349 public: 350 static constexpr bool value = std::is_same<DecayedT, DecayedU>::value; 351 }; 352 353 // When comparing whether the argument types match the parameter types, we first decay them (see 354 // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are 355 // equivalent enough for our purposes 356 template <typename T, typename U> 357 struct ArgsMatchParams {}; 358 template <typename... Args, typename... Params> 359 struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> { 360 static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments"); 361 static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments"); 362 363 private: 364 template <size_t Index> 365 static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type 366 elementsMatch() { 367 if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) { 368 return false; 369 } 370 return elementsMatch<Index + 1>(); 371 } 372 template <size_t Index> 373 static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type 374 elementsMatch() { 375 return true; 376 } 377 378 public: 379 static constexpr bool value = elementsMatch<0>(); 380 }; 381 382 // Since we assume that pointer arguments are outputs, we can use this template struct to 383 // determine whether or not a given argument is fundamentally a pointer type and thus an output 384 template <typename T> 385 struct IsPointerIfDecayed { 386 private: 387 using Decayed = typename std::decay<T>::type; 388 389 public: 390 static constexpr bool value = std::is_pointer<Decayed>::value; 391 }; 392 393 template <typename T> 394 typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput( 395 Parcel* data, T&& t) const { 396 return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t)); 397 } 398 template <typename T> 399 typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput( 400 Parcel* /*data*/, T&& /*t*/) const { 401 return NO_ERROR; 402 } 403 404 // This method iterates through all of the arguments, writing them to the data Parcel if they 405 // are an input (i.e., if they are not a pointer type) 406 template <typename T, typename... Remaining> 407 status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const { 408 status_t error = writeIfInput(data, std::forward<T>(t)); 409 if (CC_UNLIKELY(error != NO_ERROR)) { 410 // A message will have been logged by writeIfInput 411 return error; 412 } 413 return writeInputs(data, std::forward<Remaining>(remaining)...); 414 } 415 static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; } 416 417 template <typename T> 418 typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput( 419 const Parcel& reply, T&& t) const { 420 return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t)); 421 } 422 template <typename T> 423 static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput( 424 const Parcel& /*reply*/, T&& /*t*/) { 425 return NO_ERROR; 426 } 427 428 // Similar to writeInputs except that it reads output arguments from the reply Parcel 429 template <typename T, typename... Remaining> 430 status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const { 431 status_t error = readIfOutput(reply, std::forward<T>(t)); 432 if (CC_UNLIKELY(error != NO_ERROR)) { 433 // A message will have been logged by readIfOutput 434 return error; 435 } 436 return readOutputs(reply, std::forward<Remaining>(remaining)...); 437 } 438 static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; } 439 }; 440 441 template <typename Interface> 442 class SafeBnInterface : public BnInterface<Interface> { 443 public: 444 explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {} 445 446 protected: 447 template <typename Method> 448 status_t callLocal(const Parcel& data, Parcel* reply, Method method) { 449 CHECK_INTERFACE(this, data, reply); 450 451 // Since we need to both pass inputs into the call as well as retrieve outputs, we create a 452 // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the 453 // outputs. When we ultimately call into the method, we will pass the addresses of the 454 // output arguments instead of their tuple members directly, but the storage will live in 455 // the tuple. 456 using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; 457 typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{}; 458 459 // Read the inputs from the data Parcel into the argument tuple 460 status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); 461 if (CC_UNLIKELY(error != NO_ERROR)) { 462 // A message will have been logged by read 463 return error; 464 } 465 466 // Call the local method 467 status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs); 468 469 // Extract the outputs from the argument tuple and write them into the reply Parcel 470 error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs); 471 if (CC_UNLIKELY(error != NO_ERROR)) { 472 // A message will have been logged by write 473 return error; 474 } 475 476 // Return the result code in the reply Parcel 477 error = reply->writeInt32(result); 478 if (CC_UNLIKELY(error != NO_ERROR)) { 479 ALOG(LOG_ERROR, mLogTag, "Failed to write result"); 480 #if SI_DUMP_CALLSTACKS 481 CallStack callStack(mLogTag); 482 #endif 483 return error; 484 } 485 return NO_ERROR; 486 } 487 488 template <typename Method> 489 status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) { 490 // reply is not actually used by CHECK_INTERFACE 491 CHECK_INTERFACE(this, data, reply); 492 493 // Since we need to both pass inputs into the call as well as retrieve outputs, we create a 494 // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the 495 // outputs. When we ultimately call into the method, we will pass the addresses of the 496 // output arguments instead of their tuple members directly, but the storage will live in 497 // the tuple. 498 using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple; 499 typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{}; 500 501 // Read the inputs from the data Parcel into the argument tuple 502 status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); 503 if (CC_UNLIKELY(error != NO_ERROR)) { 504 // A message will have been logged by read 505 return error; 506 } 507 508 // Call the local method 509 MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs); 510 511 // After calling, there is nothing more to do since asynchronous calls do not return a value 512 // to the caller 513 return NO_ERROR; 514 } 515 516 private: 517 const char* const mLogTag; 518 519 // RemoveFirst strips the first element from a tuple. 520 // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C> 521 template <typename T, typename... Args> 522 struct RemoveFirst; 523 template <typename T, typename... Args> 524 struct RemoveFirst<std::tuple<T, Args...>> { 525 using type = std::tuple<Args...>; 526 }; 527 528 // RawConverter strips a tuple down to its fundamental types, discarding both pointers and 529 // references. This allows us to allocate storage for both input (non-pointer) arguments and 530 // output (pointer) arguments in one tuple. 531 // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B> 532 template <typename Unconverted, typename... Converted> 533 struct RawConverter; 534 template <typename Unconverted, typename... Converted> 535 struct RawConverter<std::tuple<Converted...>, Unconverted> { 536 private: 537 using ElementType = typename std::tuple_element<0, Unconverted>::type; 538 using Decayed = typename std::decay<ElementType>::type; 539 using WithoutPointer = typename std::remove_pointer<Decayed>::type; 540 541 public: 542 using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>, 543 typename RemoveFirst<Unconverted>::type>::type; 544 }; 545 template <typename... Converted> 546 struct RawConverter<std::tuple<Converted...>, std::tuple<>> { 547 using type = std::tuple<Converted...>; 548 }; 549 550 // This provides a simple way to determine whether the indexed element of Args... is a pointer 551 template <size_t I, typename... Args> 552 struct ElementIsPointer { 553 private: 554 using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type; 555 556 public: 557 static constexpr bool value = std::is_pointer<ElementType>::value; 558 }; 559 560 // This class iterates over the parameter types, and if a given parameter is an input 561 // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel 562 template <typename... Params> 563 class InputReader; 564 template <typename... Params> 565 class InputReader<std::tuple<Params...>> { 566 public: 567 explicit InputReader(const char* logTag) : mLogTag(logTag) {} 568 569 // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit 570 // index (starting with 0 here) instead of using recursion and stripping the first element. 571 // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are 572 // instead just using a tuple as a convenient container for variadic types, whereas here we 573 // can't modify the argument tuple without causing unnecessary copies or moves of the data 574 // contained therein. 575 template <typename RawTuple> 576 status_t readInputs(const Parcel& data, RawTuple* args) { 577 return dispatchArg<0>(data, args); 578 } 579 580 private: 581 const char* const mLogTag; 582 583 template <std::size_t I, typename RawTuple> 584 typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput( 585 const Parcel& data, RawTuple* args) { 586 return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args)); 587 } 588 template <std::size_t I, typename RawTuple> 589 typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput( 590 const Parcel& /*data*/, RawTuple* /*args*/) { 591 return NO_ERROR; 592 } 593 594 // Recursively iterate through the arguments 595 template <std::size_t I, typename RawTuple> 596 typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( 597 const Parcel& data, RawTuple* args) { 598 status_t error = readIfInput<I>(data, args); 599 if (CC_UNLIKELY(error != NO_ERROR)) { 600 // A message will have been logged in read 601 return error; 602 } 603 return dispatchArg<I + 1>(data, args); 604 } 605 template <std::size_t I, typename RawTuple> 606 typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg( 607 const Parcel& /*data*/, RawTuple* /*args*/) { 608 return NO_ERROR; 609 } 610 }; 611 612 // getForCall uses the types of the parameters to determine whether a given element of the 613 // argument tuple is an input, which should be passed directly into the call, or an output, for 614 // which its address should be passed into the call 615 template <size_t I, typename RawTuple, typename... Params> 616 static typename std::enable_if< 617 ElementIsPointer<I, Params...>::value, 618 typename std::tuple_element<I, std::tuple<Params...>>::type>::type 619 getForCall(RawTuple* args) { 620 return &std::get<I>(*args); 621 } 622 template <size_t I, typename RawTuple, typename... Params> 623 static typename std::enable_if< 624 !ElementIsPointer<I, Params...>::value, 625 typename std::tuple_element<I, std::tuple<Params...>>::type>::type& 626 getForCall(RawTuple* args) { 627 return std::get<I>(*args); 628 } 629 630 // This template class uses std::index_sequence and parameter pack expansion to call the given 631 // method using the elements of the argument tuple (after those arguments are passed through 632 // getForCall to get addresses instead of values for output arguments) 633 template <typename... Params> 634 struct MethodCaller; 635 template <typename... Params> 636 struct MethodCaller<std::tuple<Params...>> { 637 public: 638 // The calls through these to the helper methods are necessary to generate the 639 // std::index_sequences used to unpack the argument tuple into the method call 640 template <typename Class, typename MemberFunction, typename RawTuple> 641 static status_t call(Class* instance, MemberFunction function, RawTuple* args) { 642 return callHelper(instance, function, args, std::index_sequence_for<Params...>{}); 643 } 644 template <typename Class, typename MemberFunction, typename RawTuple> 645 static void callVoid(Class* instance, MemberFunction function, RawTuple* args) { 646 callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{}); 647 } 648 649 private: 650 template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I> 651 static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args, 652 std::index_sequence<I...> /*unused*/) { 653 return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...); 654 } 655 template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I> 656 static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args, 657 std::index_sequence<I...> /*unused*/) { 658 (instance->*function)(getForCall<I, RawTuple, Params...>(args)...); 659 } 660 }; 661 662 // This class iterates over the parameter types, and if a given parameter is an output 663 // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel 664 template <typename... Params> 665 struct OutputWriter; 666 template <typename... Params> 667 struct OutputWriter<std::tuple<Params...>> { 668 public: 669 explicit OutputWriter(const char* logTag) : mLogTag(logTag) {} 670 671 // See the note on InputReader::readInputs for why this differs from the arguably simpler 672 // RemoveFirst approach in SafeBpInterface 673 template <typename RawTuple> 674 status_t writeOutputs(Parcel* reply, RawTuple* args) { 675 return dispatchArg<0>(reply, args); 676 } 677 678 private: 679 const char* const mLogTag; 680 681 template <std::size_t I, typename RawTuple> 682 typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type 683 writeIfOutput(Parcel* reply, RawTuple* args) { 684 return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args)); 685 } 686 template <std::size_t I, typename RawTuple> 687 typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type 688 writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) { 689 return NO_ERROR; 690 } 691 692 // Recursively iterate through the arguments 693 template <std::size_t I, typename RawTuple> 694 typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( 695 Parcel* reply, RawTuple* args) { 696 status_t error = writeIfOutput<I>(reply, args); 697 if (CC_UNLIKELY(error != NO_ERROR)) { 698 // A message will have been logged in read 699 return error; 700 } 701 return dispatchArg<I + 1>(reply, args); 702 } 703 template <std::size_t I, typename RawTuple> 704 typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg( 705 Parcel* /*reply*/, RawTuple* /*args*/) { 706 return NO_ERROR; 707 } 708 }; 709 }; 710 711 } // namespace android 712