ipc_message_templates.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
  5. #define IPC_IPC_MESSAGE_TEMPLATES_H_
  6. #include <stdint.h>
  7. #include <tuple>
  8. #include <type_traits>
  9. #include <utility>
  10. #include "base/check.h"
  11. #include "base/notreached.h"
  12. #include "base/trace_event/trace_event.h"
  13. #include "base/tuple.h"
  14. #include "build/build_config.h"
  15. #include "ipc/ipc_message.h"
  16. #include "ipc/ipc_message_utils.h"
  17. #include "ipc/ipc_sync_message.h"
  18. namespace IPC {
  19. template <typename Tuple, size_t... Ns>
  20. auto TupleForwardImpl(Tuple&& tuple, std::index_sequence<Ns...>) -> decltype(
  21. std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...)) {
  22. return std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...);
  23. }
  24. // Transforms std::tuple contents to the forwarding form.
  25. // Example:
  26. // std::tuple<int, int&, const int&, int&&>&&
  27. // -> std::tuple<int&&, int&, const int&, int&&>.
  28. // const std::tuple<int, const int&, int&&>&
  29. // -> std::tuple<const int&, int&, const int&, int&>.
  30. //
  31. // TupleForward(std::make_tuple(a, b, c)) is equivalent to
  32. // std::forward_as_tuple(a, b, c).
  33. template <typename Tuple>
  34. auto TupleForward(Tuple&& tuple) -> decltype(TupleForwardImpl(
  35. std::forward<Tuple>(tuple),
  36. std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>())) {
  37. return TupleForwardImpl(
  38. std::forward<Tuple>(tuple),
  39. std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
  40. }
  41. // This function is for all the async IPCs that don't pass an extra parameter
  42. // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
  43. template <typename ObjT, typename Method, typename P, typename Tuple>
  44. void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
  45. base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
  46. }
  47. template <typename ObjT,
  48. typename Method,
  49. typename P,
  50. typename Tuple,
  51. size_t... Ns>
  52. void DispatchToMethodImpl(ObjT* obj,
  53. Method method,
  54. P* parameter,
  55. Tuple&& tuple,
  56. std::index_sequence<Ns...>) {
  57. (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
  58. }
  59. // The following function is for async IPCs which have a dispatcher with an
  60. // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
  61. template <typename ObjT, typename P, typename... Args, typename Tuple>
  62. std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
  63. DispatchToMethod(ObjT* obj,
  64. void (ObjT::*method)(P*, Args...),
  65. P* parameter,
  66. Tuple&& tuple) {
  67. constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
  68. DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
  69. std::make_index_sequence<size>());
  70. }
  71. enum class MessageKind {
  72. CONTROL,
  73. ROUTED,
  74. };
  75. // Routing is a helper struct so MessageT's private common constructor has a
  76. // different type signature than the public "int32_t routing_id" one.
  77. struct Routing {
  78. explicit Routing(int32_t id) : id(id) {}
  79. int32_t id;
  80. };
  81. // We want to restrict MessageT's constructors so that a routing_id is always
  82. // provided for ROUTED messages and never provided for CONTROL messages, so
  83. // use the SFINAE technique from N4387's "Implementation Hint" section.
  84. #define IPC_MESSAGET_SFINAE(x) \
  85. template <bool X = (x), typename std::enable_if<X, bool>::type = false>
  86. // MessageT is the common template used for all user-defined message types.
  87. // It's intended to be used via the macros defined in ipc_message_macros.h.
  88. template <typename Meta,
  89. typename InTuple = typename Meta::InTuple,
  90. typename OutTuple = typename Meta::OutTuple>
  91. class MessageT;
  92. // Asynchronous message partial specialization.
  93. template <typename Meta, typename... Ins>
  94. class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
  95. public:
  96. using Param = std::tuple<Ins...>;
  97. enum { ID = Meta::ID };
  98. // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
  99. // with just MyMessage::Param.
  100. using Schema = MessageT;
  101. IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
  102. MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
  103. DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
  104. }
  105. IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
  106. MessageT(int32_t routing_id, const Ins&... ins)
  107. : MessageT(Routing(routing_id), ins...) {
  108. DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
  109. }
  110. static bool Read(const Message* msg, Param* p);
  111. static void Log(std::string* name, const Message* msg, std::string* l);
  112. template <class T, class S, class P, class Method>
  113. static bool Dispatch(const Message* msg,
  114. T* obj,
  115. S* sender,
  116. P* parameter,
  117. Method func) {
  118. TRACE_EVENT0("ipc", Meta::kName);
  119. Param p;
  120. if (Read(msg, &p)) {
  121. DispatchToMethod(obj, func, parameter, std::move(p));
  122. return true;
  123. }
  124. return false;
  125. }
  126. private:
  127. MessageT(Routing routing, const Ins&... ins);
  128. };
  129. // Synchronous message partial specialization.
  130. template <typename Meta, typename... Ins, typename... Outs>
  131. class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
  132. : public SyncMessage {
  133. public:
  134. using SendParam = std::tuple<Ins...>;
  135. using ReplyParam = std::tuple<Outs...>;
  136. enum { ID = Meta::ID };
  137. // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
  138. // be replaced with just MyMessage::{Send,Reply}Param.
  139. using Schema = MessageT;
  140. IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
  141. MessageT(const Ins&... ins, Outs*... outs)
  142. : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
  143. DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
  144. }
  145. IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
  146. MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
  147. : MessageT(Routing(routing_id), ins..., outs...) {
  148. DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
  149. }
  150. static bool ReadSendParam(const Message* msg, SendParam* p);
  151. static bool ReadReplyParam(const Message* msg, ReplyParam* p);
  152. static void WriteReplyParams(Message* reply, const Outs&... outs);
  153. static void Log(std::string* name, const Message* msg, std::string* l);
  154. template <class T, class S, class P, class Method>
  155. static bool Dispatch(const Message* msg,
  156. T* obj,
  157. S* sender,
  158. P* /* parameter */,
  159. Method func) {
  160. TRACE_EVENT0("ipc", Meta::kName);
  161. SendParam send_params;
  162. bool ok = ReadSendParam(msg, &send_params);
  163. Message* reply = SyncMessage::GenerateReply(msg);
  164. if (!ok) {
  165. NOTREACHED() << "Error deserializing message " << msg->type();
  166. reply->set_reply_error();
  167. sender->Send(reply);
  168. return false;
  169. }
  170. ReplyParam reply_params;
  171. base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
  172. WriteParam(reply, reply_params);
  173. LogReplyParamsToMessage(reply_params, msg);
  174. sender->Send(reply);
  175. return true;
  176. }
  177. template <class T, class P, class Method>
  178. static bool DispatchDelayReply(const Message* msg,
  179. T* obj,
  180. P* /* parameter */,
  181. Method func) {
  182. TRACE_EVENT0("ipc", Meta::kName);
  183. SendParam send_params;
  184. bool ok = ReadSendParam(msg, &send_params);
  185. Message* reply = SyncMessage::GenerateReply(msg);
  186. if (!ok) {
  187. NOTREACHED() << "Error deserializing message " << msg->type();
  188. reply->set_reply_error();
  189. obj->Send(reply);
  190. return false;
  191. }
  192. std::tuple<Message&> t = std::tie(*reply);
  193. ConnectMessageAndReply(msg, reply);
  194. base::DispatchToMethod(obj, func, std::move(send_params), &t);
  195. return true;
  196. }
  197. template <class T, class P, class Method>
  198. static bool DispatchWithParamDelayReply(const Message* msg,
  199. T* obj,
  200. P* parameter,
  201. Method func) {
  202. TRACE_EVENT0("ipc", Meta::kName);
  203. SendParam send_params;
  204. bool ok = ReadSendParam(msg, &send_params);
  205. Message* reply = SyncMessage::GenerateReply(msg);
  206. if (!ok) {
  207. NOTREACHED() << "Error deserializing message " << msg->type();
  208. reply->set_reply_error();
  209. obj->Send(reply);
  210. return false;
  211. }
  212. std::tuple<Message&> t = std::tie(*reply);
  213. ConnectMessageAndReply(msg, reply);
  214. std::tuple<P*> parameter_tuple(parameter);
  215. base::DispatchToMethod(
  216. obj, func,
  217. std::tuple_cat(std::move(parameter_tuple), TupleForward(send_params)),
  218. &t);
  219. return true;
  220. }
  221. private:
  222. MessageT(Routing routing, const Ins&... ins, Outs*... outs);
  223. };
  224. } // namespace IPC
  225. #if defined(IPC_MESSAGE_IMPL)
  226. #include "ipc/ipc_message_templates_impl.h"
  227. #endif
  228. #endif // IPC_IPC_MESSAGE_TEMPLATES_H_