Bug 1131327 - Patch 6 - SWM holds ServiceWorkerRegistrationListener for updatefound and invalidation notifications. r=baku

Splits up the listener interface to which SWM can hold rawptrs so that registration objects living on the worker thread can use awkward proxies to listen to these events.
This commit is contained in:
Nikhil Marathe 2015-04-08 13:13:32 -07:00
parent 21d2d59eb7
commit eb16e0a73d
5 changed files with 86 additions and 71 deletions

View File

@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
readonly attribute DOMString waitingCacheName; readonly attribute DOMString waitingCacheName;
}; };
[scriptable, builtinclass, uuid(7e3c44bd-112f-4668-83a6-37d1089bb1f8)] [scriptable, builtinclass, uuid(ff6e13ae-ae34-4941-a81e-a82f3e0e7b6b)]
interface nsIServiceWorkerManager : nsISupports interface nsIServiceWorkerManager : nsISupports
{ {
/** /**
@ -76,10 +76,6 @@ interface nsIServiceWorkerManager : nsISupports
void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel, void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel,
in boolean aIsReload); in boolean aIsReload);
// aTarget MUST be a ServiceWorkerRegistration.
[noscript] void AddRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
[noscript] void RemoveRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
/** /**
* Call this to request that document `aDoc` be controlled by a ServiceWorker * Call this to request that document `aDoc` be controlled by a ServiceWorker
* if a registration exists for it's scope. * if a registration exists for it's scope.

View File

@ -702,9 +702,11 @@ public:
// Step 4.6 "Queue a task..." for updatefound. // Step 4.6 "Queue a task..." for updatefound.
nsCOMPtr<nsIRunnable> upr = nsCOMPtr<nsIRunnable> upr =
NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm, NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(
&ServiceWorkerManager::FireUpdateFound, swm,
mRegistration); &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
mRegistration);
NS_DispatchToMainThread(upr); NS_DispatchToMainThread(upr);
nsRefPtr<ServiceWorker> serviceWorker; nsRefPtr<ServiceWorker> serviceWorker;
@ -2184,63 +2186,59 @@ ServiceWorkerManager::GetScopeForUrl(const nsAString& aUrl, nsAString& aScope)
} }
NS_IMETHODIMP NS_IMETHODIMP
ServiceWorkerManager::AddRegistrationEventListener(const nsAString& aScope, nsIDOMEventTarget* aListener) ServiceWorkerManager::AddRegistrationEventListener(const nsAString& aScope,
ServiceWorkerRegistrationListener* aListener)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
nsAutoCString scope = NS_ConvertUTF16toUTF8(aScope); MOZ_ASSERT(aListener);
// TODO: this is very very bad:
ServiceWorkerRegistrationBase* registration = static_cast<ServiceWorkerRegistrationBase*>(aListener);
MOZ_ASSERT(!mServiceWorkerRegistrations.Contains(registration));
#ifdef DEBUG #ifdef DEBUG
// Ensure a registration is only listening for it's own scope. // Ensure a registration is only listening for it's own scope.
nsAutoString regScope; nsAutoString regScope;
registration->GetScope(regScope); aListener->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty()); MOZ_ASSERT(!regScope.IsEmpty());
MOZ_ASSERT(scope.Equals(NS_ConvertUTF16toUTF8(regScope))); MOZ_ASSERT(aScope.Equals(regScope));
#endif #endif
mServiceWorkerRegistrations.AppendElement(registration);
MOZ_ASSERT(!mServiceWorkerRegistrationListeners.Contains(aListener));
mServiceWorkerRegistrationListeners.AppendElement(aListener);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
ServiceWorkerManager::RemoveRegistrationEventListener(const nsAString& aScope, nsIDOMEventTarget* aListener) ServiceWorkerManager::RemoveRegistrationEventListener(const nsAString& aScope,
ServiceWorkerRegistrationListener* aListener)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
nsCString scope = NS_ConvertUTF16toUTF8(aScope); MOZ_ASSERT(aListener);
ServiceWorkerRegistrationBase* registration = static_cast<ServiceWorkerRegistrationBase*>(aListener);
MOZ_ASSERT(mServiceWorkerRegistrations.Contains(registration));
#ifdef DEBUG #ifdef DEBUG
// Ensure a registration is unregistering for it's own scope. // Ensure a registration is unregistering for it's own scope.
nsAutoString regScope; nsAutoString regScope;
registration->GetScope(regScope); aListener->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty()); MOZ_ASSERT(!regScope.IsEmpty());
MOZ_ASSERT(scope.Equals(NS_ConvertUTF16toUTF8(regScope))); MOZ_ASSERT(aScope.Equals(regScope));
#endif #endif
mServiceWorkerRegistrations.RemoveElement(registration);
MOZ_ASSERT(mServiceWorkerRegistrationListeners.Contains(aListener));
mServiceWorkerRegistrationListeners.RemoveElement(aListener);
return NS_OK; return NS_OK;
} }
void void
ServiceWorkerManager::FireEventOnServiceWorkerRegistrations( ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations(
ServiceWorkerRegistrationInfo* aRegistration, ServiceWorkerRegistrationInfo* aRegistration)
const nsAString& aName)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
nsTObserverArray<ServiceWorkerRegistrationBase*>::ForwardIterator it(mServiceWorkerRegistrations); nsTObserverArray<ServiceWorkerRegistrationListener*>::ForwardIterator it(mServiceWorkerRegistrationListeners);
while (it.HasMore()) { while (it.HasMore()) {
nsRefPtr<ServiceWorkerRegistrationBase> target = it.GetNext(); nsRefPtr<ServiceWorkerRegistrationListener> target = it.GetNext();
nsAutoString regScope; nsAutoString regScope;
target->GetScope(regScope); target->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty()); MOZ_ASSERT(!regScope.IsEmpty());
NS_ConvertUTF16toUTF8 utf8Scope(regScope); NS_ConvertUTF16toUTF8 utf8Scope(regScope);
if (utf8Scope.Equals(aRegistration->mScope)) { if (utf8Scope.Equals(aRegistration->mScope)) {
nsresult rv = target->DispatchTrustedEvent(aName); target->UpdateFound();
if (NS_WARN_IF(NS_FAILED(rv))) {
// Warn only.
}
} }
} }
} }
@ -2764,9 +2762,9 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
WhichServiceWorker aWhichOnes) WhichServiceWorker aWhichOnes)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
nsTObserverArray<ServiceWorkerRegistrationBase*>::ForwardIterator it(mServiceWorkerRegistrations); nsTObserverArray<ServiceWorkerRegistrationListener*>::ForwardIterator it(mServiceWorkerRegistrationListeners);
while (it.HasMore()) { while (it.HasMore()) {
nsRefPtr<ServiceWorkerRegistrationBase> target = it.GetNext(); nsRefPtr<ServiceWorkerRegistrationListener> target = it.GetNext();
nsAutoString regScope; nsAutoString regScope;
target->GetScope(regScope); target->GetScope(regScope);
MOZ_ASSERT(!regScope.IsEmpty()); MOZ_ASSERT(!regScope.IsEmpty());
@ -2774,7 +2772,7 @@ ServiceWorkerManager::InvalidateServiceWorkerRegistrationWorker(ServiceWorkerReg
NS_ConvertUTF16toUTF8 utf8Scope(regScope); NS_ConvertUTF16toUTF8 utf8Scope(regScope);
if (utf8Scope.Equals(aRegistration->mScope)) { if (utf8Scope.Equals(aRegistration->mScope)) {
target->InvalidateWorkerReference(aWhichOnes); target->InvalidateWorkers(aWhichOnes);
} }
} }
} }

View File

@ -36,7 +36,7 @@ class BackgroundChild;
namespace dom { namespace dom {
class ServiceWorkerRegistrationBase; class ServiceWorkerRegistrationListener;
namespace workers { namespace workers {
@ -338,7 +338,7 @@ public:
// The scope should be a fully qualified valid URL. // The scope should be a fully qualified valid URL.
nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mServiceWorkerRegistrationInfos; nsRefPtrHashtable<nsCStringHashKey, ServiceWorkerRegistrationInfo> mServiceWorkerRegistrationInfos;
nsTObserverArray<ServiceWorkerRegistrationBase*> mServiceWorkerRegistrations; nsTObserverArray<ServiceWorkerRegistrationListener*> mServiceWorkerRegistrationListeners;
nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments; nsRefPtrHashtable<nsISupportsHashKey, ServiceWorkerRegistrationInfo> mControlledDocuments;
@ -396,6 +396,13 @@ public:
void LoadRegistrations( void LoadRegistrations(
const nsTArray<ServiceWorkerRegistrationData>& aRegistrations); const nsTArray<ServiceWorkerRegistrationData>& aRegistrations);
NS_IMETHOD
AddRegistrationEventListener(const nsAString& aScope,
ServiceWorkerRegistrationListener* aListener);
NS_IMETHOD
RemoveRegistrationEventListener(const nsAString& aScope,
ServiceWorkerRegistrationListener* aListener);
private: private:
ServiceWorkerManager(); ServiceWorkerManager();
~ServiceWorkerManager(); ~ServiceWorkerManager();
@ -455,15 +462,7 @@ private:
const nsAString& aName); const nsAString& aName);
void void
FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration, FireUpdateFoundOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration);
const nsAString& aName);
void
FireUpdateFound(ServiceWorkerRegistrationInfo* aRegistration)
{
FireEventOnServiceWorkerRegistrations(aRegistration,
NS_LITERAL_STRING("updatefound"));
}
void void
FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration); FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);

View File

@ -142,7 +142,7 @@ ServiceWorkerRegistrationMainThread::StartListeningForEvents()
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(!mListeningForEvents); MOZ_ASSERT(!mListeningForEvents);
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) { if (swm) {
swm->AddRegistrationEventListener(mScope, this); swm->AddRegistrationEventListener(mScope, this);
mListeningForEvents = true; mListeningForEvents = true;
@ -157,7 +157,7 @@ ServiceWorkerRegistrationMainThread::StopListeningForEvents()
return; return;
} }
nsCOMPtr<nsIServiceWorkerManager> swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) { if (swm) {
swm->RemoveRegistrationEventListener(mScope, this); swm->RemoveRegistrationEventListener(mScope, this);
} }
@ -208,7 +208,13 @@ ServiceWorkerRegistrationMainThread::GetActive()
} }
void void
ServiceWorkerRegistrationMainThread::InvalidateWorkerReference(WhichServiceWorker aWhichOnes) ServiceWorkerRegistrationMainThread::UpdateFound()
{
DispatchTrustedEvent(NS_LITERAL_STRING("updatefound"));
}
void
ServiceWorkerRegistrationMainThread::InvalidateWorkers(WhichServiceWorker aWhichOnes)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) { if (aWhichOnes & WhichServiceWorker::INSTALLING_WORKER) {
@ -602,12 +608,6 @@ ServiceWorkerRegistrationWorkerThread::GetActive()
return nullptr; return nullptr;
} }
void
ServiceWorkerRegistrationWorkerThread::InvalidateWorkerReference(WhichServiceWorker aWhichOnes)
{
MOZ_CRASH("FIXME");
}
void void
ServiceWorkerRegistrationWorkerThread::Update() ServiceWorkerRegistrationWorkerThread::Update()
{ {

View File

@ -41,6 +41,24 @@ public:
}; };
// Used by ServiceWorkerManager to notify ServiceWorkerRegistrations of
// updatefound event and invalidating ServiceWorker instances.
class ServiceWorkerRegistrationListener
{
public:
NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
virtual void
UpdateFound() = 0;
virtual void
InvalidateWorkers(WhichServiceWorker aWhichOnes) = 0;
virtual void
GetScope(nsAString& aScope) const = 0;
};
class ServiceWorkerRegistrationBase : public DOMEventTargetHelper class ServiceWorkerRegistrationBase : public DOMEventTargetHelper
{ {
public: public:
@ -65,16 +83,6 @@ public:
virtual already_AddRefed<workers::ServiceWorker> virtual already_AddRefed<workers::ServiceWorker>
GetActive() = 0; GetActive() = 0;
void
GetScope(nsAString& aScope) const
{
aScope = mScope;
}
// Useful methods for ServiceWorkerManager:
virtual void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes) = 0;
protected: protected:
virtual ~ServiceWorkerRegistrationBase() virtual ~ServiceWorkerRegistrationBase()
{ } { }
@ -84,7 +92,8 @@ private:
nsCOMPtr<nsISupports> mCCDummy; nsCOMPtr<nsISupports> mCCDummy;
}; };
class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistrationBase class ServiceWorkerRegistrationMainThread final : public ServiceWorkerRegistrationBase,
public ServiceWorkerRegistrationListener
{ {
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -115,9 +124,6 @@ public:
already_AddRefed<PushManager> already_AddRefed<PushManager>
GetPushManager(ErrorResult& aRv); GetPushManager(ErrorResult& aRv);
void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes) override;
// DOMEventTargethelper // DOMEventTargethelper
void DisconnectFromOwner() override void DisconnectFromOwner() override
{ {
@ -125,6 +131,19 @@ public:
ServiceWorkerRegistrationBase::DisconnectFromOwner(); ServiceWorkerRegistrationBase::DisconnectFromOwner();
} }
// ServiceWorkerRegistrationListener
void
UpdateFound() override;
void
InvalidateWorkers(WhichServiceWorker aWhichOnes) override;
void
GetScope(nsAString& aScope) const override
{
aScope = mScope;
}
private: private:
~ServiceWorkerRegistrationMainThread(); ~ServiceWorkerRegistrationMainThread();
@ -182,7 +201,10 @@ public:
GetActive() override; GetActive() override;
void void
InvalidateWorkerReference(WhichServiceWorker aWhichOnes) override; GetScope(nsAString& aScope) const
{
aScope = mScope;
}
private: private:
~ServiceWorkerRegistrationWorkerThread() ~ServiceWorkerRegistrationWorkerThread()