recording-utils.sys.mjs (2750B)
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/. */ 4 // @ts-check 5 6 /** 7 * @typedef {import("perf").GetActiveBrowserID} GetActiveBrowserID 8 * @typedef {import("perf").ProfileCaptureResult} ProfileCaptureResult 9 */ 10 11 /** 12 * Gets the ID of active tab from the browser. 13 * 14 * @type {GetActiveBrowserID} 15 */ 16 export function getActiveBrowserID() { 17 const win = Services.wm.getMostRecentBrowserWindow(); 18 19 const browserId = win?.gBrowser?.selectedBrowser?.browsingContext?.browserId; 20 if (browserId) { 21 return browserId; 22 } 23 24 console.error( 25 "Failed to get the active browserId while starting the profiler." 26 ); 27 // `0` mean that we failed to ge the active browserId, and it's 28 // treated as null value in the platform. 29 return 0; 30 } 31 32 /** 33 * @typedef {object} ProfileCaptureResultAndAdditionalInformation 34 * @property {ProfileCaptureResult} profileCaptureResult 35 * @property {MockedExports.ProfileGenerationAdditionalInformation} [additionalInformation] 36 */ 37 /** 38 * Fetch the profile data from Firefox, then stop the profiler. 39 * 40 * @returns {Promise<ProfileCaptureResultAndAdditionalInformation>} 41 */ 42 export async function getProfileDataAsGzippedArrayBufferThenStop() { 43 if (!Services.profiler.IsActive()) { 44 // The profiler is not active, ignore. 45 return { 46 profileCaptureResult: { 47 type: "ERROR", 48 error: new Error("The profiler is not active."), 49 }, 50 }; 51 } 52 if (Services.profiler.IsPaused()) { 53 // The profiler is already paused for capture, ignore. 54 return { 55 profileCaptureResult: { 56 type: "ERROR", 57 error: new Error("The profiler is already paused."), 58 }, 59 }; 60 } 61 62 // Pause profiler before we collect the profile, so that we don't capture 63 // more samples while the parent process waits for subprocess profiles. 64 Services.profiler.Pause(); 65 66 try { 67 const { profile, additionalInformation } = 68 await Services.profiler.getProfileDataAsGzippedArrayBuffer(); 69 70 return { 71 profileCaptureResult: { type: "SUCCESS", profile }, 72 additionalInformation, 73 }; 74 } catch (unknownError) { 75 const error = /** @type {Error} */ (unknownError); 76 return { profileCaptureResult: { type: "ERROR", error } }; 77 } finally { 78 // We're purposefully not using `await`, to minimize the time the user has 79 // to wait until the result is returned. 80 Services.profiler.StopProfiler(); 81 } 82 } 83 84 // This file also exports a named object containing other exports to play well 85 // with defineESModuleGetters. 86 export const RecordingUtils = { 87 getActiveBrowserID, 88 getProfileDataAsGzippedArrayBufferThenStop, 89 };