Bug 1216972 - AsyncShutdown for content processes. r=froydnj, a=ritu
--- a/toolkit/components/asyncshutdown/AsyncShutdown.jsm
+++ b/toolkit/components/asyncshutdown/AsyncShutdown.jsm
@@ -61,16 +61,22 @@ Object.defineProperty(this, "gCrashRepor
return this.gCrashReporter = reporter;
} catch (ex) {
return this.gCrashReporter = null;
}
},
configurable: true
});
+// `true` if this is a content process, `false` otherwise.
+// It would be nicer to go through `Services.appInfo`, but some tests need to be
+// able to replace that field with a custom implementation before it is first
+// called.
+const isContent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
+
// Display timeout warnings after 10 seconds
const DELAY_WARNING_MS = 10 * 1000;
// Crash the process if shutdown is really too long
// (allowing for sleep).
const PREF_DELAY_CRASH_MS = "toolkit.asyncshutdown.crash_timeout";
var DELAY_CRASH_MS = 60 * 1000; // One minute
@@ -974,18 +980,29 @@ Barrier.prototype = Object.freeze({
// List of well-known phases
// Ideally, phases should be registered from the component that decides
// when they start/stop. For compatibility with existing startup/shutdown
// mechanisms, we register a few phases here.
-this.AsyncShutdown.profileChangeTeardown = getPhase("profile-change-teardown");
-this.AsyncShutdown.profileBeforeChange = getPhase("profile-before-change");
-this.AsyncShutdown.placesClosingInternalConnection = getPhase("places-will-close-connection");
-this.AsyncShutdown.sendTelemetry = getPhase("profile-before-change2");
+// Parent process
+if (!isContent) {
+ this.AsyncShutdown.profileChangeTeardown = getPhase("profile-change-teardown");
+ this.AsyncShutdown.profileBeforeChange = getPhase("profile-before-change");
+ this.AsyncShutdown.placesClosingInternalConnection = getPhase("places-will-close-connection");
+ this.AsyncShutdown.sendTelemetry = getPhase("profile-before-change2");
+}
+
+
+// Content process
+if (isContent) {
+ this.AsyncShutdown.contentChildShutdown = getPhase("content-child-shutdown");
+}
+
+// All processes
this.AsyncShutdown.webWorkersShutdown = getPhase("web-workers-shutdown");
this.AsyncShutdown.xpcomThreadsShutdown = getPhase("xpcom-threads-shutdown");
this.AsyncShutdown.Barrier = Barrier;
Object.freeze(this.AsyncShutdown);
--- a/toolkit/components/asyncshutdown/nsAsyncShutdown.js
+++ b/toolkit/components/asyncshutdown/nsAsyncShutdown.js
@@ -221,27 +221,35 @@ nsAsyncShutdownBarrier.prototype = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAsyncShutdownBarrier]),
classID: Components.ID("{29a0e8b5-9111-4c09-a0eb-76cd02bf20fa}"),
};
function nsAsyncShutdownService() {
// Cache for the getters
for (let _k of
- ["profileBeforeChange",
+ [// Parent process
+ "profileBeforeChange",
"profileChangeTeardown",
"sendTelemetry",
+
+ // Child processes
+ "contentChildShutdown",
+
+ // All processes
"webWorkersShutdown",
- "xpcomThreadsShutdown"]) {
+ "xpcomThreadsShutdown",
+ ]) {
let k = _k;
Object.defineProperty(this, k, {
configurable: true,
get: function() {
delete this[k];
- let result = new nsAsyncShutdownClient(AsyncShutdown[k]);
+ let wrapped = AsyncShutdown[k]; // May be undefined, if we're on the wrong process.
+ let result = wrapped ? new nsAsyncShutdownClient(wrapped) : undefined;
Object.defineProperty(this, k, {
value: result
});
return result;
}
});
}
@@ -261,9 +269,8 @@ nsAsyncShutdownService.prototype = {
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
nsAsyncShutdownService,
nsAsyncShutdownBarrier,
nsAsyncShutdownClient,
]);
-
--- a/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl
+++ b/toolkit/components/asyncshutdown/nsIAsyncShutdown.idl
@@ -155,53 +155,61 @@ interface nsIAsyncShutdownBarrier: nsISu
* The callback always receives NS_OK.
*/
void wait(in nsIAsyncShutdownCompletionCallback aOnReady);
};
/**
* A service that allows registering shutdown-time dependencies.
*/
-[scriptable, uuid(8a9a0859-0404-4d50-9e76-10a4f56dfb51)]
+[scriptable, uuid(10f51032-dcc9-4732-bec0-c0b7d6596622)]
interface nsIAsyncShutdownService: nsISupports {
/**
* Create a new barrier.
*
* By convention, the name should respect the following format:
* "MyModuleName: Doing something while it's time"
* e.g.
* "OS.File: Waiting for clients to flush before shutting down"
*
* This attribute is uploaded as part of crash reports.
*/
nsIAsyncShutdownBarrier makeBarrier(in AString aName);
- // Barriers for global shutdown stages
+
+ // Barriers for global shutdown stages in the parent process.
/**
* Barrier for notification profile-before-change.
*/
readonly attribute nsIAsyncShutdownClient profileBeforeChange;
/**
* Barrier for notification profile-change-teardown.
*/
readonly attribute nsIAsyncShutdownClient profileChangeTeardown;
/**
* Barrier for notification profile-before-change2.
*/
readonly attribute nsIAsyncShutdownClient sendTelemetry;
+ // Barriers for global shutdown stages in the content processes.
+
+ readonly attribute nsIAsyncShutdownClient contentChildShutdown;
+
+ // Barriers for global shutdown stages in all processes.
+
/**
* Barrier for notification web-workers-shutdown.
*/
readonly attribute nsIAsyncShutdownClient webWorkersShutdown;
/**
* Barrier for notification xpcom-threads-shutdown.
*/
readonly attribute nsIAsyncShutdownClient xpcomThreadsShutdown;
+
};
%{C++
#define NS_ASYNCSHUTDOWNSERVICE_CONTRACTID "@mozilla.org/async-shutdown-service;1"
%}