Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / ipc / glue / Endpoint.h
blobfc643f967f4a97e6b719fe21538f800826410f08
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #ifndef IPC_GLUE_ENDPOINT_H_
8 #define IPC_GLUE_ENDPOINT_H_
10 #include <utility>
11 #include "CrashAnnotations.h"
12 #include "base/process.h"
13 #include "base/process_util.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Maybe.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/ipc/MessageLink.h"
18 #include "mozilla/ipc/ProtocolUtils.h"
19 #include "mozilla/ipc/NodeController.h"
20 #include "mozilla/ipc/ScopedPort.h"
21 #include "nsXULAppAPI.h"
22 #include "nscore.h"
24 namespace IPC {
25 template <class P>
26 struct ParamTraits;
29 namespace mozilla {
30 namespace ipc {
32 namespace endpoint_detail {
34 template <class T>
35 static auto ActorNeedsOtherPidHelper(int)
36 -> decltype(std::declval<T>().OtherPid(), std::true_type{});
37 template <class>
38 static auto ActorNeedsOtherPidHelper(long) -> std::false_type;
40 template <typename T>
41 constexpr bool ActorNeedsOtherPid =
42 decltype(ActorNeedsOtherPidHelper<T>(0))::value;
44 } // namespace endpoint_detail
46 struct PrivateIPDLInterface {};
48 class UntypedEndpoint {
49 public:
50 UntypedEndpoint() = default;
52 UntypedEndpoint(const PrivateIPDLInterface&, ScopedPort aPort,
53 const nsID& aMessageChannelId,
54 EndpointProcInfo aMyProcInfo = EndpointProcInfo::Invalid(),
55 EndpointProcInfo aOtherProcInfo = EndpointProcInfo::Invalid())
56 : mPort(std::move(aPort)),
57 mMessageChannelId(aMessageChannelId),
58 mMyProcInfo(aMyProcInfo),
59 mOtherProcInfo(aOtherProcInfo) {}
61 UntypedEndpoint(const UntypedEndpoint&) = delete;
62 UntypedEndpoint(UntypedEndpoint&& aOther) = default;
64 UntypedEndpoint& operator=(const UntypedEndpoint&) = delete;
65 UntypedEndpoint& operator=(UntypedEndpoint&& aOther) = default;
67 // This method binds aActor to this endpoint. After this call, the actor can
68 // be used to send and receive messages. The endpoint becomes invalid.
70 // If specified, aEventTarget is the target the actor will be bound to, and
71 // must be on the current thread. Otherwise, GetCurrentSerialEventTarget() is
72 // used.
73 bool Bind(IToplevelProtocol* aActor,
74 nsISerialEventTarget* aEventTarget = nullptr) {
75 MOZ_RELEASE_ASSERT(IsValid());
76 MOZ_RELEASE_ASSERT(mMyProcInfo == EndpointProcInfo::Invalid() ||
77 mMyProcInfo == EndpointProcInfo::Current());
78 MOZ_RELEASE_ASSERT(!aEventTarget || aEventTarget->IsOnCurrentThread());
79 return aActor->Open(std::move(mPort), mMessageChannelId, mOtherProcInfo,
80 aEventTarget);
83 bool IsValid() const { return mPort.IsValid(); }
85 protected:
86 friend struct IPC::ParamTraits<UntypedEndpoint>;
88 ScopedPort mPort;
89 nsID mMessageChannelId{};
90 EndpointProcInfo mMyProcInfo;
91 EndpointProcInfo mOtherProcInfo;
94 /**
95 * An endpoint represents one end of a partially initialized IPDL channel. To
96 * set up a new top-level protocol:
98 * Endpoint<PFooParent> parentEp;
99 * Endpoint<PFooChild> childEp;
100 * nsresult rv;
101 * rv = PFoo::CreateEndpoints(&parentEp, &childEp);
103 * Endpoints can be passed in IPDL messages or sent to other threads using
104 * PostTask. Once an Endpoint has arrived at its destination process and thread,
105 * you need to create the top-level actor and bind it to the endpoint:
107 * FooParent* parent = new FooParent();
108 * bool rv1 = parentEp.Bind(parent, processActor);
109 * bool rv2 = parent->SendBar(...);
111 * (See Bind below for an explanation of processActor.) Once the actor is bound
112 * to the endpoint, it can send and receive messages.
114 * If creating endpoints for a [NeedsOtherPid] actor, you're required to also
115 * pass in parentPid and childPid, which are the pids of the processes in which
116 * the parent and child endpoints will be used.
118 template <class PFooSide>
119 class Endpoint final : public UntypedEndpoint {
120 public:
121 using UntypedEndpoint::IsValid;
122 using UntypedEndpoint::UntypedEndpoint;
124 EndpointProcInfo OtherEndpointProcInfo() const {
125 static_assert(
126 endpoint_detail::ActorNeedsOtherPid<PFooSide>,
127 "OtherPid may only be called on Endpoints for actors which are "
128 "[NeedsOtherPid]");
129 MOZ_RELEASE_ASSERT(mOtherProcInfo != EndpointProcInfo::Invalid());
130 return mOtherProcInfo;
133 base::ProcessId OtherPid() const { return OtherEndpointProcInfo().mPid; }
135 GeckoChildID OtherChildID() const { return OtherEndpointProcInfo().mChildID; }
137 // This method binds aActor to this endpoint. After this call, the actor can
138 // be used to send and receive messages. The endpoint becomes invalid.
140 // If specified, aEventTarget is the target the actor will be bound to, and
141 // must be on the current thread. Otherwise, GetCurrentSerialEventTarget() is
142 // used.
143 bool Bind(PFooSide* aActor, nsISerialEventTarget* aEventTarget = nullptr) {
144 return UntypedEndpoint::Bind(aActor, aEventTarget);
148 #if defined(XP_MACOSX)
149 void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error);
150 #else
151 inline void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag,
152 int error) {}
153 #endif
155 // This function is used internally to create a pair of Endpoints. See the
156 // comment above Endpoint for a description of how it might be used.
157 template <class PFooParent, class PFooChild>
158 nsresult CreateEndpoints(const PrivateIPDLInterface& aPrivate,
159 Endpoint<PFooParent>* aParentEndpoint,
160 Endpoint<PFooChild>* aChildEndpoint) {
161 static_assert(
162 !endpoint_detail::ActorNeedsOtherPid<PFooParent> &&
163 !endpoint_detail::ActorNeedsOtherPid<PFooChild>,
164 "Pids are required when creating endpoints for [NeedsOtherPid] actors");
166 auto [parentPort, childPort] =
167 NodeController::GetSingleton()->CreatePortPair();
168 nsID channelId = nsID::GenerateUUID();
169 *aParentEndpoint =
170 Endpoint<PFooParent>(aPrivate, std::move(parentPort), channelId);
171 *aChildEndpoint =
172 Endpoint<PFooChild>(aPrivate, std::move(childPort), channelId);
173 return NS_OK;
176 template <class PFooParent, class PFooChild>
177 nsresult CreateEndpoints(const PrivateIPDLInterface& aPrivate,
178 EndpointProcInfo aParentDestProcInfo,
179 EndpointProcInfo aChildDestProcInfo,
180 Endpoint<PFooParent>* aParentEndpoint,
181 Endpoint<PFooChild>* aChildEndpoint) {
182 MOZ_RELEASE_ASSERT(aParentDestProcInfo != EndpointProcInfo::Invalid());
183 MOZ_RELEASE_ASSERT(aChildDestProcInfo != EndpointProcInfo::Invalid());
185 auto [parentPort, childPort] =
186 NodeController::GetSingleton()->CreatePortPair();
187 nsID channelId = nsID::GenerateUUID();
188 *aParentEndpoint =
189 Endpoint<PFooParent>(aPrivate, std::move(parentPort), channelId,
190 aParentDestProcInfo, aChildDestProcInfo);
191 *aChildEndpoint =
192 Endpoint<PFooChild>(aPrivate, std::move(childPort), channelId,
193 aChildDestProcInfo, aParentDestProcInfo);
194 return NS_OK;
197 class UntypedManagedEndpoint {
198 public:
199 bool IsValid() const { return mInner.isSome(); }
201 UntypedManagedEndpoint(const UntypedManagedEndpoint&) = delete;
202 UntypedManagedEndpoint& operator=(const UntypedManagedEndpoint&) = delete;
204 protected:
205 UntypedManagedEndpoint() = default;
206 explicit UntypedManagedEndpoint(IProtocol* aActor);
208 UntypedManagedEndpoint(UntypedManagedEndpoint&& aOther) noexcept
209 : mInner(std::move(aOther.mInner)) {
210 aOther.mInner = Nothing();
212 UntypedManagedEndpoint& operator=(UntypedManagedEndpoint&& aOther) noexcept {
213 this->~UntypedManagedEndpoint();
214 new (this) UntypedManagedEndpoint(std::move(aOther));
215 return *this;
218 ~UntypedManagedEndpoint() noexcept;
220 bool BindCommon(IProtocol* aActor, IRefCountedProtocol* aManager);
222 private:
223 friend struct IPDLParamTraits<UntypedManagedEndpoint>;
225 struct Inner {
226 // Pointers to the toplevel actor which will manage this connection. When
227 // created, only `mOtherSide` will be set, and will reference the
228 // toplevel actor which the other side is managed by. After being sent over
229 // IPC, only `mToplevel` will be set, and will be the toplevel actor for the
230 // channel which received the IPC message.
231 RefPtr<WeakActorLifecycleProxy> mOtherSide;
232 RefPtr<WeakActorLifecycleProxy> mToplevel;
234 int32_t mId = 0;
235 ProtocolId mType = LastMsgIndex;
236 int32_t mManagerId = 0;
237 ProtocolId mManagerType = LastMsgIndex;
239 Maybe<Inner> mInner;
243 * A managed endpoint represents one end of a partially initialized managed
244 * IPDL actor. It is used for situations where the usual IPDL Constructor
245 * methods do not give sufficient control over the construction of actors, such
246 * as when constructing actors within replies, or constructing multiple related
247 * actors simultaneously.
249 * FooParent* parent = new FooParent();
250 * ManagedEndpoint<PFooChild> childEp = parentMgr->OpenPFooEndpoint(parent);
252 * ManagedEndpoints should be sent using IPDL messages or other mechanisms to
253 * the other side of the manager channel. Once the ManagedEndpoint has arrived
254 * at its destination, you can create the actor, and bind it to the endpoint.
256 * FooChild* child = new FooChild();
257 * childMgr->BindPFooEndpoint(childEp, child);
259 * WARNING: If the remote side of an endpoint has not been bound before it
260 * begins to receive messages, an IPC routing error will occur, likely causing
261 * a browser crash.
263 template <class PFooSide>
264 class ManagedEndpoint : public UntypedManagedEndpoint {
265 public:
266 ManagedEndpoint() = default;
267 ManagedEndpoint(ManagedEndpoint&&) noexcept = default;
268 ManagedEndpoint& operator=(ManagedEndpoint&&) noexcept = default;
270 ManagedEndpoint(const PrivateIPDLInterface&, IProtocol* aActor)
271 : UntypedManagedEndpoint(aActor) {}
273 bool Bind(const PrivateIPDLInterface&, PFooSide* aActor,
274 IRefCountedProtocol* aManager) {
275 return BindCommon(aActor, aManager);
278 // Only invalid ManagedEndpoints can be equal, as valid endpoints are unique.
279 bool operator==(const ManagedEndpoint& _o) const {
280 return !IsValid() && !_o.IsValid();
284 } // namespace ipc
285 } // namespace mozilla
287 #endif // IPC_GLUE_ENDPOINT_H_