Home | History | Annotate | Download | only in binder
      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:
     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     template <typename T>
    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>
    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     status_t read(const Parcel& parcel, float* f) const {
    156         return callParcel("readFloat", [&]() { return parcel.readFloat(f); });
    157     }
    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