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 
    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