Bug 1114507 - Part 2: Add/release the appId's refcnt in oop case. r=kanru

This commit is contained in:
chunminchang 2015-08-28 03:18:00 -04:00
parent 3c2040e20d
commit 13015804f5
7 changed files with 244 additions and 37 deletions

View File

@ -1468,7 +1468,9 @@ ContentParent::Init()
} }
Preferences::AddStrongObserver(this, ""); Preferences::AddStrongObserver(this, "");
if (obs) { if (obs) {
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", nullptr); nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
obs->NotifyObservers(static_cast<nsIObserver*>(this), "ipc:content-created", cpId.get());
} }
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY
@ -2057,7 +2059,9 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
} }
#endif #endif
} }
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nullptr); nsAutoString cpId;
cpId.AppendInt(static_cast<uint64_t>(this->ChildID()));
obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", cpId.get());
} }
// Remove any and all idle listeners. // Remove any and all idle listeners.
@ -2085,10 +2089,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
// least until after the current task finishes running. // least until after the current task finishes running.
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this)); NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
// Destroy any processes created by this ContentParent // Release the appId's reference count of any processes
ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); // created by this ContentParent and the frame opened by this ContentParent
// if this ContentParent crashes.
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
nsTArray<ContentParentId> childIDArray = nsTArray<ContentParentId> childIDArray =
cpm->GetAllChildProcessById(this->ChildID()); cpm->GetAllChildProcessById(this->ChildID());
if (why == AbnormalShutdown) {
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if(permMgr) {
// Release the appId's reference count of its child-processes
for (uint32_t i = 0; i < childIDArray.Length(); i++) {
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(childIDArray[i]);
for (uint32_t j = 0 ; j < tabCtxs.Length() ; j++) {
if (tabCtxs[j].OwnOrContainingAppId() != nsIScriptSecurityManager::NO_APP_ID) {
permMgr->ReleaseAppId(tabCtxs[j].OwnOrContainingAppId());
}
}
}
// Release the appId's reference count belong to itself
nsTArray<TabContext> tabCtxs = cpm->GetTabContextByContentProcess(mChildID);
for (uint32_t i = 0; i < tabCtxs.Length() ; i++) {
if (tabCtxs[i].OwnOrContainingAppId()!= nsIScriptSecurityManager::NO_APP_ID) {
permMgr->ReleaseAppId(tabCtxs[i].OwnOrContainingAppId());
}
}
}
}
// Destroy any processes created by this ContentParent
for(uint32_t i = 0; i < childIDArray.Length(); i++) { for(uint32_t i = 0; i < childIDArray.Length(); i++) {
ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]); ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
MessageLoop::current()->PostTask( MessageLoop::current()->PostTask(
@ -2104,23 +2133,33 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
} }
void void
ContentParent::NotifyTabDestroying(PBrowserParent* aTab) ContentParent::NotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId)
{ {
if (XRE_IsParentProcess()) {
// There can be more than one PBrowser for a given app process // There can be more than one PBrowser for a given app process
// because of popup windows. PBrowsers can also destroy // because of popup windows. PBrowsers can also destroy
// concurrently. When all the PBrowsers are destroying, kick off // concurrently. When all the PBrowsers are destroying, kick off
// another task to ensure the child process *really* shuts down, // another task to ensure the child process *really* shuts down,
// even if the PBrowsers themselves never finish destroying. // even if the PBrowsers themselves never finish destroying.
int32_t numLiveTabs = ManagedPBrowserParent().Length(); ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
++mNumDestroyingTabs; ContentParent* cp = cpm->GetContentProcessById(aCpId);
if (mNumDestroyingTabs != numLiveTabs) { if (!cp) {
return;
}
++cp->mNumDestroyingTabs;
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(aCpId);
if (static_cast<size_t>(cp->mNumDestroyingTabs) != tabIds.Length()) {
return; return;
} }
// We're dying now, so prevent this content process from being // We're dying now, so prevent this content process from being
// recycled during its shutdown procedure. // recycled during its shutdown procedure.
MarkAsDead(); cp->MarkAsDead();
StartForceKillTimer(); cp->StartForceKillTimer();
} else {
ContentChild::GetSingleton()->SendNotifyTabDestroying(aTabId, aCpId);
}
} }
void void
@ -2142,16 +2181,15 @@ ContentParent::StartForceKillTimer()
} }
void void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab, ContentParent::NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying) bool aNotifiedDestroying)
{ {
if (aNotifiedDestroying) { if (aNotifiedDestroying) {
--mNumDestroyingTabs; --mNumDestroyingTabs;
} }
TabId id = static_cast<TabParent*>(aTab)->GetTabId();
nsTArray<PContentPermissionRequestParent*> parentArray = nsTArray<PContentPermissionRequestParent*> parentArray =
nsContentPermissionUtils::GetContentPermissionRequestParentById(id); nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
// Need to close undeleted ContentPermissionRequestParents before tab is closed. // Need to close undeleted ContentPermissionRequestParents before tab is closed.
for (auto& permissionRequestParent : parentArray) { for (auto& permissionRequestParent : parentArray) {
@ -2164,7 +2202,9 @@ ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
// There can be more than one PBrowser for a given app process // There can be more than one PBrowser for a given app process
// because of popup windows. When the last one closes, shut // because of popup windows. When the last one closes, shut
// us down. // us down.
if (ManagedPBrowserParent().Length() == 1) { ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(this->ChildID());
if (tabIds.Length() == 1) {
// In the case of normal shutdown, send a shutdown message to child to // In the case of normal shutdown, send a shutdown message to child to
// allow it to perform shutdown tasks. // allow it to perform shutdown tasks.
MessageLoop::current()->PostTask( MessageLoop::current()->PostTask(
@ -4899,8 +4939,12 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
{ {
TabId tabId; TabId tabId;
if (XRE_IsParentProcess()) { if (XRE_IsParentProcess()) {
ContentProcessManager *cpm = ContentProcessManager::GetSingleton(); ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId); tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
// Add appId's reference count in oop case
if (tabId) {
PermissionManagerAddref(aCpId, tabId);
}
} }
else { else {
ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId, ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
@ -4913,14 +4957,27 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
/*static*/ void /*static*/ void
ContentParent::DeallocateTabId(const TabId& aTabId, ContentParent::DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId) const ContentParentId& aCpId,
bool aMarkedDestroying)
{ {
if (XRE_IsParentProcess()) { if (XRE_IsParentProcess()) {
// Release appId's reference count in oop case
if (aTabId) {
PermissionManagerRelease(aCpId, aTabId);
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp = cpm->GetContentProcessById(aCpId);
cp->NotifyTabDestroyed(aTabId, aMarkedDestroying);
ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId, ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
aTabId); aTabId);
} }
else { else {
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId); ContentChild::GetSingleton()->SendDeallocateTabId(aTabId,
aCpId,
aMarkedDestroying);
} }
} }
@ -4938,9 +4995,19 @@ ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
} }
bool bool
ContentParent::RecvDeallocateTabId(const TabId& aTabId) ContentParent::RecvDeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
const bool& aMarkedDestroying)
{ {
DeallocateTabId(aTabId, this->ChildID()); DeallocateTabId(aTabId, aCpId, aMarkedDestroying);
return true;
}
bool
ContentParent::RecvNotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId)
{
NotifyTabDestroying(aTabId, aCpId);
return true; return true;
} }
@ -5111,6 +5178,38 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
return true; return true;
} }
/* static */ bool
ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
const TabId& aTabId)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Call PermissionManagerAddref in content process!");
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
permMgr->AddrefAppId(appId);
return true;
}
return false;
}
/* static */ bool
ContentParent::PermissionManagerRelease(const ContentParentId& aCpId,
const TabId& aTabId)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Call PermissionManagerRelease in content process!");
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (appId != nsIScriptSecurityManager::NO_APP_ID && permMgr) {
permMgr->ReleaseAppId(appId);
return true;
}
return false;
}
bool bool
ContentParent::RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig) ContentParent::RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig)
{ {

View File

@ -212,9 +212,10 @@ public:
virtual bool KillChild() override; virtual bool KillChild() override;
/** Notify that a tab is beginning its destruction sequence. */ /** Notify that a tab is beginning its destruction sequence. */
void NotifyTabDestroying(PBrowserParent* aTab); static void NotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId);
/** Notify that a tab was destroyed during normal operation. */ /** Notify that a tab was destroyed during normal operation. */
void NotifyTabDestroyed(PBrowserParent* aTab, void NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying); bool aNotifiedDestroying);
TestShellParent* CreateTestShell(); TestShellParent* CreateTestShell();
@ -227,7 +228,21 @@ public:
const IPCTabContext& aContext, const IPCTabContext& aContext,
const ContentParentId& aCpId); const ContentParentId& aCpId);
static void static void
DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId); DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
bool aMarkedDestroying);
/*
* Add the appId's reference count by the given ContentParentId and TabId
*/
static bool
PermissionManagerAddref(const ContentParentId& aCpId, const TabId& aTabId);
/*
* Release the appId's reference count by the given ContentParentId and TabId
*/
static bool
PermissionManagerRelease(const ContentParentId& aCpId, const TabId& aTabId);
static bool static bool
GetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration& aConfig); GetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration& aConfig);
@ -356,7 +371,12 @@ public:
const ContentParentId& aCpId, const ContentParentId& aCpId,
TabId* aTabId) override; TabId* aTabId) override;
virtual bool RecvDeallocateTabId(const TabId& aTabId) override; virtual bool RecvDeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId,
const bool& aMarkedDestroying) override;
virtual bool RecvNotifyTabDestroying(const TabId& aTabId,
const ContentParentId& aCpId) override;
nsTArray<TabContext> GetManagedTabContext(); nsTArray<TabContext> GetManagedTabContext();

