Bug 781742: Try to keep a process pre-launched for app content, if the pref says to. r=jlebar

This commit is contained in:
Chris Jones 2012-08-15 18:46:03 -07:00
parent ff582a97e6
commit b5aa2f402e
4 changed files with 147 additions and 10 deletions

View File

@ -502,3 +502,9 @@ pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
pref("hal.processPriorityManager.gonk.masterNice", -1);
pref("hal.processPriorityManager.gonk.foregroundNice", 0);
pref("hal.processPriorityManager.gonk.backgroundNice", 10);
// Enable pre-launching content processes for improved startup time
// (hiding latency).
pref("dom.ipc.processPrelauch.enabled", true);
// Wait this long before pre-launching a new subprocess.
pref("dom.ipc.processPrelauch.delayMs", 1000);

View File

@ -21,10 +21,7 @@
#include "IndexedDBParent.h"
#include "IndexedDatabaseManager.h"
#include "mozIApplication.h"
#include "mozilla/Preferences.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Util.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/dom/StorageParent.h"
@ -34,6 +31,10 @@
#include "mozilla/ipc/TestShellParent.h"
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/net/NeckoParent.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Util.h"
#include "mozilla/unused.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
@ -158,6 +159,93 @@ nsTArray<ContentParent*>* ContentParent::gPrivateContent;
// The first content child has ID 1, so the chrome process can have ID 0.
static PRUint64 gContentChildID = 1;
// Try to keep an app process always preallocated, to get
// initialization off the critical path of app startup.
static bool sKeepAppProcessPreallocated;
static StaticRefPtr<ContentParent> sPreallocatedAppProcess;
static CancelableTask* sPreallocateAppProcessTask;
// This number is fairly arbitrary ... the intention is to put off
// launching another app process until the last one has finished
// loading its content, to reduce CPU/memory/IO contention.
static int sPreallocateDelayMs;
// We want the prelaunched process to know that it's for apps, but not
// actually for any app in particular. Use a magic manifest URL.
// Can't be a static constant.
#define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
/*static*/ void
ContentParent::PreallocateAppProcess()
{
MOZ_ASSERT(!sPreallocatedAppProcess);
if (sPreallocateAppProcessTask) {
// We were called directly while a delayed task was scheduled.
sPreallocateAppProcessTask->Cancel();
sPreallocateAppProcessTask = nullptr;
}
sPreallocatedAppProcess =
new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL);
sPreallocatedAppProcess->Init();
}
/*static*/ void
ContentParent::DelayedPreallocateAppProcess()
{
sPreallocateAppProcessTask = nullptr;
if (!sPreallocatedAppProcess) {
PreallocateAppProcess();
}
}
/*static*/ void
ContentParent::ScheduleDelayedPreallocateAppProcess()
{
if (!sKeepAppProcessPreallocated || sPreallocateAppProcessTask) {
return;
}
sPreallocateAppProcessTask =
NewRunnableFunction(DelayedPreallocateAppProcess);
MessageLoop::current()->PostDelayedTask(
FROM_HERE, sPreallocateAppProcessTask, sPreallocateDelayMs);
}
/*static*/ already_AddRefed<ContentParent>
ContentParent::MaybeTakePreallocatedAppProcess()
{
nsRefPtr<ContentParent> process = sPreallocatedAppProcess.get();
sPreallocatedAppProcess = nullptr;
ScheduleDelayedPreallocateAppProcess();
return process.forget();
}
/*static*/ void
ContentParent::StartUp()
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
return;
}
sKeepAppProcessPreallocated =
Preferences::GetBool("dom.ipc.processPrelauch.enabled", false);
if (sKeepAppProcessPreallocated) {
ClearOnShutdown(&sPreallocatedAppProcess);
sPreallocateDelayMs = Preferences::GetUint(
"dom.ipc.processPrelauch.delayMs", 1000);
MOZ_ASSERT(!sPreallocateAppProcessTask);
ScheduleDelayedPreallocateAppProcess();
}
}
/*static*/ void
ContentParent::ShutDown()
{
// No-op for now. We rely on normal process shutdown and
// ClearOnShutdown() to clean up our state.
}
/*static*/ ContentParent*
ContentParent::GetNewOrUsed()
{
@ -225,10 +313,16 @@ ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
return nullptr;
}
ContentParent* p = gAppContentParents->Get(manifestURL);
nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
if (!p) {
p = new ContentParent(manifestURL);
p->Init();
p = MaybeTakePreallocatedAppProcess();
if (p) {
p->SetManifestFromPreallocated(manifestURL);
} else {
NS_WARNING("Unable to use pre-allocated app process");
p = new ContentParent(manifestURL);
p->Init();
}
gAppContentParents->Put(manifestURL, p);
}
@ -302,7 +396,16 @@ ContentParent::Init()
}
void
ContentParent::ShutDown()
ContentParent::SetManifestFromPreallocated(const nsAString& aAppManifestURL)
{
MOZ_ASSERT(mAppManifestURL == MAGIC_PREALLOCATED_APP_MANIFEST_URL);
// Clients should think of mAppManifestURL as const ... we're
// bending the rules here just for the preallocation hack.
const_cast<nsString&>(mAppManifestURL) = aAppManifestURL;
}
void
ContentParent::ShutDownProcess()
{
if (mIsAlive) {
// Close() can only be called once. It kicks off the
@ -447,6 +550,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
#endif
}
if (sPreallocatedAppProcess == this) {
sPreallocatedAppProcess = nullptr;
}
mMessageManager->Disconnect();
// clear the child memory reporters
@ -513,7 +620,7 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
if (IsForApp() && ManagedPBrowserParent().Length() == 1) {
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ContentParent::ShutDown));
NewRunnableMethod(this, &ContentParent::ShutDownProcess));
}
}

