Home | History | Annotate | Download | only in rpc
      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