blob: 49bee40be530be8c34492389329198f091fb3695 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#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
14namespace android {
15namespace pdx {
16namespace rpc {
17
18#ifdef __clang__
19// Stand-in type to avoid Clang compiler bug. Clang currently has a bug where
20// performing parameter pack expansion for arguments with empty packs causes a
21// compiler crash. Provide a substitute void type and specializations/overloads
22// of CheckArgumentTypes and DispatchRemoteMethod to work around this problem.
23struct Void {};
24
25// Evaluates to true if the method type is <any>(Void), false otherwise.
26template <typename RemoteMethodType>
27using IsVoidMethod = typename std::integral_constant<
28 bool,
29 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 int ret = message.ReplyError(error_code);
125 ALOGE_IF(ret < 0, "RemoteMethodError: Failed to reply to message: %s",
126 strerror(-ret));
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 int ret = message.Reply(return_value);
139 ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s",
140 strerror(-ret));
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 int ret;
152 auto size = message.Write(payload.Data(), payload.Size());
153 if (size < static_cast<decltype(size)>(payload.Size()))
154 ret = message.ReplyError(EIO);
155 else
156 ret = message.Reply(0);
157 ALOGE_IF(ret < 0, "RemoteMethodReturn: Failed to reply to message: %s",
158 strerror(-ret));
159}
160
161// Dispatches a method by deserializing arguments from the given Message, with
162// compile-time interface check. Overload for void return types.
163template <typename RemoteMethodType, typename Class, typename... Args,
164 typename = EnableIfNotVoidMethod<RemoteMethodType>>
165void DispatchRemoteMethod(Class& instance,
166 void (Class::*method)(Message&, Args...),
167 Message& message,
168 std::size_t max_capacity = InitialBufferCapacity) {
169 using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
170 rpc::ServicePayload<ReceiveBuffer> payload(message);
171 payload.Resize(max_capacity);
172
173 auto size = message.Read(payload.Data(), payload.Size());
174 if (size < 0) {
175 RemoteMethodError(message, -size);
176 return;
177 }
178
179 payload.Resize(size);
180
181 ErrorType error;
182 auto decoder = MakeArgumentDecoder<Signature>(&payload);
183 auto arguments = decoder.DecodeArguments(&error);
184 if (error) {
185 RemoteMethodError(message, EIO);
186 return;
187 }
188
189 UnpackArguments<Class, Signature>(instance, method, message, arguments)
190 .Invoke();
191 // Return to the caller unless the message was moved.
192 if (message)
193 RemoteMethodReturn<RemoteMethodType>(message, 0);
194}
195
196// Dispatches a method by deserializing arguments from the given Message, with
197// compile-time interface check. Overload for int return types.
198template <typename RemoteMethodType, typename Class, typename... Args,
199 typename = EnableIfNotVoidMethod<RemoteMethodType>>
200void DispatchRemoteMethod(Class& instance,
201 int (Class::*method)(Message&, Args...),
202 Message& message,
203 std::size_t max_capacity = InitialBufferCapacity) {
204 using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
205 rpc::ServicePayload<ReceiveBuffer> payload(message);
206 payload.Resize(max_capacity);
207
208 auto size = message.Read(payload.Data(), payload.Size());
209 if (size < 0) {
210 RemoteMethodError(message, -size);
211 return;
212 }
213
214 payload.Resize(size);
215
216 ErrorType error;
217 auto decoder = MakeArgumentDecoder<Signature>(&payload);
218 auto arguments = decoder.DecodeArguments(&error);
219 if (error) {
220 RemoteMethodError(message, EIO);
221 return;
222 }
223
224 auto return_value =
225 UnpackArguments<Class, Signature>(instance, method, message, arguments)
226 .Invoke();
227 // Return the value to the caller unless the message was moved.
228 if (message)
229 RemoteMethodReturn<RemoteMethodType>(message, return_value);
230}
231
232// Dispatches a method by deserializing arguments from the given Message, with
233// compile-time interface check. Overload for FileHandle return types.
234template <typename RemoteMethodType, FileHandleMode Mode, typename Class,
235 typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
236void DispatchRemoteMethod(Class& instance,
237 FileHandle<Mode> (Class::*method)(Message&, Args...),
238 Message& message,
239 std::size_t max_capacity = InitialBufferCapacity) {
240 using Signature =
241 typename RemoteMethodType::template RewriteSignature<FileHandle<Mode>,
242 Args...>;
243 rpc::ServicePayload<ReceiveBuffer> payload(message);
244 payload.Resize(max_capacity);
245
246 auto size = message.Read(payload.Data(), payload.Size());
247 if (size < 0) {
248 RemoteMethodError(message, -size);
249 return;
250 }
251
252 payload.Resize(size);
253
254 ErrorType error;
255 auto decoder = MakeArgumentDecoder<Signature>(&payload);
256 auto arguments = decoder.DecodeArguments(&error);
257 if (error) {
258 RemoteMethodError(message, EIO);
259 return;
260 }
261
262 auto return_value =
263 UnpackArguments<Class, Signature>(instance, method, message, arguments)
264 .Invoke();
265 // Return the value to the caller unless the message was moved.
266 if (message)
267 RemoteMethodReturn<RemoteMethodType>(message, return_value);
268}
269
270// Dispatches a method by deserializing arguments from the given Message, with
271// compile-time interface check. Overload for ChannelHandle return types.
272template <typename RemoteMethodType, ChannelHandleMode Mode, typename Class,
273 typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
274void DispatchRemoteMethod(
275 Class& instance, ChannelHandle<Mode> (Class::*method)(Message&, Args...),
276 Message& message, std::size_t max_capacity = InitialBufferCapacity) {
277 using Signature = typename RemoteMethodType::template RewriteArgs<Args...>;
278 rpc::ServicePayload<ReceiveBuffer> payload(message);
279 payload.Resize(max_capacity);
280
281 auto size = message.Read(payload.Data(), payload.Size());
282 if (size < 0) {
283 RemoteMethodError(message, -size);
284 return;
285 }
286
287 payload.Resize(size);
288
289 ErrorType error;
290 auto decoder = MakeArgumentDecoder<Signature>(&payload);
291 auto arguments = decoder.DecodeArguments(&error);
292 if (error) {
293 RemoteMethodError(message, EIO);
294 return;
295 }
296
297 auto return_value =
298 UnpackArguments<Class, Signature>(instance, method, message, arguments)
299 .Invoke();
300 // Return the value to the caller unless the message was moved.
301 if (message)
302 RemoteMethodReturn<RemoteMethodType>(message, return_value);
303}
304
305// Dispatches a method by deserializing arguments from the given Message, with
306// compile-time interface signature check. Overload for generic return types.
307template <typename RemoteMethodType, typename Class, typename Return,
308 typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
309void DispatchRemoteMethod(Class& instance,
310 Return (Class::*method)(Message&, Args...),
311 Message& message,
312 std::size_t max_capacity = InitialBufferCapacity) {
313 using Signature =
314 typename RemoteMethodType::template RewriteSignature<Return, Args...>;
315 rpc::ServicePayload<ReceiveBuffer> payload(message);
316 payload.Resize(max_capacity);
317
318 auto size = message.Read(payload.Data(), payload.Size());
319 if (size < 0) {
320 RemoteMethodError(message, -size);
321 return;
322 }
323
324 payload.Resize(size);
325
326 ErrorType error;
327 auto decoder = MakeArgumentDecoder<Signature>(&payload);
328 auto arguments = decoder.DecodeArguments(&error);
329 if (error) {
330 RemoteMethodError(message, EIO);
331 return;
332 }
333
334 auto return_value =
335 UnpackArguments<Class, Signature>(instance, method, message, arguments)
336 .Invoke();
337 // Return the value to the caller unless the message was moved.
338 if (message)
339 RemoteMethodReturn<RemoteMethodType>(message, return_value);
340}
341
342#ifdef __clang__
343// Overloads to handle Void argument type without exploding clang.
344
345// Overload for void return type.
346template <typename RemoteMethodType, typename Class,
347 typename = EnableIfVoidMethod<RemoteMethodType>>
348void DispatchRemoteMethod(Class& instance, void (Class::*method)(Message&),
349 Message& message) {
350 (instance.*method)(message);
351 // Return to the caller unless the message was moved.
352 if (message)
353 RemoteMethodReturn<RemoteMethodType>(message, 0);
354}
355
356// Overload for int return type.
357template <typename RemoteMethodType, typename Class,
358 typename = EnableIfVoidMethod<RemoteMethodType>>
359void DispatchRemoteMethod(Class& instance, int (Class::*method)(Message&),
360 Message& message) {
361 const int return_value = (instance.*method)(message);
362 // Return the value to the caller unless the message was moved.
363 if (message)
364 RemoteMethodReturn<RemoteMethodType>(message, return_value);
365}
366
367// Overload for FileHandle return type.
368template <typename RemoteMethodType, typename Class, FileHandleMode Mode,
369 typename = EnableIfVoidMethod<RemoteMethodType>>
370void DispatchRemoteMethod(Class& instance,
371 FileHandle<Mode> (Class::*method)(Message&),
372 Message& message) {
373 FileHandle<Mode> return_value = (instance.*method)(message);
374 // Return the value to the caller unless the message was moved.
375 if (message)
376 RemoteMethodReturn<RemoteMethodType>(message, return_value);
377}
378
379// Overload for ChannelHandle return types.
380template <typename RemoteMethodType, typename Class, ChannelHandleMode Mode,
381 typename = EnableIfVoidMethod<RemoteMethodType>>
382void DispatchRemoteMethod(Class& instance,
383 ChannelHandle<Mode> (Class::*method)(Message&),
384 Message& message) {
385 ChannelHandle<Mode> return_value = (instance.*method)(message);
386 // Return the value to the caller unless the message was moved.
387 if (message)
388 RemoteMethodReturn<RemoteMethodType>(message, return_value);
389}
390
391// Overload for generic return type.
392template <typename RemoteMethodType, typename Class, typename Return,
393 typename = EnableIfVoidMethod<RemoteMethodType>>
394void DispatchRemoteMethod(Class& instance, Return (Class::*method)(Message&),
395 Message& message) {
396 auto return_value = (instance.*method)(message);
397 // Return the value to the caller unless the message was moved.
398 if (message)
399 RemoteMethodReturn<RemoteMethodType>(message, return_value);
400}
401#endif
402
403} // namespace rpc
404
405// Definitions for template methods declared in pdx/client.h.
406
407template <int Opcode, typename T>
408struct CheckArgumentTypes;
409
410template <int Opcode, typename Return, typename... Args>
411struct CheckArgumentTypes<Opcode, Return(Args...)> {
412 template <typename R>
413 static typename rpc::EnableIfDirectReturn<R, Status<R>> Invoke(Client& client,
414 Args... args) {
415 Transaction trans{client};
416 rpc::ClientPayload<rpc::SendBuffer> payload{trans};
417 rpc::MakeArgumentEncoder<Return(Args...)>(&payload).EncodeArguments(
418 std::forward<Args>(args)...);
419 return trans.Send<R>(Opcode, payload.Data(), payload.Size(), nullptr, 0);
420 }
421
422 template <typename R>
423 static typename rpc::EnableIfNotDirectReturn<R, Status<R>> Invoke(
424 Client& client, Args... args) {
425 Transaction trans{client};
426
427 rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
428 rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
429 .EncodeArguments(std::forward<Args>(args)...);
430
431 rpc::ClientPayload<rpc::ReplyBuffer> reply_payload{trans};
432 reply_payload.Resize(reply_payload.Capacity());
433
434 Status<R> result;
435 auto status =
436 trans.Send<void>(Opcode, send_payload.Data(), send_payload.Size(),
437 reply_payload.Data(), reply_payload.Size());
438 if (!status) {
439 result.SetError(status.error());
440 } else {
441 R return_value;
442 rpc::ErrorType error =
443 rpc::MakeArgumentDecoder<Return(Args...)>(&reply_payload)
444 .DecodeReturn(&return_value);
445
446 switch (error.error_code()) {
447 case rpc::ErrorCode::NO_ERROR:
448 result.SetValue(std::move(return_value));
449 break;
450
451 // This error is returned when ArrayWrapper/StringWrapper is too
452 // small to receive the payload.
453 case rpc::ErrorCode::INSUFFICIENT_DESTINATION_SIZE:
454 result.SetError(ENOBUFS);
455 break;
456
457 default:
458 result.SetError(EIO);
459 break;
460 }
461 }
462 return result;
463 }
464
465 template <typename R>
466 static typename rpc::EnableIfDirectReturn<R, Status<void>> InvokeInPlace(
467 Client& client, R* return_value, Args... args) {
468 Transaction trans{client};
469
470 rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
471 rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
472 .EncodeArguments(std::forward<Args>(args)...);
473
474 Status<void> result;
475 auto status = trans.Send<R>(Opcode, send_payload.Data(),
476 send_payload.Size(), nullptr, 0);
477 if (status) {
478 *return_value = status.take();
479 result.SetValue();
480 } else {
481 result.SetError(status.error());
482 }
483 return result;
484 }
485
486 template <typename R>
487 static typename rpc::EnableIfNotDirectReturn<R, Status<void>> InvokeInPlace(
488 Client& client, R* return_value, Args... args) {
489 Transaction trans{client};
490
491 rpc::ClientPayload<rpc::SendBuffer> send_payload{trans};
492 rpc::MakeArgumentEncoder<Return(Args...)>(&send_payload)
493 .EncodeArguments(std::forward<Args>(args)...);
494
495 rpc::ClientPayload<rpc::ReplyBuffer> reply_payload{trans};
496 reply_payload.Resize(reply_payload.Capacity());
497
498 auto result =
499 trans.Send<void>(Opcode, send_payload.Data(), send_payload.Size(),
500 reply_payload.Data(), reply_payload.Size());
501 if (result) {
502 rpc::ErrorType error =
503 rpc::MakeArgumentDecoder<Return(Args...)>(&reply_payload)
504 .DecodeReturn(return_value);
505
506 switch (error.error_code()) {
507 case rpc::ErrorCode::NO_ERROR:
508 result.SetValue();
509 break;
510
511 // This error is returned when ArrayWrapper/StringWrapper is too
512 // small to receive the payload.
513 case rpc::ErrorCode::INSUFFICIENT_DESTINATION_SIZE:
514 result.SetError(ENOBUFS);
515 break;
516
517 default:
518 result.SetError(EIO);
519 break;
520 }
521 }
522 return result;
523 }
524};
525
526// Invokes the remote method with opcode and signature described by
527// |RemoteMethodType|.
528template <typename RemoteMethodType, typename... Args>
529Status<typename RemoteMethodType::Return> Client::InvokeRemoteMethod(
530 Args&&... args) {
531 return CheckArgumentTypes<
532 RemoteMethodType::Opcode,
533 typename RemoteMethodType::template RewriteArgs<Args...>>::
534 template Invoke<typename RemoteMethodType::Return>(
535 *this, std::forward<Args>(args)...);
536}
537
538template <typename RemoteMethodType, typename Return, typename... Args>
539Status<void> Client::InvokeRemoteMethodInPlace(Return* return_value,
540 Args&&... args) {
541 return CheckArgumentTypes<
542 RemoteMethodType::Opcode,
543 typename RemoteMethodType::template RewriteSignature<Return, Args...>>::
544 template InvokeInPlace(*this, return_value, std::forward<Args>(args)...);
545}
546
547} // namespace pdx
548} // namespace android
549
550#endif // ANDROID_PDX_RPC_REMOTE_METHOD_H_