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