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, "");
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
@ -2057,7 +2059,9 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
}
#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.
@ -2085,10 +2089,35 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
// least until after the current task finishes running.
NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
// Destroy any processes created by this ContentParent
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
// Release the appId's reference count of any processes
// created by this ContentParent and the frame opened by this ContentParent
// if this ContentParent crashes.
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
nsTArray<ContentParentId> childIDArray =
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++) {
ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
MessageLoop::current()->PostTask(
@ -2104,23 +2133,33 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
}
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
// because of popup windows. PBrowsers can also destroy
// concurrently. When all the PBrowsers are destroying, kick off
// another task to ensure the child process *really* shuts down,
// even if the PBrowsers themselves never finish destroying.
int32_t numLiveTabs = ManagedPBrowserParent().Length();
++mNumDestroyingTabs;
if (mNumDestroyingTabs != numLiveTabs) {
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
ContentParent* cp = cpm->GetContentProcessById(aCpId);
if (!cp) {
return;
}
++cp->mNumDestroyingTabs;
nsTArray<TabId> tabIds = cpm->GetTabParentsByProcessId(aCpId);
if (static_cast<size_t>(cp->mNumDestroyingTabs) != tabIds.Length()) {
return;
}
// We're dying now, so prevent this content process from being
// recycled during its shutdown procedure.
MarkAsDead();
StartForceKillTimer();
cp->MarkAsDead();
cp->StartForceKillTimer();
} else {
ContentChild::GetSingleton()->SendNotifyTabDestroying(aTabId, aCpId);
}
}
void
@ -2142,16 +2181,15 @@ ContentParent::StartForceKillTimer()
}
void
ContentParent::NotifyTabDestroyed(PBrowserParent* aTab,
ContentParent::NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying)
{
if (aNotifiedDestroying) {
--mNumDestroyingTabs;
}
TabId id = static_cast<TabParent*>(aTab)->GetTabId();
nsTArray<PContentPermissionRequestParent*> parentArray =
nsContentPermissionUtils::GetContentPermissionRequestParentById(id);
nsContentPermissionUtils::GetContentPermissionRequestParentById(aTabId);
// Need to close undeleted ContentPermissionRequestParents before tab is closed.
for (auto& permissionRequestParent : parentArray) {
@ -2164,7 +2202,9 @@ 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 (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
// allow it to perform shutdown tasks.
MessageLoop::current()->PostTask(
@ -4899,8 +4939,12 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
{
TabId tabId;
if (XRE_IsParentProcess()) {
ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
// Add appId's reference count in oop case
if (tabId) {
PermissionManagerAddref(aCpId, tabId);
}
}
else {
ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
@ -4913,14 +4957,27 @@ ContentParent::AllocateTabId(const TabId& aOpenerTabId,
/*static*/ void
ContentParent::DeallocateTabId(const TabId& aTabId,
const ContentParentId& aCpId)
const ContentParentId& aCpId,
bool aMarkedDestroying)
{
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,
aTabId);
}
else {
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
ContentChild::GetSingleton()->SendDeallocateTabId(aTabId,
aCpId,
aMarkedDestroying);
}
}
@ -4938,9 +4995,19 @@ ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
}
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;
}
@ -5111,6 +5178,38 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
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
ContentParent::RecvGetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration* aConfig)
{

View File

@ -212,9 +212,10 @@ public:
virtual bool KillChild() override;
/** 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. */
void NotifyTabDestroyed(PBrowserParent* aTab,
void NotifyTabDestroyed(const TabId& aTabId,
bool aNotifiedDestroying);
TestShellParent* CreateTestShell();
@ -227,7 +228,21 @@ public:
const IPCTabContext& aContext,
const ContentParentId& aCpId);
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
GetBrowserConfiguration(const nsCString& aURI, BrowserConfiguration& aConfig);
@ -356,7 +371,12 @@ public:
const ContentParentId& aCpId,
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();

View File

@ -12,6 +12,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "nsPrintfCString.h"
#include "nsIScriptSecurityManager.h"
// XXX need another bug to move this to a common header.
#ifdef DISABLE_ASSERTS_FOR_FUZZING
@ -334,5 +335,40 @@ ContentProcessManager::GetTopLevelTabParentByProcessAndTabId(const ContentParent
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 mozilla

View File

@ -110,6 +110,13 @@ public:
const TabId& aChildTabId,
/*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.
* Return nullptr when TabParent couldn't be found via aChildCpId
@ -135,6 +142,15 @@ public:
GetTopLevelTabParentByProcessAndTabId(const ContentParentId& aChildCpId,
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:
static StaticAutoPtr<ContentProcessManager> sSingleton;
TabId mUniqueId;

View File

@ -991,8 +991,15 @@ parent:
*/
sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
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.
* @param manifestURI

View File

@ -436,12 +436,8 @@ TabParent::IsVisible()
}
void
TabParent::Destroy()
TabParent::DestroyInternal()
{
if (mIsDestroyed) {
return;
}
IMEStateManager::OnTabParentDestroying(this);
RemoveWindowListeners();
@ -455,11 +451,6 @@ TabParent::Destroy()
RemoveTabParentFromTable(frame->GetLayersId());
frame->Destroy();
}
mIsDestroyed = true;
if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroying(this);
}
// Let all PluginWidgets know we are tearing down. Prevents
// 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) {
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;
}
@ -476,12 +485,15 @@ bool
TabParent::Recv__delete__()
{
if (XRE_IsParentProcess()) {
Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
ContentParent::DeallocateTabId(mTabId,
Manager()->AsContentParent()->ChildID());
Manager()->AsContentParent()->ChildID(),
mMarkedDestroying);
}
else {
ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
Manager()->AsContentBridgeParent()->NotifyTabDestroyed();
ContentParent::DeallocateTabId(mTabId,
Manager()->ChildID(),
mMarkedDestroying);
}
return true;
@ -494,6 +506,22 @@ TabParent::ActorDestroy(ActorDestroyReason why)
// case of a crash.
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);
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (frameLoader) {

View File

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