1#ifndef ANDROID_PDX_RPC_REMOTE_METHOD_H_
2#define ANDROID_PDX_RPC_REMOTE_METHOD_H_
3
4#include <tuple>
5#include <type_traits>
6
7#include <pdx/client.h>
8#include <pdx/rpc/argument_encoder.h>
9#include <pdx/rpc/message_buffer.h>
10#include <pdx/rpc/payload.h>
11#include <pdx/rpc/remote_method_type.h>
12#include <pdx/service.h>
13#include <pdx/status.h>
14
15namespace android {
16namespace pdx {
17namespace rpc {
18
19#ifdef __clang__
20// Stand-in type to avoid Clang compiler bug. Clang currently has a bug where
21// performing parameter pack expansion for arguments with empty packs causes a
22// compiler crash. Provide a substitute void type and specializations/overloads
23// of CheckArgumentTypes and DispatchRemoteMethod to work around this problem.
24struct Void {};
25
26// Evaluates to true if the method type is <any>(Void), false otherwise.
27template <typename RemoteMethodType>
28using IsVoidMethod = typename std::integral_constant<
29    bool, RemoteMethodType::Traits::Arity == 1 &&
30              std::is_same<typename RemoteMethodType::Traits::template Arg<0>,
31                           Void>::value>;
32
33// Utility to determine if a method is of type <any>(Void).
34template <typename RemoteMethodType>
35using EnableIfVoidMethod =
36    typename std::enable_if<IsVoidMethod<RemoteMethodType>::value>::type;
37
38// Utility to determine if a method is not of type <any>(Void).
39template <typename RemoteMethodType>
40using EnableIfNotVoidMethod =
41    typename std::enable_if<!IsVoidMethod<RemoteMethodType>::value>::type;
42
43#else
44// GCC works fine with void argument types, always enable the regular
45// implementation of DispatchRemoteMethod.
46using Void = void;
47template <typename RemoteMethodType>
48using EnableIfVoidMethod = void;
49template <typename RemoteMethodType>
50using EnableIfNotVoidMethod = void;
51#endif
52
53// Helper type trait to specialize InvokeRemoteMethods for return types that
54// can be obtained directly from Transaction::Send<T>() without deserializing
55// reply payload.
56template <typename T>
57struct IsDirectReturn : std::false_type {};
58
59template <>
60struct IsDirectReturn<void> : std::true_type {};
61
62template <>
63struct IsDirectReturn<int> : std::true_type {};
64
65template <>
66struct IsDirectReturn<LocalHandle> : std::true_type {};
67
68template <>
69struct IsDirectReturn<LocalChannelHandle> : std::true_type {};
70
71template <typename Return, typename Type = void>
72using EnableIfDirectReturn =
73    typename std::enable_if<IsDirectReturn<Return>::value, Type>::type;
74
75template <typename Return, typename Type = void>
76using EnableIfNotDirectReturn =
77    typename std::enable_if<!IsDirectReturn<Return>::value, Type>::type;
78
79// Utility class to invoke a method with arguments packed in a tuple.
80template <typename Class, typename T>
81class UnpackArguments;
82
83// Utility class to invoke a method with arguments packed in a tuple.
84template <typename Class, typename Return, typename... Args>
85class UnpackArguments<Class, Return(Args...)> {
86 public:
87  using ArgsTupleType = std::tuple<typename std::decay<Args>::type...>;
88  using MethodType = Return (Class::*)(Message&, Args...);
89
90  UnpackArguments(Class& instance, MethodType method, Message& message,
91                  ArgsTupleType& parameters)
92      : instance_(instance),
93        method_(method),
94        message_(message),
95        parameters_(parameters) {}
96
97  // Invokes method_ on intance_ with the packed arguments from parameters_.
98  Return Invoke() {
99    constexpr auto Arity = sizeof...(Args);
100    return static_cast<Return>(InvokeHelper(MakeIndexSequence<Arity>{}));
101  }
102
103 private:
104  Class& instance_;
105  MethodType method_;
106  Message& message_;
107  ArgsTupleType& parameters_;
108
109  template <std::size_t... Index>
110  Return InvokeHelper(IndexSequence<Index...>) {
111    return static_cast<Return>((instance_.*method_)(
112        message_,
113        std::get<Index>(std::forward<ArgsTupleType>(parameters_))...));
114  }
115
116  UnpackArguments(const UnpackArguments&) = delete;
117  void operator=(const UnpackArguments&) = delete;
118};
119
120// Returns an error code from a remote method to the client. May be called
121// either during dispatch of the remote method handler or at a later time if the
122// message is moved for delayed response.
123inline void RemoteMethodError(Message& message, int error_code) {
124  const auto status = message.ReplyError(error_code);
125  ALOGE_IF(!status, "RemoteMethodError: Failed to reply to message: %s",
126           status.GetErrorMessage().c_str());
127}
128
129// Returns a value from a remote method to the client. The usual method to
130// return a value during dispatch of a remote method is to simply use a return
131// statement in the handler. If the message is moved however, these methods may
132// be used to return a value at a later time, outside of initial dispatch.
133
134// Overload for direct return types.
135template <typename RemoteMethodType, typename Return>
136EnableIfDirectReturn<typename RemoteMethodType::Return> RemoteMethodReturn(
137    Message& message, const Return& return_value) {
138  const auto status = message.Reply(return_value);
139  ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s",
140           status.GetErrorMessage().c_str());
141}
142
143// Overload for non-direct return types.
144template <typename RemoteMethodType, typename Return>
145EnableIfNotDirectReturn<typename RemoteMethodType::Return> RemoteMethodReturn(
146    Message& message, const Return& return_value) {
147  using Signature = typename RemoteMethodType::template RewriteReturn<Return>;
148  rpc::ServicePayload<ReplyBuffer> payload(message);
149  MakeArgumentEncoder<Signature>(&payload).EncodeReturn(return_value);
150
151  auto ret = message.WriteAll(payload.Data(), payload.Size());
152  auto status = message.Reply(ret);
153  ALOGE_IF(!status, "RemoteMethodReturn: Failed to reply to message: %s",
154           status.GetErrorMessage().c_str());
155}
156
157// Overload for Status<void> return types.
158template <typename RemoteMethodType>
159void RemoteMethodReturn(Message& message, const Status<void>& return_value) {
160  if (return_value)
161    RemoteMethodReturn<RemoteMethodType>(message, 0);
162  else
163    RemoteMethodError(message, return_value.error());
164}
165
166// Overload for Status<T> return types. This overload forwards the underlying
167// value or error within the Status<T>.
168template <typename RemoteMethodType, typename Return>
169void RemoteMethodReturn(Message& message, const Status<Return>& return_value) {
170  if (return_value)
171    RemoteMethodReturn<RemoteMethodType, Return>(message, return_value.get());
172  else
173    RemoteMethodError(message, return_value.error());
174}
175
176// Dispatches a method by deserializing arguments from the given Message, with
177// compile-time interface check. Overload for void return types.
178template <typename RemoteMethodType, typename Class, typename... Args,
179          typename = EnableIfNotVoidMethod<RemoteMethodType>>
180void DispatchRemoteMethod(Class& instance,
181                          void (Class::*method)(Message&, Args...),
182                          Message& message,
183                          std::size_t max_capacity = InitialBufferCapacity) {
184  using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
185  rpc::ServicePayload<ReceiveBuffer> payload(message);
186  payload.Resize(max_capacity);
187
188  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
189  if (!read_status) {
190    RemoteMethodError(message, read_status.error());
191    return;
192  }
193
194  payload.Resize(read_status.get());
195
196  ErrorType error;
197  auto decoder = MakeArgumentDecoder<Signature>(&payload);
198  auto arguments = decoder.DecodeArguments(&error);
199  if (error) {
200    RemoteMethodError(message, EIO);
201    return;
202  }
203
204  UnpackArguments<Class, Signature>(instance, method, message, arguments)
205      .Invoke();
206  // Return to the caller unless the message was moved.
207  if (message)
208    RemoteMethodReturn<RemoteMethodType>(message, 0);
209}
210
211// Dispatches a method by deserializing arguments from the given Message, with
212// compile-time interface signature check. Overload for generic return types.
213template <typename RemoteMethodType, typename Class, typename Return,
214          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
215void DispatchRemoteMethod(Class& instance,
216                          Return (Class::*method)(Message&, Args...),
217                          Message& message,
218                          std::size_t max_capacity = InitialBufferCapacity) {
219  using Signature =
220      typename RemoteMethodType::template RewriteSignature<Return, Args...>;
221  rpc::ServicePayload<ReceiveBuffer> payload(message);
222  payload.Resize(max_capacity);
223
224  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
225  if (!read_status) {
226    RemoteMethodError(message, read_status.error());
227    return;
228  }
229
230  payload.Resize(read_status.get());
231
232  ErrorType error;
233  auto decoder = MakeArgumentDecoder<Signature>(&payload);
234  auto arguments = decoder.DecodeArguments(&error);
235  if (error) {
236    RemoteMethodError(message, EIO);
237    return;
238  }
239
240  auto return_value =
241      UnpackArguments<Class, Signature>(instance, method, message, arguments)
242          .Invoke();
243  // Return the value to the caller unless the message was moved.
244  if (message)
245    RemoteMethodReturn<RemoteMethodType>(message, return_value);
246}
247
248// Dispatches a method by deserializing arguments from the given Message, with
249// compile-time interface signature check. Overload for Status<T> return types.
250template <typename RemoteMethodType, typename Class, typename Return,
251          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
252void DispatchRemoteMethod(Class& instance,
253                          Status<Return> (Class::*method)(Message&, Args...),
254                          Message& message,
255                          std::size_t max_capacity = InitialBufferCapacity) {
256  using Signature =
257      typename RemoteMethodType::template RewriteSignature<Return, Args...>;
258  using InvokeSignature =
259      typename RemoteMethodType::template RewriteSignatureWrapReturn<
260          Status, Return, Args...>;
261  rpc::ServicePayload<ReceiveBuffer> payload(message);
262  payload.Resize(max_capacity);
263
264  Status<size_t> read_status = message.Read(payload.Data(), payload.Size());
265  if (!read_status) {
266    RemoteMethodError(message, read_status.error());
267    return;
268  }
269
270  payload.Resize(read_status.get());
271
272  ErrorType error;
273  auto decoder = MakeArgumentDecoder<Signature>(&payload);
274  auto arguments = decoder.DecodeArguments(&error);
275  if (error) {
276    RemoteMethodError(message, EIO);
277    return;
278  }
279
280  auto return_value = UnpackArguments<Class, InvokeSignature>(
281                          instance, method, message, arguments)
282                          .Invoke();
283  // Return the value to the caller unless the message was moved.
284  if (message)
285    RemoteMethodReturn<RemoteMethodType>(message, return_value);
286}
287
288#ifdef __clang__
289// Overloads to handle Void argument type without exploding clang.
290
291// Overload for void return type.
292template <typename RemoteMethodType, typename Class,
293          typename = EnableIfVoidMethod<RemoteMethodType>>
294void DispatchRemoteMethod(Class& instance, void (Class::*method)(Message&),
295                          Message& message) {
296  (instance.*method)(message);
297  // Return to the caller unless the message was moved.
298  if (message)
299    RemoteMethodReturn<RemoteMethodType>(message, 0);
300}
301
302// Overload for generic return type.
303template <typename RemoteMethodType, typename Class, typename Return,
304          typename = EnableIfVoidMethod<RemoteMethodType>>
305void DispatchRemoteMethod(Class& instance, Return (Class::*method)(Message&),
306                          Message& message) {
307  auto return_value = (instance.*method)(message);
308  // Return the value to the caller unless the message was moved.
309  if (message)
310    RemoteMethodReturn<RemoteMethodType>(message, return_value);
311}
312
313// Overload for Status<T> return type.
314template <typename RemoteMethodType, typename Class, typename Return,
315          typename = EnableIfVoidMethod<RemoteMethodType>>
316void DispatchRemoteMethod(Class& instance,
317                          Status<Return> (Class::*method)(Message&),
318                          Message& message) {
319  auto return_value = (instance.*method)(message);
320  // Return the value to the caller unless the message was moved.
321  if (message)
322    RemoteMethodReturn<RemoteMethodType>(message, return_value);
323}
324#endif
325
326}  // namespace rpc
327
328// Definitions for template methods declared in pdx/client.h.
329
330template <int Opcode, typename T>
331struct CheckArgumentTypes;
332
333template <int Opcode, typename Return, typename... Args>
334struct CheckArgumentTypes<Opcode, Return(Args...)> {
335  template <typename R>
336  static typename rpc::EnableIfDirectReturn<R, Status<R>> Invoke(Client& client,
337                                                                 Args... args) {
338    Transaction trans{client};
339    rpc::ClientPayload<rpc::SendBuffer> payload{trans};
340    rpc::MakeArgumentEncoder<Return(Args...)>(&payload).EncodeArguments(
341        std::forward<Args>(args)...);
342    return trans.Send<R>(Opcode, payload.Data(), payload.Size(), nullptr, 0);
343  }
344
345  template <typename R>
346  static typename rpc::EnableIfNotDirectReturn<R, Status<R>> Invoke(
347      Client& client, Args... args) {
348    Transaction trans{client};
349
350    rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
351    rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
352        .EncodeArguments(std::forward<Args>(args)...);
353
354    rpc::ClientPayload<rpc::ReplyBuffer> reply_payload{trans};
355    reply_payload.Resize(reply_payload.Capacity());
356
357    Status<R> result;
358    auto status =
359        trans.Send<void>(Opcode, send_payload.Data(), send_payload.Size(),
360                         reply_payload.Data(), reply_payload.Size());
361    if (!status) {
362      result.SetError(status.error());
363    } else {
364      R return_value;
365      rpc::ErrorType error =
366          rpc::MakeArgumentDecoder<Return(Args...)>(&reply_payload)
367              .DecodeReturn(&return_value);
368
369      switch (error.error_code()) {
370        case rpc::ErrorCode::NO_ERROR:
371          result.SetValue(std::move(return_value));
372          break;
373
374        // This error is returned when ArrayWrapper/StringWrapper is too
375        // small to receive the payload.
376        case rpc::ErrorCode::INSUFFICIENT_DESTINATION_SIZE:
377          result.SetError(ENOBUFS);
378          break;
379
380        default:
381          result.SetError(EIO);
382          break;
383      }
384    }
385    return result;
386  }
387
388  template <typename R>
389  static typename rpc::EnableIfDirectReturn<R, Status<void>> InvokeInPlace(
390      Client& client, R* return_value, Args... args) {
391    Transaction trans{client};
392
393    rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
394    rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
395        .EncodeArguments(std::forward<Args>(args)...);
396
397    Status<void> result;
398    auto status = trans.Send<R>(Opcode, send_payload.Data(),
399                                send_payload.Size(), nullptr, 0);
400    if (status) {
401      *return_value = status.take();
402      result.SetValue();
403    } else {
404      result.SetError(status.error());
405    }
406    return result;
407  }
408
409  template <typename R>
410  static typename rpc::EnableIfNotDirectReturn<R, Status<void>> InvokeInPlace(
411      Client& client, R* return_value, Args... args) {
412    Transaction trans{client};
413
414    rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
415    rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
416        .EncodeArguments(std::forward<Args>(args)...);
417
418    rpc::ClientPayload<rpc::ReplyBuffer> reply_payload{trans};
419    reply_payload.Resize(reply_payload.Capacity());
420
421    auto result =
422        trans.Send<void>(Opcode, send_payload.Data(), send_payload.Size(),
423                         reply_payload.Data(), reply_payload.Size());
424    if (result) {
425      rpc::ErrorType error =
426          rpc::MakeArgumentDecoder<Return(Args...)>(&reply_payload)
427              .DecodeReturn(return_value);
428
429      switch (error.error_code()) {
430        case rpc::ErrorCode::NO_ERROR:
431          result.SetValue();
432          break;
433
434        // This error is returned when ArrayWrapper/StringWrapper is too
435        // small to receive the payload.
436        case rpc::ErrorCode::INSUFFICIENT_DESTINATION_SIZE:
437          result.SetError(ENOBUFS);
438          break;
439
440        default:
441          result.SetError(EIO);
442          break;
443      }
444    }
445    return result;
446  }
447};
448
449// Invokes the remote method with opcode and signature described by
450// |RemoteMethodType|.
451template <typename RemoteMethodType, typename... Args>
452Status<typename RemoteMethodType::Return> Client::InvokeRemoteMethod(
453    Args&&... args) {
454  return CheckArgumentTypes<
455      RemoteMethodType::Opcode,
456      typename RemoteMethodType::template RewriteArgs<Args...>>::
457      template Invoke<typename RemoteMethodType::Return>(
458          *this, std::forward<Args>(args)...);
459}
460
461template <typename RemoteMethodType, typename Return, typename... Args>
462Status<void> Client::InvokeRemoteMethodInPlace(Return* return_value,
463                                               Args&&... args) {
464  return CheckArgumentTypes<
465      RemoteMethodType::Opcode,
466      typename RemoteMethodType::template RewriteSignature<Return, Args...>>::
467      template InvokeInPlace(*this, return_value, std::forward<Args>(args)...);
468}
469
470}  // namespace pdx
471}  // namespace android
472
473#endif  // ANDROID_PDX_RPC_REMOTE_METHOD_H_
474