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