libpdx: Add support for Status<T> return type from message handlers.

Add support for returning Status<T> from a message handler for a
remote method protocol with return type T. This greatly simplifies
error reporting logic in message handler methods.

Bug: None
Test: mm -j30; tests added to libpdx_uds in a follow up CL
Change-Id: Ib84e1ddc1f1c6a6d57b35ffada06f94a28e8e0cc
diff --git a/libs/vr/libpdx/private/pdx/rpc/function_traits.h b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
index 5fdad72..7641b0a 100644
--- a/libs/vr/libpdx/private/pdx/rpc/function_traits.h
+++ b/libs/vr/libpdx/private/pdx/rpc/function_traits.h
@@ -43,6 +43,12 @@
       SignatureType<ConditionalRewrite<Return_, ReturnType>(
           ConditionalRewrite<Args_, Params>...)>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      SignatureType<Wrapper<ConditionalRewrite<Return_, ReturnType>>(
+          ConditionalRewrite<Args_, Params>...)>;
+
   template <typename ReturnType>
   using RewriteReturn =
       SignatureType<ConditionalRewrite<Return_, ReturnType>(Args_...)>;
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method.h b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
index 679503c..e5c6616 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method.h
@@ -10,6 +10,7 @@
 #include <pdx/rpc/payload.h>
 #include <pdx/rpc/remote_method_type.h>
 #include <pdx/service.h>
+#include <pdx/status.h>
 
 namespace android {
 namespace pdx {
@@ -157,6 +158,25 @@
            strerror(-ret));
 }
 
+// Overload for Status<void> return types.
+template <typename RemoteMethodType>
+void RemoteMethodReturn(Message& message, const Status<void>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType>(message, 0);
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
+// Overload for Status<T> return types. This overload forwards the underlying
+// value or error within the Status<T>.
+template <typename RemoteMethodType, typename Return>
+void RemoteMethodReturn(Message& message, const Status<Return>& return_value) {
+  if (return_value)
+    RemoteMethodReturn<RemoteMethodType, Return>(message, return_value.get());
+  else
+    RemoteMethodError(message, return_value.error());
+}
+
 // Dispatches a method by deserializing arguments from the given Message, with
 // compile-time interface check. Overload for void return types.
 template <typename RemoteMethodType, typename Class, typename... Args,
@@ -340,6 +360,46 @@
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
 
+// Dispatches a method by deserializing arguments from the given Message, with
+// compile-time interface signature check. Overload for Status<T> return types.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename... Args, typename = EnableIfNotVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&, Args...),
+                          Message& message,
+                          std::size_t max_capacity = InitialBufferCapacity) {
+  using Signature =
+      typename RemoteMethodType::template RewriteSignature<Return, Args...>;
+  using InvokeSignature =
+      typename RemoteMethodType::template RewriteSignatureWrapReturn<
+          Status, Return, Args...>;
+  rpc::ServicePayload<ReceiveBuffer> payload(message);
+  payload.Resize(max_capacity);
+
+  auto size = message.Read(payload.Data(), payload.Size());
+  if (size < 0) {
+    RemoteMethodError(message, -size);
+    return;
+  }
+
+  payload.Resize(size);
+
+  ErrorType error;
+  auto decoder = MakeArgumentDecoder<Signature>(&payload);
+  auto arguments = decoder.DecodeArguments(&error);
+  if (error) {
+    RemoteMethodError(message, EIO);
+    return;
+  }
+
+  auto return_value = UnpackArguments<Class, InvokeSignature>(
+                          instance, method, message, arguments)
+                          .Invoke();
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
+
 #ifdef __clang__
 // Overloads to handle Void argument type without exploding clang.
 
@@ -399,6 +459,18 @@
   if (message)
     RemoteMethodReturn<RemoteMethodType>(message, return_value);
 }
+
+// Overload for Status<T> return type.
+template <typename RemoteMethodType, typename Class, typename Return,
+          typename = EnableIfVoidMethod<RemoteMethodType>>
+void DispatchRemoteMethod(Class& instance,
+                          Status<Return> (Class::*method)(Message&),
+                          Message& message) {
+  auto return_value = (instance.*method)(message);
+  // Return the value to the caller unless the message was moved.
+  if (message)
+    RemoteMethodReturn<RemoteMethodType>(message, return_value);
+}
 #endif
 
 }  // namespace rpc
diff --git a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
index de9a3cc..cf9a189 100644
--- a/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
+++ b/libs/vr/libpdx/private/pdx/rpc/remote_method_type.h
@@ -31,6 +31,12 @@
   using RewriteSignature =
       typename Traits::template RewriteSignature<ReturnType, Params...>;
 
+  template <template <typename> class Wrapper, typename ReturnType,
+            typename... Params>
+  using RewriteSignatureWrapReturn =
+      typename Traits::template RewriteSignatureWrapReturn<Wrapper, ReturnType,
+                                                           Params...>;
+
   template <typename ReturnType>
   using RewriteReturn = typename Traits::template RewriteReturn<ReturnType>;
 };