+= ("0" + hashBin.charCodeAt(i).toString(16)).slice(-2); } return hash; } catch (e) { console.error(e); return null; } })(); } export var CrashServiceUtils = { computeMinidumpHash: async function CrashServiceUtils_computeMinidumpHash(f) { return computeMinidumpHash(f); }, }; /** * Process the given .extra file and return the annotations it contains in an * object. * * @param extraPath {string} The path to the .extra file * * @return {Promise} A promise that resolves to an object holding the crash * annotations. */ function processExtraFile(extraPath) { return (async function () { try { let decoder = new TextDecoder(); let extraData = await IOUtils.read(extraPath); return JSON.parse(decoder.decode(extraData)); } catch (e) { console.error(e); return {}; } })(); } /** * This component makes crash data available throughout the application. * * It is a service because some background activity will eventually occur. */ export function CrashService() { Services.obs.addObserver(this, "quit-application"); } CrashService.prototype = Object.freeze({ classID: Components.ID("{92668367-1b17-4190-86b2-1061b2179744}"), QueryInterface: ChromeUtils.generateQI(["nsICrashService", "nsIObserver"]), async addCrash(processType, crashType, id) { if (processType === Ci.nsIXULRuntime.PROCESS_TYPE_IPDLUNITTEST) { return; } processType = Services.crashmanager.processTypes[processType]; let allThreads = false; switch (crashType) { case Ci.nsICrashService.CRASH_TYPE_CRASH: crashType = Services.crashmanager.CRASH_TYPE_CRASH; break; case Ci.nsICrashService.CRASH_TYPE_HANG: crashType = Services.crashmanager.CRASH_TYPE_HANG; allThreads = true; break; default: throw new Error("Unrecognized CRASH_TYPE: " + crashType); } let minidumpPath = Services.appinfo.getMinidumpForID(id).path; let extraPath = Services.appinfo.getExtraFileForID(id).path; let metadata = {}; let hash = null; await maybeRunMinidumpAnalyzer(minidumpPath, allThreads); metadata = await processExtraFile(extraPath); hash = await computeMinidumpHash(minidumpPath); if (hash) { metadata.MinidumpSha256Hash = hash; } let blocker = Services.crashmanager.addCrash( processType, crashType, id, new Date(), metadata ); AsyncShutdown.profileBeforeChange.addBlocker( "CrashService waiting for content crash ping to be sent", blocker ); blocker.then(AsyncShutdown.profileBeforeChange.removeBlocker(blocker)); await blocker; }, observe(subject, topic) { switch (topic) { case "profile-after-change": // Side-effect is the singleton is instantiated. Services.crashmanager; break; case "quit-application": gQuitting = true; gRunningProcesses.forEach(process => { try { process.kill(); } catch (e) { // If the process has already quit then kill() fails, but since // this failure is benign it is safe to silently ignore it. } Services.obs.notifyObservers(null, "test-minidump-analyzer-killed"); }); break; } }, }); PK