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