View File

@ -58,6 +58,14 @@ private:
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
public:
/**
* Start up the content-process machinery. This might include
* scheduling pre-launch tasks.
*/
static void StartUp();
/** Shut down the content-process machinery. */
static void ShutDown();
static ContentParent* GetNewOrUsed();
/**
@ -112,6 +120,11 @@ private:
static nsTArray<ContentParent*>* gNonAppContentParents;
static nsTArray<ContentParent*>* gPrivateContent;
static void PreallocateAppProcess();
static void DelayedPreallocateAppProcess();
static void ScheduleDelayedPreallocateAppProcess();
static already_AddRefed<ContentParent> MaybeTakePreallocatedAppProcess();
// Hide the raw constructor methods since we don't want client code
// using them.
using PContentParent::SendPBrowserConstructor;
@ -122,6 +135,10 @@ private:
void Init();
// Transform a pre-allocated app process into a "real" app
// process, for the specified manifest URL.
void SetManifestFromPreallocated(const nsAString& aAppManifestURL);
/**
* Mark this ContentParent as dead for the purposes of Get*().
* This method is idempotent.
@ -134,7 +151,7 @@ private:
* by the Get*() funtions. However, the shutdown sequence itself
* may be asynchronous.
*/
void ShutDown();
void ShutDownProcess();
PCompositorParent* AllocPCompositor(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) MOZ_OVERRIDE;

View File

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "nsLayoutStatics.h"
#include "nscore.h"
@ -94,6 +96,7 @@
#include "nsHyphenationManager.h"
#include "nsEditorSpellCheck.h"
#include "nsWindowMemoryReporter.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ipc/ProcessPriorityManager.h"
extern void NS_ShutdownChainItemPool();
@ -116,6 +119,8 @@ nsLayoutStatics::Initialize()
nsresult rv;
ContentParent::StartUp();
// Register all of our atoms once
nsCSSAnonBoxes::AddRefAtoms();
nsCSSPseudoClasses::AddRefAtoms();
@ -344,4 +349,6 @@ nsLayoutStatics::Shutdown()
nsHyphenationManager::Shutdown();
nsEditorSpellCheck::ShutDown();
nsDOMMutationObserver::Shutdown();
ContentParent::ShutDown();
}