|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: sw=4 ts=4 et : |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #ifndef mozilla_ipc_ProtocolUtils_h |
|
9 #define mozilla_ipc_ProtocolUtils_h 1 |
|
10 |
|
11 #include "base/process.h" |
|
12 #include "base/process_util.h" |
|
13 #include "chrome/common/ipc_message_utils.h" |
|
14 |
|
15 #include "prenv.h" |
|
16 |
|
17 #include "IPCMessageStart.h" |
|
18 #include "mozilla/Attributes.h" |
|
19 #include "mozilla/ipc/FileDescriptor.h" |
|
20 #include "mozilla/ipc/Shmem.h" |
|
21 #include "mozilla/ipc/Transport.h" |
|
22 #include "mozilla/ipc/MessageLink.h" |
|
23 #include "mozilla/LinkedList.h" |
|
24 |
|
25 #if defined(ANDROID) && defined(DEBUG) |
|
26 #include <android/log.h> |
|
27 #endif |
|
28 |
|
29 // WARNING: this takes into account the private, special-message-type |
|
30 // enum in ipc_channel.h. They need to be kept in sync. |
|
31 namespace { |
|
32 // XXX the max message ID is actually kuint32max now ... when this |
|
33 // changed, the assumptions of the special message IDs changed in that |
|
34 // they're not carving out messages from likely-unallocated space, but |
|
35 // rather carving out messages from the end of space allocated to |
|
36 // protocol 0. Oops! We can get away with this until protocol 0 |
|
37 // starts approaching its 65,536th message. |
|
38 enum { |
|
39 CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 5, |
|
40 SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 4, |
|
41 SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 3, |
|
42 GOODBYE_MESSAGE_TYPE = kuint16max - 2 |
|
43 |
|
44 // kuint16max - 1 is used by ipc_channel.h. |
|
45 }; |
|
46 } |
|
47 |
|
48 namespace mozilla { |
|
49 namespace dom { |
|
50 class ContentParent; |
|
51 } |
|
52 |
|
53 namespace net { |
|
54 class NeckoParent; |
|
55 } |
|
56 |
|
57 namespace ipc { |
|
58 |
|
59 #ifdef XP_WIN |
|
60 const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE; |
|
61 #else |
|
62 const base::ProcessHandle kInvalidProcessHandle = -1; |
|
63 #endif |
|
64 |
|
65 class ProtocolFdMapping; |
|
66 class ProtocolCloneContext; |
|
67 |
|
68 // Used to pass references to protocol actors across the wire. |
|
69 // Actors created on the parent-side have a positive ID, and actors |
|
70 // allocated on the child side have a negative ID. |
|
71 struct ActorHandle |
|
72 { |
|
73 int mId; |
|
74 }; |
|
75 |
|
76 // Used internally to represent a "trigger" that might cause a state |
|
77 // transition. Triggers are normalized across parent+child to Send |
|
78 // and Recv (instead of child-in, child-out, parent-in, parent-out) so |
|
79 // that they can share the same state machine implementation. To |
|
80 // further normalize, |Send| is used for 'call', |Recv| for 'answer'. |
|
81 struct Trigger |
|
82 { |
|
83 enum Action { Send, Recv }; |
|
84 |
|
85 Trigger(Action action, int32_t msg) : |
|
86 mAction(action), |
|
87 mMsg(msg) |
|
88 {} |
|
89 |
|
90 Action mAction; |
|
91 int32_t mMsg; |
|
92 }; |
|
93 |
|
94 class ProtocolCloneContext |
|
95 { |
|
96 typedef mozilla::dom::ContentParent ContentParent; |
|
97 typedef mozilla::net::NeckoParent NeckoParent; |
|
98 |
|
99 ContentParent* mContentParent; |
|
100 NeckoParent* mNeckoParent; |
|
101 |
|
102 public: |
|
103 ProtocolCloneContext() |
|
104 : mContentParent(nullptr) |
|
105 , mNeckoParent(nullptr) |
|
106 {} |
|
107 |
|
108 void SetContentParent(ContentParent* aContentParent) |
|
109 { |
|
110 mContentParent = aContentParent; |
|
111 } |
|
112 |
|
113 ContentParent* GetContentParent() { return mContentParent; } |
|
114 |
|
115 void SetNeckoParent(NeckoParent* aNeckoParent) |
|
116 { |
|
117 mNeckoParent = aNeckoParent; |
|
118 } |
|
119 |
|
120 NeckoParent* GetNeckoParent() { return mNeckoParent; } |
|
121 }; |
|
122 |
|
123 template<class ListenerT> |
|
124 class /*NS_INTERFACE_CLASS*/ IProtocolManager |
|
125 { |
|
126 public: |
|
127 enum ActorDestroyReason { |
|
128 FailedConstructor, |
|
129 Deletion, |
|
130 AncestorDeletion, |
|
131 NormalShutdown, |
|
132 AbnormalShutdown |
|
133 }; |
|
134 |
|
135 typedef base::ProcessHandle ProcessHandle; |
|
136 |
|
137 virtual int32_t Register(ListenerT*) = 0; |
|
138 virtual int32_t RegisterID(ListenerT*, int32_t) = 0; |
|
139 virtual ListenerT* Lookup(int32_t) = 0; |
|
140 virtual void Unregister(int32_t) = 0; |
|
141 virtual void RemoveManagee(int32_t, ListenerT*) = 0; |
|
142 |
|
143 virtual Shmem::SharedMemory* CreateSharedMemory( |
|
144 size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0; |
|
145 virtual bool AdoptSharedMemory(Shmem::SharedMemory*, int32_t*) = 0; |
|
146 virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0; |
|
147 virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0; |
|
148 virtual bool DestroySharedMemory(Shmem&) = 0; |
|
149 |
|
150 // XXX odd ducks, acknowledged |
|
151 virtual ProcessHandle OtherProcess() const = 0; |
|
152 virtual MessageChannel* GetIPCChannel() = 0; |
|
153 |
|
154 // The implementation of function is generated by code generator. |
|
155 virtual void CloneManagees(ListenerT* aSource, |
|
156 ProtocolCloneContext* aCtx) = 0; |
|
157 }; |
|
158 |
|
159 typedef IPCMessageStart ProtocolId; |
|
160 |
|
161 /** |
|
162 * All RPC protocols should implement this interface. |
|
163 */ |
|
164 class IProtocol : protected MessageListener |
|
165 { |
|
166 public: |
|
167 /** |
|
168 * This function is used to clone this protocol actor. |
|
169 * |
|
170 * see IProtocol::CloneProtocol() |
|
171 */ |
|
172 virtual IProtocol* |
|
173 CloneProtocol(MessageChannel* aChannel, |
|
174 ProtocolCloneContext* aCtx) = 0; |
|
175 }; |
|
176 |
|
177 /** |
|
178 * All top-level protocols should inherit this class. |
|
179 * |
|
180 * IToplevelProtocol tracks all top-level protocol actors created from |
|
181 * this protocol actor. |
|
182 */ |
|
183 class IToplevelProtocol : public LinkedListElement<IToplevelProtocol> |
|
184 { |
|
185 protected: |
|
186 IToplevelProtocol(ProtocolId aProtoId) |
|
187 : mProtocolId(aProtoId) |
|
188 , mTrans(nullptr) |
|
189 { |
|
190 } |
|
191 |
|
192 ~IToplevelProtocol(); |
|
193 |
|
194 /** |
|
195 * Add an actor to the list of actors that have been opened by this |
|
196 * protocol. |
|
197 */ |
|
198 void AddOpenedActor(IToplevelProtocol* aActor); |
|
199 |
|
200 public: |
|
201 void SetTransport(Transport* aTrans) |
|
202 { |
|
203 mTrans = aTrans; |
|
204 } |
|
205 |
|
206 Transport* GetTransport() const { return mTrans; } |
|
207 |
|
208 ProtocolId GetProtocolId() const { return mProtocolId; } |
|
209 |
|
210 /** |
|
211 * Return first of actors of top level protocols opened by this one. |
|
212 */ |
|
213 IToplevelProtocol* GetFirstOpenedActors() |
|
214 { |
|
215 return mOpenActors.getFirst(); |
|
216 } |
|
217 const IToplevelProtocol* GetFirstOpenedActors() const |
|
218 { |
|
219 return mOpenActors.getFirst(); |
|
220 } |
|
221 |
|
222 virtual IToplevelProtocol* |
|
223 CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds, |
|
224 base::ProcessHandle aPeerProcess, |
|
225 ProtocolCloneContext* aCtx); |
|
226 |
|
227 void CloneOpenedToplevels(IToplevelProtocol* aTemplate, |
|
228 const InfallibleTArray<ProtocolFdMapping>& aFds, |
|
229 base::ProcessHandle aPeerProcess, |
|
230 ProtocolCloneContext* aCtx); |
|
231 |
|
232 private: |
|
233 LinkedList<IToplevelProtocol> mOpenActors; // All protocol actors opened by this. |
|
234 |
|
235 ProtocolId mProtocolId; |
|
236 Transport* mTrans; |
|
237 }; |
|
238 |
|
239 |
|
240 inline bool |
|
241 LoggingEnabled() |
|
242 { |
|
243 #if defined(DEBUG) |
|
244 return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG"); |
|
245 #else |
|
246 return false; |
|
247 #endif |
|
248 } |
|
249 |
|
250 MOZ_NEVER_INLINE void |
|
251 ProtocolErrorBreakpoint(const char* aMsg); |
|
252 |
|
253 MOZ_NEVER_INLINE void |
|
254 FatalError(const char* aProtocolName, const char* aMsg, |
|
255 base::ProcessHandle aHandle, bool aIsParent); |
|
256 |
|
257 struct PrivateIPDLInterface {}; |
|
258 |
|
259 bool |
|
260 Bridge(const PrivateIPDLInterface&, |
|
261 MessageChannel*, base::ProcessHandle, MessageChannel*, base::ProcessHandle, |
|
262 ProtocolId, ProtocolId); |
|
263 |
|
264 bool |
|
265 Open(const PrivateIPDLInterface&, |
|
266 MessageChannel*, base::ProcessHandle, Transport::Mode, |
|
267 ProtocolId, ProtocolId); |
|
268 |
|
269 bool |
|
270 UnpackChannelOpened(const PrivateIPDLInterface&, |
|
271 const IPC::Message&, |
|
272 TransportDescriptor*, base::ProcessId*, ProtocolId*); |
|
273 |
|
274 } // namespace ipc |
|
275 } // namespace mozilla |
|
276 |
|
277 |
|
278 namespace IPC { |
|
279 |
|
280 template <> |
|
281 struct ParamTraits<mozilla::ipc::ActorHandle> |
|
282 { |
|
283 typedef mozilla::ipc::ActorHandle paramType; |
|
284 |
|
285 static void Write(Message* aMsg, const paramType& aParam) |
|
286 { |
|
287 IPC::WriteParam(aMsg, aParam.mId); |
|
288 } |
|
289 |
|
290 static bool Read(const Message* aMsg, void** aIter, paramType* aResult) |
|
291 { |
|
292 int id; |
|
293 if (IPC::ReadParam(aMsg, aIter, &id)) { |
|
294 aResult->mId = id; |
|
295 return true; |
|
296 } |
|
297 return false; |
|
298 } |
|
299 |
|
300 static void Log(const paramType& aParam, std::wstring* aLog) |
|
301 { |
|
302 aLog->append(StringPrintf(L"(%d)", aParam.mId)); |
|
303 } |
|
304 }; |
|
305 |
|
306 } // namespace IPC |
|
307 |
|
308 |
|
309 #endif // mozilla_ipc_ProtocolUtils_h |