• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace android {
16 namespace pdx {
17 namespace 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.
24 struct Void {};
25 
26 // Evaluates to true if the method type is <any>(Void), false otherwise.
27 template <typename RemoteMethodType>
28 using 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).
34 template <typename RemoteMethodType>
35 using EnableIfVoidMethod =
36     typename std::enable_if<IsVoidMethod<RemoteMethodType>::value>::type;
37 
38 // Utility to determine if a method is not of type <any>(Void).
39 template <typename RemoteMethodType>
40 using 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.
46 using Void = void;
47 template <typename RemoteMethodType>
48 using EnableIfVoidMethod = void;
49 template <typename RemoteMethodType>
50 using 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.
56 template <typename T>
57 struct IsDirectReturn : std::false_type {};
58 
59 template <>
60 struct IsDirectReturn<void> : std::true_type {};
61 
62 template <>
63 struct IsDirectReturn<int> : std::true_type {};
64 
65 template <>
66 struct IsDirectReturn<LocalHandle> : std::true_type {};
67 
68 template <>
69 struct IsDirectReturn<LocalChannelHandle> : std::true_type {};
70 
71 template <typename Return, typename Type = void>
72 using EnableIfDirectReturn =
73     typename std::enable_if<IsDirectReturn<Return>::value, Type>::type;
74 
75 template <typename Return, typename Type = void>
76 using 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.
80 template <typename Class, typename T>
81 class UnpackArguments;
82 
83 // Utility class to invoke a method with arguments packed in a tuple.
84 template <typename Class, typename Return, typename... Args>
85 class 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.
123 inline 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.
135 template <typename RemoteMethodType, typename Return>
136 EnableIfDirectReturn<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.
144 template <typename RemoteMethodType, typename Return>
145 EnableIfNotDirectReturn<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.
158 template <typename RemoteMethodType>
159 void 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>.
168 template <typename RemoteMethodType, typename Return>
169 void 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.
178 template <typename RemoteMethodType, typename Class, typename... Args,
179           typename = EnableIfNotVoidMethod<RemoteMethodType>>
180 void 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.
213 template <typename RemoteMethodType, typename Class, typename Return,
214           typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
215 void 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.
250 template <typename RemoteMethodType, typename Class, typename Return,
251           typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
252 void 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.
292 template <typename RemoteMethodType, typename Class,
293           typename = EnableIfVoidMethod<RemoteMethodType>>
294 void 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.
303 template <typename RemoteMethodType, typename Class, typename Return,
304           typename = EnableIfVoidMethod<RemoteMethodType>>
305 void 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.
314 template <typename RemoteMethodType, typename Class, typename Return,
315           typename = EnableIfVoidMethod<RemoteMethodType>>
316 void 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 
330 template <int Opcode, typename T>
331 struct CheckArgumentTypes;
332 
333 template <int Opcode, typename Return, typename... Args>
334 struct 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|.
451 template <typename RemoteMethodType, typename... Args>
452 Status<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 
461 template <typename RemoteMethodType, typename Return, typename... Args>
462 Status<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