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