View File

@ -12,6 +12,7 @@
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "nsPrintfCString.h" #include "nsPrintfCString.h"
#include "nsIScriptSecurityManager.h"
// XXX need another bug to move this to a common header. // XXX need another bug to move this to a common header.
#ifdef DISABLE_ASSERTS_FOR_FUZZING #ifdef DISABLE_ASSERTS_FOR_FUZZING
@ -334,5 +335,40 @@ ContentProcessManager::GetTopLevelTabParentByProcessAndTabId(const ContentParent
return GetTabParentByProcessAndTabId(currentCpId, currentTabId); return GetTabParentByProcessAndTabId(currentCpId, currentTabId);
} }
nsTArray<TabId>
ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpId)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<TabId> tabIdList;
auto iter = mContentParentMap.find(aChildCpId);
if (NS_WARN_IF(iter == mContentParentMap.end())) {
ASSERT_UNLESS_FUZZING();
return Move(tabIdList);
}
for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
remoteFrameIter != iter->second.mRemoteFrames.end();
++remoteFrameIter) {
tabIdList.AppendElement(remoteFrameIter->first);
}
return Move(tabIdList);
}
uint32_t
ContentProcessManager::GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId)
{
uint32_t appId = nsIScriptSecurityManager::NO_APP_ID;
if (aChildCpId && aChildTabId) {
TabContext tabContext;
if (GetTabContextByProcessAndTabId(aChildCpId, aChildTabId, &tabContext)) {
appId = tabContext.OwnOrContainingAppId();
}
}
return appId;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -110,6 +110,13 @@ public:
const TabId& aChildTabId, const TabId& aChildTabId,
/*out*/ TabId* aOpenerTabId); /*out*/ TabId* aOpenerTabId);
/**
* Get all TabParents' Ids managed by the givent content process.
* Return empty array when TabParent couldn't be found via aChildCpId
*/
nsTArray<TabId>
GetTabParentsByProcessId(const ContentParentId& aChildCpId);
/** /**
* Get the TabParent by the given content process and tab id. * Get the TabParent by the given content process and tab id.
* Return nullptr when TabParent couldn't be found via aChildCpId * Return nullptr when TabParent couldn't be found via aChildCpId
@ -135,6 +142,15 @@ public:
GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId, GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId); const TabId& aChildTabId);
/**
* Return appId by given TabId and ContentParentId.
* It will return nsIScriptSecurityManager::NO_APP_ID
* if the given tab is not an app.
*/
uint32_t
GetAppIdByProcessAndTabId(const ContentParentId& aChildCpId,
const TabId& aChildTabId);
private: private:
static StaticAutoPtr<ContentProcessManager> sSingleton; static StaticAutoPtr<ContentProcessManager> sSingleton;
TabId mUniqueId; TabId mUniqueId;

