Bug 773998: Shut down app processes when the last browser closes. r=jlebar

This commit is contained in:
Chris Jones 2012-07-17 11:27:27 -07:00
parent 98e8cfcf46
commit 9e4503dd30
4 changed files with 91 additions and 24 deletions

View File

@ -251,6 +251,49 @@ ContentParent::Init()
#endif
}
void
ContentParent::ShutDown()
{
if (mIsAlive) {
// Close() can only be called once. It kicks off the
// destruction sequence.
Close();
}
// NB: must MarkAsDead() here so that this isn't accidentally
// returned from Get*() while in the midst of shutdown.
MarkAsDead();
}
void
ContentParent::MarkAsDead()
{
if (!mAppManifestURL.IsEmpty()) {
if (gAppContentParents) {
gAppContentParents->Remove(mAppManifestURL);
if (!gAppContentParents->Count()) {
delete gAppContentParents;
gAppContentParents = NULL;
}
}
} else if (gNonAppContentParents) {
gNonAppContentParents->RemoveElement(this);
if (!gNonAppContentParents->Length()) {
delete gNonAppContentParents;
gNonAppContentParents = NULL;
}
}
if (gPrivateContent) {
gPrivateContent->RemoveElement(this);
if (!gPrivateContent->Length()) {
delete gPrivateContent;
gPrivateContent = NULL;
}
}
mIsAlive = false;
}
void
ContentParent::OnChannelConnected(int32 pid)
{
@ -349,29 +392,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
if (mRunToCompletionDepth)
mRunToCompletionDepth = 0;
if (!mAppManifestURL.IsEmpty()) {
gAppContentParents->Remove(mAppManifestURL);
if (!gAppContentParents->Count()) {
delete gAppContentParents;
gAppContentParents = NULL;
}
} else {
gNonAppContentParents->RemoveElement(this);
if (!gNonAppContentParents->Length()) {
delete gNonAppContentParents;
gNonAppContentParents = NULL;
}
}
if (gPrivateContent) {
gPrivateContent->RemoveElement(this);
if (!gPrivateContent->Length()) {
delete gPrivateContent;
gPrivateContent = NULL;
}
}
mIsAlive = false;
MarkAsDead();
if (obs) {
nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
@ -416,6 +437,19 @@ ContentParent::CreateTab(PRUint32 aChromeFlags, bool aIsBrowserFrame)
return static_cast<TabParent*>(SendPBrowserConstructor(aChromeFlags, aIsBrowserFrame));
}
void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab)
{
// There can be more than one PBrowser for a given app process
// because of popup windows. When the last one closes, shut
// us down.
if (IsForApp() && ManagedPBrowserParent().Length() == 1) {
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ContentParent::ShutDown));
}
}
TestShellParent*
ContentParent::CreateTestShell()
{
@ -493,6 +527,12 @@ ContentParent::IsAlive()
return mIsAlive;
}
bool
ContentParent::IsForApp()
{
return !mAppManifestURL.IsEmpty();
}
bool
ContentParent::RecvReadPrefsArray(InfallibleTArray<PrefTuple> *prefs)
{

View File

@ -68,6 +68,8 @@ public:
* <iframe mozbrowser>.
*/
TabParent* CreateTab(PRUint32 aChromeFlags, bool aIsBrowserFrame);
/** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab);
TestShellParent* CreateTestShell();
bool DestroyTestShell(TestShellParent* aTestShell);
@ -77,6 +79,7 @@ public:
bool RequestRunToCompletion();
bool IsAlive();
bool IsForApp();
void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
@ -107,6 +110,20 @@ private:
void Init();
/**
* Mark this ContentParent as dead for the purposes of Get*().
* This method is idempotent.
*/
void MarkAsDead();
/**
* Exit the subprocess and vamoose. After this call IsAlive()
* will return false and this ContentParent will not be returned
* by the Get*() funtions. However, the shutdown sequence itself
* may be asynchronous.
*/
void ShutDown();
virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags, const bool& aIsBrowserFrame);
virtual bool DeallocPBrowser(PBrowserParent* frame);

View File

@ -99,6 +99,14 @@ TabParent::Destroy()
}
}
bool
TabParent::Recv__delete__()
{
ContentParent* cp = static_cast<ContentParent*>(Manager());
cp->NotifyTabDestroyed(this);
return true;
}
void
TabParent::ActorDestroy(ActorDestroyReason why)
{

View File

@ -164,7 +164,9 @@ protected:
const nsString& aJSON,
InfallibleTArray<nsString>* aJSONRetVal = nsnull);
void ActorDestroy(ActorDestroyReason why);
virtual bool Recv__delete__() MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
virtual PIndexedDBParent* AllocPIndexedDB(const nsCString& aASCIIOrigin,
bool* /* aAllowed */);