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