mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1166207 - Load preload.js in the Nuwa process. r=khuey
--HG-- extra : rebase_source : 292c5e5dbee5fa49a78fd1997d97094ef2190143
This commit is contained in:
parent
1f8f5b63b0
commit
3c09a9761d
@ -1757,4 +1757,13 @@ BrowserElementChild.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
var api = new BrowserElementChild();
|
||||
var api = null;
|
||||
if ('DoPreloadPostfork' in this && typeof this.DoPreloadPostfork === 'function') {
|
||||
// If we are preloaded, instantiate BrowserElementChild after a content
|
||||
// process is forked.
|
||||
this.DoPreloadPostfork(function() {
|
||||
api = new BrowserElementChild();
|
||||
});
|
||||
} else {
|
||||
api = new BrowserElementChild();
|
||||
}
|
||||
|
@ -2291,11 +2291,7 @@ ContentChild::RecvAppInit()
|
||||
// PreloadSlowThings() may set the docshell of the first TabChild
|
||||
// inactive, and we can only safely restore it to active from
|
||||
// BrowserElementChild.js.
|
||||
if ((mIsForApp || mIsForBrowser)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
&& !IsNuwaProcess()
|
||||
#endif
|
||||
) {
|
||||
if (mIsForApp || mIsForBrowser) {
|
||||
PreloadSlowThings();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include "mozilla/plugins/PluginWidgetChild.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "mozilla/layers/APZCTreeManager.h"
|
||||
@ -450,10 +453,67 @@ TabChild::FindTabChild(const TabId& aTabId)
|
||||
return tabChild.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
PreloadSlowThingsPostFork(void* aUnused)
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
observerService->NotifyObservers(nullptr, "preload-postfork", nullptr);
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
class MessageChannelAutoBlock MOZ_STACK_CLASS
|
||||
{
|
||||
public:
|
||||
MessageChannelAutoBlock()
|
||||
{
|
||||
SetMessageChannelBlocked(true);
|
||||
}
|
||||
|
||||
~MessageChannelAutoBlock()
|
||||
{
|
||||
SetMessageChannelBlocked(false);
|
||||
}
|
||||
|
||||
private:
|
||||
void SetMessageChannelBlocked(bool aBlock)
|
||||
{
|
||||
if (!IsNuwaProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::dom::ContentChild* content =
|
||||
mozilla::dom::ContentChild::GetSingleton();
|
||||
if (aBlock) {
|
||||
content->GetIPCChannel()->Block();
|
||||
} else {
|
||||
content->GetIPCChannel()->Unblock();
|
||||
}
|
||||
|
||||
nsTArray<IToplevelProtocol*> actors;
|
||||
content->GetOpenedActors(actors);
|
||||
for (size_t j = 0; j < actors.Length(); j++) {
|
||||
IToplevelProtocol* actor = actors[j];
|
||||
if (aBlock) {
|
||||
actor->GetIPCChannel()->Block();
|
||||
} else {
|
||||
actor->GetIPCChannel()->Unblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
static bool sPreloaded = false;
|
||||
|
||||
/*static*/ void
|
||||
TabChild::PreloadSlowThings()
|
||||
{
|
||||
MOZ_ASSERT(!sPreallocatedTab);
|
||||
if (sPreloaded) {
|
||||
// If we are alredy initialized in Nuwa, don't redo preloading.
|
||||
return;
|
||||
}
|
||||
sPreloaded = true;
|
||||
|
||||
// Pass nullptr to aManager since at this point the TabChild is
|
||||
// not connected to any manager. Any attempt to use the TabChild
|
||||
@ -465,6 +525,13 @@ TabChild::PreloadSlowThings()
|
||||
!tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Temporarily block the IPC channels to the chrome process when we are
|
||||
// preloading.
|
||||
MessageChannelAutoBlock autoblock;
|
||||
#endif
|
||||
|
||||
// Just load and compile these scripts, but don't run them.
|
||||
tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
|
||||
// Load, compile, and run these scripts.
|
||||
@ -472,6 +539,16 @@ TabChild::PreloadSlowThings()
|
||||
NS_LITERAL_STRING("chrome://global/content/preload.js"),
|
||||
true);
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NuwaAddFinalConstructor(PreloadSlowThingsPostFork, nullptr);
|
||||
} else {
|
||||
PreloadSlowThingsPostFork(nullptr);
|
||||
}
|
||||
#else
|
||||
PreloadSlowThingsPostFork(nullptr);
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(tab->WebNavigation());
|
||||
if (nsIPresShell* presShell = docShell->GetPresShell()) {
|
||||
// Initialize and do an initial reflow of the about:blank
|
||||
|
@ -9,6 +9,17 @@
|
||||
|
||||
const BrowserElementIsPreloaded = true;
|
||||
|
||||
const DoPreloadPostfork = function(aCallback) {
|
||||
Services.obs.addObserver({
|
||||
_callback: aCallback,
|
||||
|
||||
observe: function() {
|
||||
this._callback();
|
||||
Services.obs.removeObserver(this, "preload-postfork");
|
||||
}
|
||||
}, "preload-postfork", false);
|
||||
};
|
||||
|
||||
(function (global) {
|
||||
"use strict";
|
||||
|
||||
@ -16,7 +27,6 @@ const BrowserElementIsPreloaded = true;
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
@ -30,12 +40,10 @@ const BrowserElementIsPreloaded = true;
|
||||
|
||||
Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci["nsIAppShellService"]);
|
||||
Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci["nsIWindowMediator"]);
|
||||
Cc["@mozilla.org/AppsService;1"].getService(Ci["nsIAppsService"]);
|
||||
Cc["@mozilla.org/base/telemetry;1"].getService(Ci["nsITelemetry"]);
|
||||
Cc["@mozilla.org/categorymanager;1"].getService(Ci["nsICategoryManager"]);
|
||||
Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci["nsIMessageSender"]);
|
||||
Cc["@mozilla.org/consoleservice;1"].getService(Ci["nsIConsoleService"]);
|
||||
Cc["@mozilla.org/cookieService;1"].getService(Ci["nsICookieService"]);
|
||||
Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci["nsIURIFixup"]);
|
||||
Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci["nsIDOMRequestService"]);
|
||||
Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci["nsIPromptService"]);
|
||||
@ -53,14 +61,12 @@ const BrowserElementIsPreloaded = true;
|
||||
Cc["@mozilla.org/network/idn-service;1"].getService(Ci["nsIIDNService"]);
|
||||
Cc["@mozilla.org/network/io-service;1"].getService(Ci["nsIIOService2"]);
|
||||
Cc["@mozilla.org/network/mime-hdrparam;1"].getService(Ci["nsIMIMEHeaderParam"]);
|
||||
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
|
||||
Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci["nsISocketTransportService"]);
|
||||
Cc["@mozilla.org/network/stream-transport-service;1"].getService(Ci["nsIStreamTransportService"]);
|
||||
Cc["@mozilla.org/network/url-parser;1?auth=maybe"].getService(Ci["nsIURLParser"]);
|
||||
Cc["@mozilla.org/network/url-parser;1?auth=no"].getService(Ci["nsIURLParser"]);
|
||||
Cc["@mozilla.org/network/url-parser;1?auth=yes"].getService(Ci["nsIURLParser"]);
|
||||
Cc["@mozilla.org/observer-service;1"].getService(Ci["nsIObserverService"]);
|
||||
Cc["@mozilla.org/permissionmanager;1"].getService(Ci["nsIPermissionManager"]);
|
||||
Cc["@mozilla.org/preferences-service;1"].getService(Ci["nsIPrefBranch"]);
|
||||
Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci["nsIScriptSecurityManager"]);
|
||||
Cc["@mozilla.org/storage/service;1"].getService(Ci["mozIStorageService"]);
|
||||
@ -70,7 +76,6 @@ const BrowserElementIsPreloaded = true;
|
||||
Cc["@mozilla.org/uriloader;1"].getService(Ci["nsIURILoader"]);
|
||||
Cc["@mozilla.org/cspcontext;1"].createInstance(Ci["nsIContentSecurityPolicy"]);
|
||||
Cc["@mozilla.org/settingsManager;1"].createInstance(Ci["nsISupports"]);
|
||||
Cc["@mozilla.org/webapps;1"].createInstance(Ci["nsISupports"]);
|
||||
|
||||
/* Applications Specific Helper */
|
||||
try {
|
||||
@ -104,7 +109,44 @@ const BrowserElementIsPreloaded = true;
|
||||
Services.io.getProtocolHandler("app");
|
||||
Services.io.getProtocolHandler("default");
|
||||
|
||||
docShell.isActive = false;
|
||||
docShell.createAboutBlankContentViewer(null);
|
||||
// Register an observer for topic "preload_postfork" after we fork a content
|
||||
// process.
|
||||
DoPreloadPostfork(function () {
|
||||
// Load AppsServiceChild.jsm after fork since it sends an async message to
|
||||
// the chrome process in its init() function.
|
||||
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
|
||||
|
||||
// Load UserCustomizations.jsm after fork since it sends an async message to
|
||||
// the chrome process in its init() function.
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("dom.apps.customization.enabled")) {
|
||||
Cu.import("resource://gre/modules/UserCustomizations.jsm");
|
||||
}
|
||||
} catch(e) {}
|
||||
|
||||
// Load nsIAppsService after fork since its implementation loads
|
||||
// AppsServiceChild.jsm
|
||||
Cc["@mozilla.org/AppsService;1"].getService(Ci["nsIAppsService"]);
|
||||
|
||||
// Load nsICookieService after fork since it sends an IPC constructor
|
||||
// message to the chrome process.
|
||||
Cc["@mozilla.org/cookieService;1"].getService(Ci["nsICookieService"]);
|
||||
|
||||
// Load nsIPermissionManager after fork since it sends a message to the
|
||||
// chrome process to read permissions.
|
||||
Cc["@mozilla.org/permissionmanager;1"].getService(Ci["nsIPermissionManager"]);
|
||||
|
||||
// Create this instance after fork since it loads AppsServiceChild.jsm
|
||||
Cc["@mozilla.org/webapps;1"].createInstance(Ci["nsISupports"]);
|
||||
|
||||
// Load nsIProtocolProxyService after fork since it asynchronously accesses
|
||||
// the "Proxy Resolution" thread after it's frozen.
|
||||
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
|
||||
|
||||
// Call docShell.createAboutBlankContentViewer() after fork since it has IPC
|
||||
// activity in the PCompositor protocol.
|
||||
docShell.createAboutBlankContentViewer(null);
|
||||
docShell.isActive = false;
|
||||
});
|
||||
})(this);
|
||||
|
||||
|
@ -175,6 +175,16 @@ class MessageChannel : HasResultCodes
|
||||
sIsPumpingMessages = aIsPumping;
|
||||
}
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
void Block() {
|
||||
mLink->Block();
|
||||
}
|
||||
|
||||
void Unblock() {
|
||||
mLink->Unblock();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OS_WIN
|
||||
struct MOZ_STACK_CLASS SyncStackFrame
|
||||
{
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/PNuwa.h"
|
||||
#include "mozilla/hal_sandbox/PHal.h"
|
||||
#if defined(DEBUG) || defined(ENABLE_TESTS)
|
||||
#include "jsprf.h"
|
||||
extern "C" char* PrintJSStack();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
@ -75,6 +79,7 @@ ProcessLink::ProcessLink(MessageChannel *aChan)
|
||||
, mExistingListener(nullptr)
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
, mIsToNuwaProcess(false)
|
||||
, mIsBlocked(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
@ -175,6 +180,8 @@ ProcessLink::SendMessage(Message *msg)
|
||||
mChan->mMonitor->AssertCurrentThreadOwns();
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// Parent to child: check whether we are sending some unexpected message to
|
||||
// the Nuwa process.
|
||||
if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
|
||||
switch (msg->type()) {
|
||||
case mozilla::dom::PNuwa::Msg_Fork__ID:
|
||||
@ -193,6 +200,19 @@ ProcessLink::SendMessage(Message *msg)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Nuwa to parent: check whether we are currently blocked.
|
||||
if (IsNuwaProcess() && mIsBlocked) {
|
||||
#if defined(ENABLE_TESTS) || defined(DEBUG)
|
||||
char* jsstack = PrintJSStack();
|
||||
printf_stderr("Fatal error: sending a message to the chrome process"
|
||||
"with a blocked IPC channel from \n%s",
|
||||
jsstack ? jsstack : "<no JS stack>");
|
||||
JS_smprintf_free(jsstack);
|
||||
MOZ_CRASH();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
mIOLoop->PostTask(
|
||||
|
@ -128,6 +128,12 @@ class MessageLink
|
||||
virtual bool Unsound_IsClosed() const = 0;
|
||||
virtual uint32_t Unsound_NumQueuedMessages() const = 0;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// To be overridden by ProcessLink.
|
||||
virtual void Block() {}
|
||||
virtual void Unblock() {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
MessageChannel *mChan;
|
||||
};
|
||||
@ -175,12 +181,22 @@ class ProcessLink
|
||||
virtual bool Unsound_IsClosed() const override;
|
||||
virtual uint32_t Unsound_NumQueuedMessages() const override;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
void Block() override {
|
||||
mIsBlocked = true;
|
||||
}
|
||||
void Unblock() override {
|
||||
mIsBlocked = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Transport* mTransport;
|
||||
MessageLoop* mIOLoop; // thread where IO happens
|
||||
Transport::Listener* mExistingListener; // channel's previous listener
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
bool mIsToNuwaProcess;
|
||||
bool mIsBlocked;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -235,6 +235,8 @@ public:
|
||||
|
||||
void GetOpenedActors(nsTArray<IToplevelProtocol*>& aActors);
|
||||
|
||||
virtual MessageChannel* GetIPCChannel() = 0;
|
||||
|
||||
// This Unsafe version should only be used when all other threads are
|
||||
// frozen, since it performs no locking. It also takes a stack-allocated
|
||||
// array and its size (number of elements) rather than an nsTArray. The Nuwa
|
||||
|
@ -2077,4 +2077,28 @@ IsNuwaReady() {
|
||||
return sNuwaReady;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(ENABLE_TESTS)
|
||||
MFBT_API void
|
||||
NuwaAssertNotFrozen(unsigned int aThread, const char* aThreadName) {
|
||||
if (!sIsNuwaProcess || !sIsFreezing) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread_info_t *tinfo = GetThreadInfo(static_cast<pthread_t>(aThread));
|
||||
if (!tinfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((tinfo->flags & TINFO_FLAG_NUWA_SUPPORT) &&
|
||||
!(tinfo->flags & TINFO_FLAG_NUWA_EXPLICIT_CHECKPOINT)) {
|
||||
__android_log_print(ANDROID_LOG_FATAL, "Nuwa",
|
||||
"Fatal error: the Nuwa process is about to deadlock in "
|
||||
"accessing a frozen thread (%s, tid=%d).",
|
||||
aThreadName ? aThreadName : "(unnamed)",
|
||||
tinfo->origNativeThreadID);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
|
@ -186,6 +186,16 @@ MFBT_API bool IsNuwaProcess();
|
||||
* @return If the Nuwa process is ready for spawning new processes.
|
||||
*/
|
||||
MFBT_API bool IsNuwaReady();
|
||||
|
||||
#if defined(DEBUG) || defined(ENABLE_TESTS)
|
||||
/**
|
||||
* Asserts that aThread is not frozen.
|
||||
*/
|
||||
MFBT_API void NuwaAssertNotFrozen(unsigned int aThread,
|
||||
const char* aThreadName);
|
||||
#else
|
||||
#define NuwaAssertNotFrozen(aThread, aThreadName) do {} while(0);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* __NUWA_H_ */
|
||||
|
@ -41,6 +41,10 @@
|
||||
#include "nsICrashReporter.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include "private/pprthred.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_LINUX
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
@ -511,6 +515,12 @@ nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget*
|
||||
{
|
||||
nsCOMPtr<nsIThreadObserver> obs;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
// On debug build or when tests are enabled, assert that we are not about to
|
||||
// create a deadlock in the Nuwa process.
|
||||
NuwaAssertNotFrozen(PR_GetThreadID(mThread), PR_GetThreadName(mThread));
|
||||
#endif
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
|
||||
|
Loading…
Reference in New Issue
Block a user