Bug 1854550 - pt 2. Move PHC into memory/build r=glandium
[gecko.git] / remote / cdp / CDP.sys.mjs
blob0307c7114905c7a16cae11fa678fb15e59276204
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   // Accept all cookies (see behavior definitions in nsICookieService.idl)
30   ["network.cookie.cookieBehavior", 0],
31 ]);
33 /**
34  * Entry class for the Chrome DevTools Protocol support.
35  *
36  * It holds the list of available targets (tabs, main browser), and also
37  * sets up the necessary handlers for the HTTP server.
38  *
39  * @see https://chromedevtools.github.io/devtools-protocol
40  */
41 export class CDP {
42   /**
43    * Creates a new instance of the CDP class.
44    *
45    * @param {RemoteAgent} agent
46    *     Reference to the Remote Agent instance.
47    */
48   constructor(agent) {
49     this.agent = agent;
50     this.targetList = null;
52     this._running = false;
53     this._activePortPath;
54   }
56   get address() {
57     const mainTarget = this.targetList.getMainProcessTarget();
58     return mainTarget.wsDebuggerURL;
59   }
61   get mainTargetPath() {
62     const mainTarget = this.targetList.getMainProcessTarget();
63     return mainTarget.path;
64   }
66   /**
67    * Starts the CDP support.
68    */
69   async start() {
70     if (this._running) {
71       return;
72     }
74     // Note: Ideally this would only be set at the end of the method. However
75     // since start() is async, we prefer to set the flag early in order to
76     // avoid potential race conditions.
77     this._running = true;
79     lazy.RecommendedPreferences.applyPreferences(RECOMMENDED_PREFS);
81     // Starting CDP too early can cause issues with clients in not being able
82     // to find any available target. Also when closing the application while
83     // it's still starting up can cause shutdown hangs. As such CDP will be
84     // started when the initial application window has finished initializing.
85     lazy.logger.debug(`Waiting for initial application window`);
86     await this.agent.browserStartupFinished;
88     this.agent.server.registerPrefixHandler("/", new lazy.JSONHandler(this));
90     this.targetList = new lazy.TargetList();
91     this.targetList.on("target-created", (eventName, target) => {
92       this.agent.server.registerPathHandler(target.path, target);
93     });
94     this.targetList.on("target-destroyed", (eventName, target) => {
95       this.agent.server.registerPathHandler(target.path, null);
96     });
98     await this.targetList.watchForTargets();
100     Cu.printStderr(`DevTools listening on ${this.address}\n`);
102     // Write connection details to DevToolsActivePort file within the profile.
103     this._activePortPath = PathUtils.join(
104       PathUtils.profileDir,
105       "DevToolsActivePort"
106     );
108     const data = `${this.agent.port}\n${this.mainTargetPath}`;
109     try {
110       await IOUtils.write(this._activePortPath, lazy.textEncoder.encode(data));
111     } catch (e) {
112       lazy.logger.warn(
113         `Failed to create ${this._activePortPath} (${e.message})`
114       );
115     }
116   }
118   /**
119    * Stops the CDP support.
120    */
121   async stop() {
122     if (!this._running) {
123       return;
124     }
126     try {
127       await IOUtils.remove(this._activePortPath);
128     } catch (e) {
129       lazy.logger.warn(
130         `Failed to remove ${this._activePortPath} (${e.message})`
131       );
132     }
134     try {
135       this.targetList?.destructor();
136       this.targetList = null;
138       lazy.RecommendedPreferences.restorePreferences(RECOMMENDED_PREFS);
139     } catch (e) {
140       lazy.logger.error("Failed to stop protocol", e);
141     } finally {
142       this._running = false;
143     }
144   }