Bug 1885602 - Part 4: Implement navigating to the settings from the menu header for...
[gecko.git] / remote / cdp / CDP.sys.mjs
blobcd9aedfecc65f279babab4a1663ec2d734a99707
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const lazy = {};
7 ChromeUtils.defineESModuleGetters(lazy, {
8   JSONHandler: "chrome://remote/content/cdp/JSONHandler.sys.mjs",
9   Log: "chrome://remote/content/shared/Log.sys.mjs",
10   RecommendedPreferences:
11     "chrome://remote/content/shared/RecommendedPreferences.sys.mjs",
12   TargetList: "chrome://remote/content/cdp/targets/TargetList.sys.mjs",
13 });
15 ChromeUtils.defineLazyGetter(lazy, "logger", () =>
16   lazy.Log.get(lazy.Log.TYPES.CDP)
18 ChromeUtils.defineLazyGetter(lazy, "textEncoder", () => new TextEncoder());
20 // Map of CDP-specific preferences that should be set via
21 // RecommendedPreferences.
22 const RECOMMENDED_PREFS = new Map([
23   // Prevent various error message on the console
24   // jest-puppeteer asserts that no error message is emitted by the console
25   [
26     "browser.contentblocking.features.standard",
27     "-tp,tpPrivate,cookieBehavior0,-cm,-fp",
28   ],
29 ]);
31 /**
32  * Entry class for the Chrome DevTools Protocol support.
33  *
34  * It holds the list of available targets (tabs, main browser), and also
35  * sets up the necessary handlers for the HTTP server.
36  *
37  * @see https://chromedevtools.github.io/devtools-protocol
38  */
39 export class CDP {
40   /**
41    * Creates a new instance of the CDP class.
42    *
43    * @param {RemoteAgent} agent
44    *     Reference to the Remote Agent instance.
45    */
46   constructor(agent) {
47     this.agent = agent;
48     this.targetList = null;
50     this._running = false;
51     this._activePortPath;
52   }
54   get address() {
55     const mainTarget = this.targetList.getMainProcessTarget();
56     return mainTarget.wsDebuggerURL;
57   }
59   get mainTargetPath() {
60     const mainTarget = this.targetList.getMainProcessTarget();
61     return mainTarget.path;
62   }
64   /**
65    * Starts the CDP support.
66    */
67   async start() {
68     if (this._running) {
69       return;
70     }
72     // Note: Ideally this would only be set at the end of the method. However
73     // since start() is async, we prefer to set the flag early in order to
74     // avoid potential race conditions.
75     this._running = true;
77     lazy.RecommendedPreferences.applyPreferences(RECOMMENDED_PREFS);
79     // Starting CDP too early can cause issues with clients in not being able
80     // to find any available target. Also when closing the application while
81     // it's still starting up can cause shutdown hangs. As such CDP will be
82     // started when the initial application window has finished initializing.
83     lazy.logger.debug(`Waiting for initial application window`);
84     await this.agent.browserStartupFinished;
86     this.agent.server.registerPrefixHandler("/", new lazy.JSONHandler(this));
88     this.targetList = new lazy.TargetList();
89     this.targetList.on("target-created", (eventName, target) => {
90       this.agent.server.registerPathHandler(target.path, target);
91     });
92     this.targetList.on("target-destroyed", (eventName, target) => {
93       this.agent.server.registerPathHandler(target.path, null);
94     });
96     await this.targetList.watchForTargets();
98     Cu.printStderr(`DevTools listening on ${this.address}\n`);
100     // Write connection details to DevToolsActivePort file within the profile.
101     this._activePortPath = PathUtils.join(
102       PathUtils.profileDir,
103       "DevToolsActivePort"
104     );
106     const data = `${this.agent.port}\n${this.mainTargetPath}`;
107     try {
108       await IOUtils.write(this._activePortPath, lazy.textEncoder.encode(data));
109     } catch (e) {
110       lazy.logger.warn(
111         `Failed to create ${this._activePortPath} (${e.message})`
112       );
113     }
114   }
116   /**
117    * Stops the CDP support.
118    */
119   async stop() {
120     if (!this._running) {
121       return;
122     }
124     try {
125       await IOUtils.remove(this._activePortPath);
126     } catch (e) {
127       lazy.logger.warn(
128         `Failed to remove ${this._activePortPath} (${e.message})`
129       );
130     }
132     try {
133       this.targetList?.destructor();
134       this.targetList = null;
136       lazy.RecommendedPreferences.restorePreferences(RECOMMENDED_PREFS);
137     } catch (e) {
138       lazy.logger.error("Failed to stop protocol", e);
139     } finally {
140       this._running = false;
141     }
142   }