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