Bug 1788596 - Remove UTILITY_AUDIO_DECODING_GENERIC r=nika,media-playback-reviewers...
[gecko.git] / ipc / glue / NodeChannel.cpp
blob89c6c83c8fff8491773cd78abd622cdd143d2116
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/ipc/NodeChannel.h"
8 #include "chrome/common/ipc_message.h"
9 #include "chrome/common/ipc_message_utils.h"
10 #include "mojo/core/ports/name.h"
11 #include "mozilla/ipc/BrowserProcessSubThread.h"
12 #include "mozilla/ipc/ProtocolMessageUtils.h"
13 #include "mozilla/ipc/ProtocolUtils.h"
14 #include "nsThreadUtils.h"
15 #include "nsXULAppAPI.h"
17 #ifdef FUZZING_SNAPSHOT
18 # include "mozilla/fuzzing/IPCFuzzController.h"
19 #endif
21 template <>
22 struct IPC::ParamTraits<mozilla::ipc::NodeChannel::Introduction> {
23 using paramType = mozilla::ipc::NodeChannel::Introduction;
24 static void Write(MessageWriter* aWriter, paramType&& aParam) {
25 WriteParam(aWriter, aParam.mName);
26 WriteParam(aWriter, std::move(aParam.mHandle));
27 WriteParam(aWriter, aParam.mMode);
28 WriteParam(aWriter, aParam.mMyPid);
29 WriteParam(aWriter, aParam.mOtherPid);
31 static bool Read(MessageReader* aReader, paramType* aResult) {
32 return ReadParam(aReader, &aResult->mName) &&
33 ReadParam(aReader, &aResult->mHandle) &&
34 ReadParam(aReader, &aResult->mMode) &&
35 ReadParam(aReader, &aResult->mMyPid) &&
36 ReadParam(aReader, &aResult->mOtherPid);
40 namespace mozilla::ipc {
42 NodeChannel::NodeChannel(const NodeName& aName,
43 UniquePtr<IPC::Channel> aChannel, Listener* aListener,
44 base::ProcessId aPid)
45 : mListener(aListener),
46 mName(aName),
47 mOtherPid(aPid),
48 mChannel(std::move(aChannel)) {}
50 NodeChannel::~NodeChannel() {
51 AssertIOThread();
52 if (!mClosed) {
53 mChannel->Close();
57 // Called when the NodeChannel's refcount drops to `0`.
58 void NodeChannel::Destroy() {
59 // Dispatch the `delete` operation to the IO thread. We need to do this even
60 // if we're already on the IO thread, as we could be in an `IPC::Channel`
61 // callback which unfortunately will not hold a strong reference to keep
62 // `this` alive.
63 MessageLoop* ioThread = XRE_GetIOMessageLoop();
64 if (ioThread->IsAcceptingTasks()) {
65 ioThread->PostTask(NewNonOwningRunnableMethod("NodeChannel::Destroy", this,
66 &NodeChannel::FinalDestroy));
67 return;
70 // If the IOThread has already been destroyed, we must be shutting it down and
71 // need to synchronously invoke `FinalDestroy` to ensure we're cleaned up
72 // before the thread dies. This is safe as we can't be in a non-owning
73 // IPC::Channel callback at this point.
74 if (MessageLoop::current() == ioThread) {
75 FinalDestroy();
76 return;
79 MOZ_ASSERT_UNREACHABLE("Leaking NodeChannel after IOThread destroyed!");
82 void NodeChannel::FinalDestroy() {
83 AssertIOThread();
84 delete this;
87 void NodeChannel::Start(bool aCallConnect) {
88 AssertIOThread();
90 mExistingListener = mChannel->set_listener(this);
92 std::queue<UniquePtr<IPC::Message>> pending;
93 if (mExistingListener) {
94 mExistingListener->GetQueuedMessages(pending);
97 if (aCallConnect) {
98 MOZ_ASSERT(pending.empty(), "unopened channel with pending messages?");
99 if (!mChannel->Connect()) {
100 OnChannelError();
102 } else {
103 // Check if our channel has already been connected, and knows the other PID.
104 base::ProcessId otherPid = mChannel->OtherPid();
105 if (otherPid != base::kInvalidProcessId) {
106 SetOtherPid(otherPid);
109 // Handle any events the previous listener had queued up. Make sure to stop
110 // if an error causes our channel to become closed.
111 while (!pending.empty() && !mClosed) {
112 OnMessageReceived(std::move(pending.front()));
113 pending.pop();
118 void NodeChannel::Close() {
119 AssertIOThread();
121 if (!mClosed) {
122 mChannel->Close();
123 mChannel->set_listener(mExistingListener);
125 mClosed = true;
128 void NodeChannel::SetOtherPid(base::ProcessId aNewPid) {
129 AssertIOThread();
130 MOZ_ASSERT(aNewPid != base::kInvalidProcessId);
132 base::ProcessId previousPid = base::kInvalidProcessId;
133 if (!mOtherPid.compare_exchange_strong(previousPid, aNewPid)) {
134 // The PID was already set before this call, double-check that it's correct.
135 MOZ_RELEASE_ASSERT(previousPid == aNewPid,
136 "Different sources disagree on the correct pid?");
140 #ifdef XP_MACOSX
141 void NodeChannel::SetMachTaskPort(task_t aTask) {
142 AssertIOThread();
144 if (!mClosed) {
145 mChannel->SetOtherMachTask(aTask);
148 #endif
150 void NodeChannel::SendEventMessage(UniquePtr<IPC::Message> aMessage) {
151 // Make sure we're not sending a message with one of our special internal
152 // types ,as those should only be sent using the corresponding methods on
153 // NodeChannel.
154 MOZ_DIAGNOSTIC_ASSERT(aMessage->type() != BROADCAST_MESSAGE_TYPE &&
155 aMessage->type() != INTRODUCE_MESSAGE_TYPE &&
156 aMessage->type() != REQUEST_INTRODUCTION_MESSAGE_TYPE &&
157 aMessage->type() != ACCEPT_INVITE_MESSAGE_TYPE);
158 SendMessage(std::move(aMessage));
161 void NodeChannel::RequestIntroduction(const NodeName& aPeerName) {
162 MOZ_ASSERT(aPeerName != mojo::core::ports::kInvalidNodeName);
163 auto message = MakeUnique<IPC::Message>(MSG_ROUTING_CONTROL,
164 REQUEST_INTRODUCTION_MESSAGE_TYPE);
165 IPC::MessageWriter writer(*message);
166 WriteParam(&writer, aPeerName);
167 SendMessage(std::move(message));
170 void NodeChannel::Introduce(Introduction aIntroduction) {
171 auto message =
172 MakeUnique<IPC::Message>(MSG_ROUTING_CONTROL, INTRODUCE_MESSAGE_TYPE);
173 IPC::MessageWriter writer(*message);
174 WriteParam(&writer, std::move(aIntroduction));
175 SendMessage(std::move(message));
178 void NodeChannel::Broadcast(UniquePtr<IPC::Message> aMessage) {
179 MOZ_DIAGNOSTIC_ASSERT(aMessage->type() == BROADCAST_MESSAGE_TYPE,
180 "Can only broadcast messages with the correct type");
181 SendMessage(std::move(aMessage));
184 void NodeChannel::AcceptInvite(const NodeName& aRealName,
185 const PortName& aInitialPort) {
186 MOZ_ASSERT(aRealName != mojo::core::ports::kInvalidNodeName);
187 MOZ_ASSERT(aInitialPort != mojo::core::ports::kInvalidPortName);
188 auto message =
189 MakeUnique<IPC::Message>(MSG_ROUTING_CONTROL, ACCEPT_INVITE_MESSAGE_TYPE);
190 IPC::MessageWriter writer(*message);
191 WriteParam(&writer, aRealName);
192 WriteParam(&writer, aInitialPort);
193 SendMessage(std::move(message));
196 void NodeChannel::SendMessage(UniquePtr<IPC::Message> aMessage) {
197 if (aMessage->size() > IPC::Channel::kMaximumMessageSize) {
198 CrashReporter::AnnotateCrashReport(
199 CrashReporter::Annotation::IPCMessageName,
200 nsDependentCString(aMessage->name()));
201 CrashReporter::AnnotateCrashReport(
202 CrashReporter::Annotation::IPCMessageSize,
203 static_cast<unsigned int>(aMessage->size()));
204 MOZ_CRASH("IPC message size is too large");
206 aMessage->AssertAsLargeAsHeader();
208 XRE_GetIOMessageLoop()->PostTask(
209 NewRunnableMethod<StoreCopyPassByRRef<UniquePtr<IPC::Message>>>(
210 "NodeChannel::DoSendMessage", this, &NodeChannel::DoSendMessage,
211 std::move(aMessage)));
214 void NodeChannel::DoSendMessage(UniquePtr<IPC::Message> aMessage) {
215 #ifdef FUZZING_SNAPSHOT
216 if (mBlockSendRecv) {
217 return;
219 #endif
221 AssertIOThread();
222 if (mClosed) {
223 NS_WARNING("Dropping message as channel has been closed");
224 return;
227 if (!mChannel->Send(std::move(aMessage))) {
228 NS_WARNING("Call to Send() failed");
229 OnChannelError();
233 void NodeChannel::OnMessageReceived(UniquePtr<IPC::Message> aMessage) {
234 AssertIOThread();
236 #ifdef FUZZING_SNAPSHOT
237 if (mBlockSendRecv && !aMessage->IsFuzzMsg()) {
238 return;
240 #endif
242 IPC::MessageReader reader(*aMessage);
243 switch (aMessage->type()) {
244 case REQUEST_INTRODUCTION_MESSAGE_TYPE: {
245 NodeName name;
246 if (IPC::ReadParam(&reader, &name)) {
247 mListener->OnRequestIntroduction(mName, name);
248 return;
250 break;
252 case INTRODUCE_MESSAGE_TYPE: {
253 Introduction introduction;
254 if (IPC::ReadParam(&reader, &introduction)) {
255 mListener->OnIntroduce(mName, std::move(introduction));
256 return;
258 break;
260 case BROADCAST_MESSAGE_TYPE: {
261 mListener->OnBroadcast(mName, std::move(aMessage));
262 return;
264 case ACCEPT_INVITE_MESSAGE_TYPE: {
265 NodeName realName;
266 PortName initialPort;
267 if (IPC::ReadParam(&reader, &realName) &&
268 IPC::ReadParam(&reader, &initialPort)) {
269 mListener->OnAcceptInvite(mName, realName, initialPort);
270 return;
272 break;
274 // Assume all unrecognized types are intended as user event messages, and
275 // deliver them to our listener as such. This allows us to use the same type
276 // field for both internal messages and protocol messages.
278 // FIXME: Consider doing something cleaner in the future?
279 case EVENT_MESSAGE_TYPE:
280 default: {
281 #ifdef FUZZING_SNAPSHOT
282 if (!fuzzing::IPCFuzzController::instance().ObserveIPCMessage(
283 this, *aMessage)) {
284 return;
286 #endif
288 mListener->OnEventMessage(mName, std::move(aMessage));
289 return;
293 // If we got to this point without early returning the message was malformed
294 // in some way. Report an error.
296 NS_WARNING("NodeChannel received a malformed message");
297 OnChannelError();
300 void NodeChannel::OnChannelConnected(base::ProcessId aPeerPid) {
301 AssertIOThread();
303 SetOtherPid(aPeerPid);
305 // We may need to tell our original listener (which will be the process launch
306 // code) that the the channel has been connected to unblock completing the
307 // process launch.
308 // FIXME: This is super sketchy, but it's also what we were already doing. We
309 // should swap this out for something less sketchy.
310 if (mExistingListener) {
311 mExistingListener->OnChannelConnected(aPeerPid);
315 void NodeChannel::OnChannelError() {
316 AssertIOThread();
318 // Clean up the channel and make sure we're no longer the active listener.
319 mChannel->Close();
320 MOZ_ALWAYS_TRUE(this == mChannel->set_listener(mExistingListener));
321 mClosed = true;
323 // Tell our listener about the error.
324 mListener->OnChannelError(mName);
327 } // namespace mozilla::ipc