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