View File

@ -991,8 +991,15 @@ parent:
*/ */
sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId) sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
returns (TabId tabId); returns (TabId tabId);
async DeallocateTabId(TabId tabId); async DeallocateTabId(TabId tabId,
ContentParentId cpId,
bool aMarkedDestroying);
/**
* Tell the chrome process there is a destruction of PBrowser(Tab)
*/
async NotifyTabDestroying(TabId tabId,
ContentParentId cpId);
/** /**
* Starts an offline application cache update. * Starts an offline application cache update.
* @param manifestURI * @param manifestURI

View File

@ -436,12 +436,8 @@ TabParent::IsVisible()
} }
void void
TabParent::Destroy() TabParent::DestroyInternal()
{ {
if (mIsDestroyed) {
return;
}
IMEStateManager::OnTabParentDestroying(this); IMEStateManager::OnTabParentDestroying(this);
RemoveWindowListeners(); RemoveWindowListeners();
@ -455,11 +451,6 @@ TabParent::Destroy()
RemoveTabParentFromTable(frame->GetLayersId()); RemoveTabParentFromTable(frame->GetLayersId());
frame->Destroy(); frame->Destroy();
} }
mIsDestroyed = true;
if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroying(this);
}
// Let all PluginWidgets know we are tearing down. Prevents // Let all PluginWidgets know we are tearing down. Prevents
// these objects from sending async events after the child side // these objects from sending async events after the child side
@ -468,6 +459,24 @@ TabParent::Destroy()
for (uint32_t idx = 0; idx < kids.Length(); ++idx) { for (uint32_t idx = 0; idx < kids.Length(); ++idx) {
static_cast<mozilla::plugins::PluginWidgetParent*>(kids[idx])->ParentDestroy(); static_cast<mozilla::plugins::PluginWidgetParent*>(kids[idx])->ParentDestroy();
} }
}
void
TabParent::Destroy()
{
if (mIsDestroyed) {
return;
}
DestroyInternal();
mIsDestroyed = true;
if (XRE_IsParentProcess()) {
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->AsContentParent()->ChildID());
} else {
ContentParent::NotifyTabDestroying(this->GetTabId(), Manager()->ChildID());
}
mMarkedDestroying = true; mMarkedDestroying = true;
} }
@ -476,12 +485,15 @@ bool
TabParent::Recv__delete__() TabParent::Recv__delete__()
{ {
if (XRE_IsParentProcess()) { if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
ContentParent::DeallocateTabId(mTabId, ContentParent::DeallocateTabId(mTabId,
Manager()->AsContentParent()->ChildID()); Manager()->AsContentParent()->ChildID(),
mMarkedDestroying);
} }
else { else {
ContentParent::DeallocateTabId(mTabId, ContentParentId(0)); Manager()->AsContentBridgeParent()->NotifyTabDestroyed();
ContentParent::DeallocateTabId(mTabId,
Manager()->ChildID(),
mMarkedDestroying);
} }
return true; return true;
@ -494,6 +506,22 @@ TabParent::ActorDestroy(ActorDestroyReason why)
// case of a crash. // case of a crash.
IMEStateManager::OnTabParentDestroying(this); IMEStateManager::OnTabParentDestroying(this);
// Prevent executing ContentParent::NotifyTabDestroying in
// TabParent::Destroy() called by frameLoader->DestroyComplete() below
// when tab crashes in contentprocess because ContentParent::ActorDestroy()
// in main process will be triggered before this function
// and remove the process information that
// ContentParent::NotifyTabDestroying need from mContentParentMap.
// When tab crashes in content process,
// there is no need to call ContentParent::NotifyTabDestroying
// because the jobs in ContentParent::NotifyTabDestroying
// will be done by ContentParent::ActorDestroy.
if (XRE_IsContentProcess() && why == AbnormalShutdown && !mIsDestroyed) {
DestroyInternal();
mIsDestroyed = true;
}
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true); nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
nsCOMPtr<nsIObserverService> os = services::GetObserverService(); nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (frameLoader) { if (frameLoader) {

View File

@ -491,6 +491,7 @@ protected:
LayoutDeviceIntPoint mChromeOffset; LayoutDeviceIntPoint mChromeOffset;
private: private:
void DestroyInternal();
already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const; already_AddRefed<nsFrameLoader> GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy = false) const;
nsRefPtr<nsIContentParent> mManager; nsRefPtr<nsIContentParent> mManager;
void TryCacheDPIAndScale(); void TryCacheDPIAndScale();