| Bug 1641989: Add FOGTransport parent/child to replace PContentChild in FOG IPC r?chutten
Referenced Files | Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:29 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:28 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:26 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:25 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:24 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:24 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:23 (UTC+0) |
| Unknown Object (File) | | Tue, Jun 16, 10:13 PM2026-06-16 22:13:22 (UTC+0) |
Event Timeline| dom/ipc/ContentParent.cpp |
| 1245–1248 | In a normal Firefox Desktop run there'll be multiple content children and each one will need their own pair of child,parent endpoints. This'll mean that we'll have multiple different parent endpoints arriving here, all of which we'll need to bind.
This ought to be testable via xpcshell with multiple simultaneous content tasks, but I'm not sure I've ever tried. |
| 1250 | |
| 1260 |
| toolkit/components/glean/docs/dev/ipc.md |
| 166 | |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 474 | Weird that it's asking you to qualify these. They ought to just be from the statement up on line 49 |
| toolkit/components/glean/ipc/FOGTransportChild.h |
| 16 | I think modern C++ prefers over like |
Comment ActionsThis is starting to look good, so I think it's time to bring in @nika to weigh in on whether we successfully understood her instructions.
Some notes:
- This is for content children only so far, and only handles the receipt on the parent on a bg task queue (send is still main thread). If it's easy to support bg sending as well as bg receiving, we'd love to hear it (though it might be a follow-up given how the Rust calls out to C++ at the moment, and because a small, landable improvement is worth landing).
- We're not 100% sure how to test this. Manual testing using with confirms that it runs, but it only runs a single content child. If there are examples of multi-child tests we can learn from: fantastic.
| toolkit/components/glean/ipc/FOGTransportChild.h |
| 29 | |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 17–19 | |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 474 | Seems like re-defining that statement to be has fixed the issue |
nika added inline comments. | dom/ipc/ContentParent.cpp |
| 1250–1256 | I don't think you need to hold onto this task queue, as this will be the only time it is ever used - as it's created for this particular use. I also don't think it is possible for it to fail to create a queue when a is still able to receive IPC, so you can probably get away with .
FYI the current design creates a separate task queue for every content process. I'm not sure if that's what the intention was or not? |
| 1252 | Out of curiosity, why the vowels-removed task queue name? |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 52 | Where did this change come from? |
| 451 | Looks like you ran into the " is ambiguous" issue I mention below :-) |
| 601–620 | Do you aspire to also support for these other process types? I think it should be feasible to also send the endpoints over these actors as well, and uniformly use for FOG data between all child processes and the parent process (though non-content processes naturally don't have a type). |
| toolkit/components/glean/ipc/FOGTransportChild.cpp |
| 27 | I notice you're still sending the FOG data on the content process main thread. I take it this patch isn't intending to change that? |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 23–26 | I'd generally not bother with doing unless you really need to avoid a refcount. |
| 30 | AFAICT this is currently completely unused, is that correct? DO you have aspirations to do more validation based on this or something like that? |
| toolkit/components/glean/ipc/PFOGTransport.ipdl |
| 8–10 | In general I prefer not to add extra namespaces like when possible. We have one for , and it causes headaches every once in a while, as if you're in a translation unit which has done a , or are within the namespace, names like are now ambiguous and require full qualification. This sometimes causes build issues in unified builds.
I think I'd probably recommend just putting it into ? |
| 13 | nothing on this protocol needs to be sync. |
| 20 | isn't necessary for toplevel actors. |
| 23–25 | We like to add comments to closing namespace indicators, so that it's more clear what's going on, as often they can be quite far away from the initial declaration. |
Comment ActionsThe ones I've marked done I'm in the process of addressing - working through build issues locally.
Thank you so much for your review, I've got some responses and questions if you don't mind. | dom/ipc/ContentParent.cpp |
| 1250–1256 | The intention was for it to create a single task queue on first use that would be used across all processes, so that's certainly something I need to adjust. I'd meant for the created task queue to have be a reference to it.
Is there something in what I wrote that didn't do that as I expected it to? That's what I understood to be doing. |
| 1252 | I think that's from when I had accidentally left it as a BackgroundThread, which had a character limit on the name. I was following previous patterns, which primarily seemed to remove the vowels. |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 52 | Harbormaster and my local IDE were both complaining that usages of ByteBuf later in the file were not resolving correctly, and this seemed to resolve that issue |
| 451 | Yep that's also why I ended up adding the above |
| 601–620 | My understanding is for now we are focused on content processes, but we may choose to expand it in the future. |
| toolkit/components/glean/ipc/FOGTransportChild.cpp |
| 27 | This would be the child process' main thread, right? |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 30 | I think it would be wise of us to do so, but at this time I admittedly don't have the experience in this space to know how to do that. |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 23–26 | I'm running into issues implementing this change due to the following errors:
0:13.37 E /Users/charlie.humphreys/git/firefox/toolkit/components/glean/FOGTransportParent.h:24:9: error: call to implicitly-deleted copy constructor of 'ThreadsafeContentParentHandle' (aka 'mozilla::dom::ThreadsafeContentParentHandle')
0:13.37 E 24 | : mThreadsafeContentParentHandle(*aThreadsafeContentParentHandle) {}
0:13.37 E | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0:13.37 E /Users/charlie.humphreys/git/firefox/dom/ipc/ContentParent.h:1679:3: note: copy constructor of 'ThreadsafeContentParentHandle' is implicitly deleted because field 'mRefCnt' has a deleted copy constructor
0:13.37 E 1679 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadsafeContentParentHandle);
0:13.37 E | ^
0:13.37 E /Users/charlie.humphreys/git/firefox/xpcom/base/nsISupportsImpl.h:771:3: note: expanded from macro 'NS_INLINE_DECL_THREADSAFE_REFCOUNTING'
0:13.37 E 771 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY(_class, delete (this), \
0:13.37 E | ^
0:13.37 E /Users/charlie.humphreys/git/firefox/xpcom/base/nsISupportsImpl.h:749:3: note: expanded from macro 'NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DESTROY'
0:13.37 E 749 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META(_class, NS_METHOD_, _destroy, \
0:13.37 E | ^
0:13.37 E /Users/charlie.humphreys/git/firefox/xpcom/base/nsISupportsImpl.h:732:35: note: expanded from macro 'NS_INLINE_DECL_THREADSAFE_REFCOUNTING_META'
0:13.37 E 732 | ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
0:13.38 E | ^
0:13.38 E /Users/charlie.humphreys/git/firefox/xpcom/base/nsISupportsImpl.h:372:3: note: 'ThreadSafeAutoRefCnt' has been explicitly marked deleted here
0:13.38 E 372 | ThreadSafeAutoRefCnt(const ThreadSafeAutoRefCnt&) = delete;
0:13.38 E | ^
0:13.38 W In file included from /Users/charlie.humphreys/git/firefox/obj-aarch64-apple-darwin25.4.0/dom/ipc/Unified_cpp_dom_ipc0.cpp:119:
0:13.38 W In file included from /Users/charlie.humphreys/git/firefox/dom/ipc/ContentParent.cpp:142:
0:13.38 E /Users/charlie.humphreys/git/firefox/toolkit/components/glean/FOGTransportParent.h:28:33: error: field of type 'ThreadsafeContentParentHandle' (aka 'mozilla::dom::ThreadsafeContentParentHandle') has private destructor
0:13.38 E 28 | ThreadsafeContentParentHandle mThreadsafeContentParentHandle;
0:13.38 E | ^
0:13.38 E /Users/charlie.humphreys/git/firefox/dom/ipc/ContentParent.h:1710:3: note: declared private here
0:13.38 E 1710 | ~ThreadsafeContentParentHandle() { MOZ_ASSERT(!mWeakActor); }
0:13.38 E | ^
0:14.72 E 2 errors generated. |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 23–26 | |
nika added inline comments. | dom/ipc/ContentParent.cpp |
| 1250–1256 | is a per-process actor, so if you're storing the task queue on as a member, then it will still be per-content-process.
If you want to have a task queue which is global, you need to make it a static, rather than having it on the object. The easiest way is perhaps to add a (e.g. https://searchfox.org/firefox-main/rev/7c07e6f277dd6d5122183d6feecb7473277ab5bb/xpcom/tests/gtest/TestStaticBackgroundTaskQueue.cpp#14-17), which is a helper to declare background task queues which are process global.
This could look something like this:
// in the header
class FOGTransportParent : ... {
...
static already_AddRefed<nsISerialEventTarget> GetQueue();
...
};
// in the .cpp
already_AddRefed<nsISerialEventTarget> FOGTransportParent::GetQueue() {
static StaticBackgroundTaskQueue sQueue("FOGTransportTaskQueue");
return sQueue.Get();
}
// when using it:
nsCOMPtr<nsISerialEventTarget> queue = FOGTransportParent::GetQueue();
...
queue->Dispatch(...); |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 451 | Now that you've dropped the namespace, you can probably also drop the other changes in this file removing prefixes. They're not necessary due to the statement, but it's nice to keep the diff smaller if possible. |
| toolkit/components/glean/ipc/FOGTransportChild.h |
| 17 | FWIW I think that IPDL will already generate a typedef for this on PFOGTransportChild. |
| 29 | FWIW I think that IPDL will already generate a typedef for this on PFOGTransportChild. |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 17 | This is probably already defined with a typedef from . |
| 30 | This should still be a strong reference. My feedback about using a raw pointer was just for the signature of the constructor. |
| 30 | If you're not using it for now, you can probably drop the entirely unless you think you'll want to use it in the near future.
Does Glean actually preserve any information about which process sent the telemetry? My vague understanding is that there is no "process identity" as far as glean is concerned, so the buffers sent here are just blindly replayed onto the global state from the parent process. Is that right? |
| toolkit/components/glean/ipc/PFOGTransport.ipdl |
| 22 | You're missing a newline at end of file. |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 30 | I believe that's correct. In which case I agree, I think we can completely drop that handle. |
nika added inline comments. | dom/ipc/ContentParent.cpp |
| 1254–1255 | If you're not using the threadsafe handle, there's no reason to capture it. |
| 1256–1258 | Let's not have a 0 refcount object sitting around in a local - best practice these days is to use like this. |
| toolkit/components/glean/ipc/FOGTransportParent.h |
| 15–18 | |
nika added inline comments. | toolkit/components/glean/ipc/FOGIPC.cpp |
| 474 | Looks like you still have an extra change here removing |
| 478–480 | Thing which I just noticed, sorry I didn't catch this in an earlier pass:
This patch currently doesn't change the logic such that we're sending the message over the actor. In fact, it will be sent over the normal actor like before.
I think this could have surprising consequences if the FOG transport is turned on, as it means that the flush may not actually have flushed all data (due to different threads being involved). Effectively, now that you're using a second actor, there's nothing guaranteeing that all FOG data messages sent over have arrived & been processed before the response from arrives.
This is complicated even more more by timing. Currently the actor isn't created at all until the first message is ready to be sent by the child, which means that even if we send over the actors, the parent process may have actors which don't have a corresponding actor to send the message over.
Looking at the way that is used, it appears it's used in only the following two ways:
- During testing, to ensure that data is available in the parent before checking what data is stored (https://searchfox.org/firefox-main/rev/4524afcc186654ad357e48fec686249515860ac8/toolkit/components/glean/xpcom/FOG.cpp#392-424), and
- During "idle" events (https://searchfox.org/firefox-main/rev/4524afcc186654ad357e48fec686249515860ac8/toolkit/components/glean/xpcom/FOG.cpp#431-438)
Neither of these appear to be super worried about the edge cases of trying to flush FOG data for a content process which is _extremely_ early during startup, so I would propose the following solution:
- We don't want to wait until the content process is ready to send up to create the actor, instead we probably want to create it early during content process startup, and pass that actor down to the FOGIPC code, so we replace with this:
// FOGTransportChild.h
/**
* Get the singleton FOGTransportChild instance for the current process.
* Returns null if the FOG transport actor either hasn't been created yet, or is disabled.
*/
static FOGTransportChild* GetSingleton();
/**
* Create the FOGTransportActor for the current process, binding it
* to the parent process over the given endpoint.
*/
static void Create(Endpoint<PFOGTransportChild> aEndpoint);
- Now the actor needs to be created manually early during content process startup.
For this, we add some code to early during content process startup, but after IPC has been established. Arbitrarily, I think we could get away with doing the following, but feel free to tweak to something which feels better:
- In the content process, when flushing the FOG transport, check if there is a by checking (you could even do this before checking process type if you wanted), and send the message over the transport singleton if it's available.
- In , replace the direct call with a wrapper which does something like this:
RefPtr<FlushFOGDataPromise> ContentParent::DoFlushFOGData() {
if (mFOGTransport) {
nsCOMPtr<nsISerialEventTarget> queue = glean::FOGTransportParent::GetQueue();
return InvokeAsync(queue, __func__, [transport = RefPtr{mFOGTransport}] {
return transport->SendFlushFOGData();
});
}
return SendFlushFOGData();
} |
| toolkit/components/glean/ipc/FOGTransportChild.cpp |
| 27 | Yeah, the "content process" is our name for the child process which renders web content. |
| toolkit/components/glean/ipc/FOGIPC.cpp |
| 474 | |
| 478–480 | I ended up pairing with @chutten on this and we _think_ we've fully covered what you shared in this comment. Great callout, thank you for the in-depth description of what needed to be done.
If you don't mind double checking our work I think that would be very greatly appreciated. |
| toolkit/components/glean/ipc/FOGTransportChild.cpp |
| 27 | Yep we aren't changing that at the moment, as best I'm aware |
| Path | Size |
|---|
| | 3 lines | | 12 lines | | 7 lines | | 47 lines | | 3 lines | | | 5 lines | | | | | 5 lines | | 6 lines | | | 26 lines | | 46 lines | | 34 lines | | 24 lines | | 21 lines | | 21 lines | | 8 lines | | | 6 lines |
| Commit | Tree | Parents | Author | Summary | Date |
|---|
| bd0e5f6c8ddc | d1a65227e9ad | 960d5e224813 | Charlie Humphreys | Bug 1641989: Add FOGTransport parent/child to replace PContentChild in FOG IPC… (Show More…) | Apr 24 2026, 9:14 PM |
- Thu, Jun 18, 1:35 AM2026-06-18 01:35:53 (UTC+0)
- Thu, Jun 18, 12:33 AM2026-06-18 00:33:25 (UTC+0)
- Wed, Jun 17, 11:21 PM2026-06-17 23:21:18 (UTC+0)
- Wed, Jun 17, 11:11 PM2026-06-17 23:11:41 (UTC+0)
- Wed, Jun 17, 6:40 PM2026-06-17 18:40:08 (UTC+0)
- Wed, Jun 17, 6:10 PM2026-06-17 18:10:55 (UTC+0)
- Wed, Jun 17, 3:27 PM2026-06-17 15:27:31 (UTC+0)
- Wed, Jun 17, 12:31 PM2026-06-17 12:31:14 (UTC+0)
- Wed, Jun 17, 12:21 PM2026-06-17 12:21:50 (UTC+0)
- Wed, Jun 17, 10:46 AM2026-06-17 10:46:24 (UTC+0)
dom/ipc/ContentParent.cppmodules/libpref/init/StaticPrefList.yamltoolkit/components/glean/docs/dev/ipc.mdtoolkit/components/glean/docs/dev/preferences.mdtoolkit/components/glean/ipc/FOGIPC.cpptoolkit/components/glean/ipc/FOGTransportChild.htoolkit/components/glean/ipc/FOGTransportChild.cpptoolkit/components/glean/ipc/FOGTransportParent.htoolkit/components/glean/ipc/FOGTransportParent.cpptoolkit/components/glean/ipc/PFOGTransport.ipdltoolkit/components/glean/moz.buildtoolkit/components/nimbus/FeatureManifest.yaml |