commit df5ae350decc3b64eacb6a44cd7f095d9b003434
parent b224e97d13d9a4965f963f53e5823a4c019aa445
Author: Julian Descottes <jdescottes@mozilla.com>
Date: Tue, 28 Oct 2025 09:11:28 +0000
Bug 1979731 - [remote] Expose events from UserContextManager r=Sasha
The side effect of this change is that UUID of the user context is no longer found in the name of that user context. I initially did this to make it easier to debug, but in the end I don't think we rely much on the user context name, so as long as it is unique it should be fine.
Differential Revision: https://phabricator.services.mozilla.com/D270214
Diffstat:
2 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/remote/shared/UserContextManager.sys.mjs b/remote/shared/UserContextManager.sys.mjs
@@ -7,6 +7,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ContextualIdentityService:
"resource://gre/modules/ContextualIdentityService.sys.mjs",
+ EventEmitter: "resource://gre/modules/EventEmitter.sys.mjs",
ContextualIdentityListener:
"chrome://remote/content/shared/listeners/ContextualIdentityListener.sys.mjs",
@@ -23,12 +24,21 @@ const DEFAULT_INTERNAL_ID = 0;
*
* This class is exported for test purposes. Otherwise the UserContextManager
* singleton should be used.
+ *
+ * @fires user-context-created
+ * - {string} userContextId
+ * The UUID of the user context which was just created.
+ * @fires user-context-deleted
+ * - {string} userContextId
+ * The UUID of the user context which was just deleted.
*/
export class UserContextManagerClass {
#contextualIdentityListener;
#userContextIds;
constructor() {
+ lazy.EventEmitter.decorate(this);
+
// Map from internal ids (numbers) from the ContextualIdentityService to
// opaque UUIDs (string).
this.#userContextIds = new Map();
@@ -76,19 +86,14 @@ export class UserContextManagerClass {
* The user context id of the new user context.
*/
createContext(prefix = "remote") {
- // Prepare the opaque id and name beforehand.
- const userContextId = lazy.generateUUID();
- const name = `${prefix}-${userContextId}`;
+ // Prepare a unique name.
+ const name = `${prefix}-${lazy.generateUUID()}`;
// Create the user context.
const identity = lazy.ContextualIdentityService.create(name);
- const internalId = identity.userContextId;
// An id has been set already by the contextual-identity-created observer.
- // Override it with `userContextId` to match the container name.
- this.#userContextIds.set(internalId, userContextId);
-
- return userContextId;
+ return this.#userContextIds.get(identity.userContextId);
}
/**
@@ -226,13 +231,15 @@ export class UserContextManagerClass {
};
#onIdentityDeleted = (eventName, data) => {
+ const userContextId = this.#userContextIds.get(data.identity.userContextId);
this.#userContextIds.delete(data.identity.userContextId);
+ this.emit("user-context-deleted", { userContextId });
};
#registerIdentity(identity) {
- // Note: the id for identities created via UserContextManagerClass.createContext
- // are overridden in createContext.
- this.#userContextIds.set(identity.userContextId, lazy.generateUUID());
+ const userContextId = lazy.generateUUID();
+ this.#userContextIds.set(identity.userContextId, userContextId);
+ this.emit("user-context-created", { userContextId });
}
}
diff --git a/remote/shared/test/browser/browser_UserContextManager.js b/remote/shared/test/browser/browser_UserContextManager.js
@@ -142,6 +142,30 @@ add_task(async function test_create_context_prefix() {
userContextManager.destroy();
});
+add_task(async function test_events() {
+ const manager = new UserContextManagerClass();
+ const userContextCreatedEvents = [];
+ const userContextDeletedEvents = [];
+ manager.on("user-context-created", (name, data) =>
+ userContextCreatedEvents.push(data)
+ );
+ manager.on("user-context-deleted", (name, data) =>
+ userContextDeletedEvents.push(data)
+ );
+
+ const contextId1 = manager.createContext();
+ is(userContextCreatedEvents.length, 1);
+ is(userContextCreatedEvents[0].userContextId, contextId1);
+ is(userContextDeletedEvents.length, 0);
+
+ manager.removeUserContext(contextId1);
+ is(userContextCreatedEvents.length, 1);
+ is(userContextDeletedEvents.length, 1);
+ is(userContextDeletedEvents[0].userContextId, contextId1);
+
+ manager.destroy();
+});
+
add_task(async function test_several_managers() {
const manager1 = new UserContextManagerClass();
const manager2 = new UserContextManagerClass();