Bug 1225121 - [B2G] All the rest of content processes crash if user tries to run app that uses Service Workers after restart. r=baku

This commit is contained in:
Fernando Jimenez 2015-11-24 19:38:48 +01:00
parent e70ec2d790
commit a3d950d1bd
4 changed files with 140 additions and 10 deletions

View File

@ -150,6 +150,7 @@ private:
ServiceWorkerManagerParent::ServiceWorkerManagerParent()
: mService(ServiceWorkerManagerService::GetOrCreate())
, mID(++sServiceWorkerManagerParentID)
, mActorDestroyed(false)
{
AssertIsOnBackgroundThread();
mService->RegisterActor(this);
@ -160,6 +161,17 @@ ServiceWorkerManagerParent::~ServiceWorkerManagerParent()
AssertIsOnBackgroundThread();
}
already_AddRefed<ContentParent>
ServiceWorkerManagerParent::GetContentParent() const
{
AssertIsOnBackgroundThread();
// This object must be released on main-thread.
RefPtr<ContentParent> parent =
BackgroundParent::GetContentParent(Manager());
return parent.forget();
}
bool
ServiceWorkerManagerParent::RecvRegister(
const ServiceWorkerRegistrationData& aData)
@ -306,6 +318,8 @@ ServiceWorkerManagerParent::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBackgroundThread();
mActorDestroyed = true;
if (mService) {
// This object is about to be released and with it, also mService will be
// released too.

View File

@ -27,11 +27,19 @@ class ServiceWorkerManagerParent final : public PServiceWorkerManagerParent
friend class mozilla::ipc::BackgroundParentImpl;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServiceWorkerManagerParent)
bool ActorDestroyed() const
{
return mActorDestroyed;
}
uint64_t ID() const
{
return mID;
}
already_AddRefed<ContentParent> GetContentParent() const;
private:
ServiceWorkerManagerParent();
~ServiceWorkerManagerParent();
@ -61,6 +69,8 @@ private:
// We use this ID in the Service in order to avoid the sending of messages to
// ourself.
uint64_t mID;
bool mActorDestroyed;
};
} // namespace workers

View File

