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