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