@ -7,6 +7,7 @@
#include "ServiceWorkerManagerService.h"
#include "ServiceWorkerManagerParent.h"
#include "ServiceWorkerRegistrar.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/unused.h"
@ -21,6 +22,84 @@ namespace {
ServiceWorkerManagerService* sInstance = nullptr;
struct NotifySoftUpdateData
{
RefPtr<ServiceWorkerManagerParent> mParent;
RefPtr<ContentParent> mContentParent;
~NotifySoftUpdateData()
{
MOZ_ASSERT(!mContentParent);
}
};
class NotifySoftUpdateIfPrincipalOkRunnable final : public nsRunnable
{
public:
NotifySoftUpdateIfPrincipalOkRunnable(
nsAutoPtr<nsTArray<NotifySoftUpdateData>>& aData,
const PrincipalOriginAttributes& aOriginAttributes,
const nsAString& aScope)
: mData(aData)
, mOriginAttributes(aOriginAttributes)
, mScope(aScope)
, mBackgroundThread(NS_GetCurrentThread())
{
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
MOZ_ASSERT(mData && !aData);
MOZ_ASSERT(mBackgroundThread);
}
NS_IMETHODIMP
Run() override
{
if (NS_IsMainThread()) {
for (uint32_t i = 0; i < mData->Length(); ++i) {
NotifySoftUpdateData& data = mData->ElementAt(i);
nsTArray<TabContext> contextArray =
data.mContentParent->GetManagedTabContext();
// mContentParent needs to be released in the main thread.
data.mContentParent = nullptr;
// We only send the notification about the soft update to the
// tabs/apps with the same appId and inBrowser values.
// Sending a notification to the wrong process will make the process
// to be killed.
for (uint32_t j = 0; j < contextArray.Length(); ++j) {
if ((contextArray[j].OwnOrContainingAppId() == mOriginAttributes.mAppId) &&
(contextArray[j].IsBrowserElement() == mOriginAttributes.mInBrowser)) {
continue;
}
// Array entries with no mParent won't receive any notification.
data.mParent = nullptr;
}
}
nsresult rv = mBackgroundThread->Dispatch(this, NS_DISPATCH_NORMAL);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
return NS_OK;
}
AssertIsOnBackgroundThread();
for (uint32_t i = 0; i < mData->Length(); ++i) {
NotifySoftUpdateData& data = mData->ElementAt(i);
MOZ_ASSERT(!(data.mContentParent));
ServiceWorkerManagerParent* parent = data.mParent;
if (parent && !parent->ActorDestroyed()) {
Unused << parent->SendNotifySoftUpdate(mOriginAttributes, mScope);
}
}
return NS_OK;
}
private:
nsAutoPtr<nsTArray<NotifySoftUpdateData>> mData;
PrincipalOriginAttributes mOriginAttributes;
nsString mScope;
nsCOMPtr<nsIThread> mBackgroundThread;
};
} // namespace
ServiceWorkerManagerService::ServiceWorkerManagerService()
@ -91,7 +170,7 @@ ServiceWorkerManagerService::PropagateRegistration(
DebugOnly<bool> parentFound = false;
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerManagerParent* parent = iter.Get()->GetKey();
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != aParentID) {
@ -116,21 +195,44 @@ ServiceWorkerManagerService::PropagateSoftUpdate(
{
AssertIsOnBackgroundThread();
nsAutoPtr<nsTArray<NotifySoftUpdateData>> notifySoftUpdateDataArray(
new nsTArray<NotifySoftUpdateData>());
DebugOnly<bool> parentFound = false;
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerManagerParent* parent = iter.Get()->GetKey();
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
nsString scope(aScope);
Unused << parent->SendNotifySoftUpdate(aOriginAttributes,
scope);
#ifdef DEBUG
if (parent->ID() == aParentID) {
parentFound = true;
}
#endif
RefPtr<ContentParent> contentParent = parent->GetContentParent();
// If the ContentParent is null we are dealing with a same-process actor.
if (!contentParent) {
Unused << parent->SendNotifySoftUpdate(aOriginAttributes,
nsString(aScope));
continue;
}
NotifySoftUpdateData* data = notifySoftUpdateDataArray->AppendElement();
data->mContentParent.swap(contentParent);
data->mParent.swap(parent);
}
if (notifySoftUpdateDataArray->IsEmpty()) {
return;
}
RefPtr<NotifySoftUpdateIfPrincipalOkRunnable> runnable =
new NotifySoftUpdateIfPrincipalOkRunnable(notifySoftUpdateDataArray,
aOriginAttributes, aScope);
MOZ_ASSERT(!notifySoftUpdateDataArray);
nsresult rv = NS_DispatchToMainThread(runnable);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
#ifdef DEBUG
MOZ_ASSERT(parentFound);
#endif
@ -155,7 +257,7 @@ ServiceWorkerManagerService::PropagateUnregister(
DebugOnly<bool> parentFound = false;
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerManagerParent* parent = iter.Get()->GetKey();
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != aParentID) {
@ -181,7 +283,7 @@ ServiceWorkerManagerService::PropagateRemove(uint64_t aParentID,
DebugOnly<bool> parentFound = false;
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerManagerParent* parent = iter.Get()->GetKey();
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != aParentID) {
@ -212,7 +314,7 @@ ServiceWorkerManagerService::PropagateRemoveAll(uint64_t aParentID)
DebugOnly<bool> parentFound = false;
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
ServiceWorkerManagerParent* parent = iter.Get()->GetKey();
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
MOZ_ASSERT(parent);
if (parent->ID() != aParentID) {

View File

@ -569,7 +569,9 @@ BackgroundParentImpl::AllocPServiceWorkerManagerParent()
AssertIsInMainProcess();
AssertIsOnBackgroundThread();
return new ServiceWorkerManagerParent();
RefPtr<dom::workers::ServiceWorkerManagerParent> agent =
new dom::workers::ServiceWorkerManagerParent();
return agent.forget().take();
}
bool
@ -580,7 +582,9 @@ BackgroundParentImpl::DeallocPServiceWorkerManagerParent(
AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor);
delete static_cast<ServiceWorkerManagerParent*>(aActor);
RefPtr<dom::workers::ServiceWorkerManagerParent> parent =
dont_AddRef(static_cast<dom::workers::ServiceWorkerManagerParent*>(aActor));
MOZ_ASSERT(parent);
return true;
}