Bug 1231213 - Implement cross-process ServiceWorkerGlobalScope.skipWaiting(). r=asuth

Differential Revision: https://phabricator.services.mozilla.com/D26175

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Perry Jiang 2019-08-13 04:57:44 +00:00
Родитель 8089eeb912
Коммит 5239719800
25 изменённых файлов: 291 добавлений и 23 удалений

Просмотреть файл

@ -19,4 +19,6 @@ UNIFIED_SOURCES += [
'AbortSignal.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -52,4 +52,6 @@ MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -42,6 +42,8 @@ UNIFIED_SOURCES += [
'PerformanceWorker.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -388,6 +388,34 @@ nsresult ServiceWorkerPrivateImpl::Initialize() {
return NS_OK;
}
RefPtr<GenericPromise> ServiceWorkerPrivateImpl::SetSkipWaitingFlag() {
AssertIsOnMainThread();
MOZ_ASSERT(mOuter);
MOZ_ASSERT(mOuter->mInfo);
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (!swm) {
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
RefPtr<ServiceWorkerRegistrationInfo> regInfo =
swm->GetRegistration(mOuter->mInfo->Principal(), mOuter->mInfo->Scope());
if (!regInfo) {
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
mOuter->mInfo->SetSkipWaitingFlag();
RefPtr<GenericPromise::Private> promise =
new GenericPromise::Private(__func__);
regInfo->TryToActivateAsync([promise] { promise->Resolve(true, __func__); });
return promise;
}
nsresult ServiceWorkerPrivateImpl::RefreshRemoteWorkerData(
const RefPtr<ServiceWorkerRegistrationInfo>& aRegistration) {
AssertIsOnMainThread();

Просмотреть файл

@ -52,6 +52,8 @@ class ServiceWorkerPrivateImpl final : public ServiceWorkerPrivate::Inner,
nsresult Initialize();
RefPtr<GenericPromise> SetSkipWaitingFlag();
private:
class RAIIActorPtrHolder;

Просмотреть файл

@ -294,16 +294,20 @@ ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId) {
return serviceWorker.forget();
}
void ServiceWorkerRegistrationInfo::TryToActivateAsync() {
void ServiceWorkerRegistrationInfo::TryToActivateAsync(
TryToActivateCallback&& aCallback) {
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
NewRunnableMethod("ServiceWorkerRegistrationInfo::TryToActivate", this,
&ServiceWorkerRegistrationInfo::TryToActivate)));
NewRunnableMethod<StoreCopyPassByRRef<TryToActivateCallback>>(
"ServiceWorkerRegistrationInfo::TryToActivate", this,
&ServiceWorkerRegistrationInfo::TryToActivate,
std::move(aCallback))));
}
/*
* TryToActivate should not be called directly, use TryToActivateAsync instead.
*/
void ServiceWorkerRegistrationInfo::TryToActivate() {
void ServiceWorkerRegistrationInfo::TryToActivate(
TryToActivateCallback&& aCallback) {
MOZ_ASSERT(NS_IsMainThread());
bool controlling = IsControllingClients();
bool skipWaiting = mWaitingWorker && mWaitingWorker->SkipWaitingFlag();
@ -311,6 +315,10 @@ void ServiceWorkerRegistrationInfo::TryToActivate() {
if (idle && (!controlling || skipWaiting)) {
Activate();
}
if (aCallback) {
aCallback();
}
}
void ServiceWorkerRegistrationInfo::Activate() {

Просмотреть файл

@ -7,6 +7,8 @@
#ifndef mozilla_dom_serviceworkerregistrationinfo_h
#define mozilla_dom_serviceworkerregistrationinfo_h
#include <functional>
#include "mozilla/dom/ServiceWorkerInfo.h"
#include "mozilla/dom/ServiceWorkerRegistrationBinding.h"
#include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
@ -68,6 +70,8 @@ class ServiceWorkerRegistrationInfo final
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEWORKERREGISTRATIONINFO
typedef std::function<void()> TryToActivateCallback;
ServiceWorkerRegistrationInfo(const nsACString& aScope,
nsIPrincipal* aPrincipal,
ServiceWorkerUpdateViaCache aUpdateViaCache);
@ -120,9 +124,9 @@ class ServiceWorkerRegistrationInfo final
bool IsCorrupt() const;
void TryToActivateAsync();
void TryToActivateAsync(TryToActivateCallback&& aCallback = nullptr);
void TryToActivate();
void TryToActivate(TryToActivateCallback&& aCallback);
void Activate();

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/dom/ErrorEventBinding.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/ServiceWorkerManager.h"
#include "mozilla/dom/ServiceWorkerUtils.h"
#include "mozilla/dom/SimpleGlobalObject.h"
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
@ -80,15 +81,28 @@ class ReportErrorRunnable final : public WorkerDebuggeeRunnable {
// worker error reporting will crash. Instead, pass the error to
// the ServiceWorkerManager to report on any controlled documents.
if (aWorkerPrivate->IsServiceWorker()) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), mReport->mMessage,
mReport->mFilename, mReport->mLine,
mReport->mLineNumber, mReport->mColumnNumber,
mReport->mFlags, mReport->mExnType);
if (ServiceWorkerParentInterceptEnabled()) {
RefPtr<RemoteWorkerChild> actor(
aWorkerPrivate->GetRemoteWorkerControllerWeakRef());
Unused << NS_WARN_IF(!actor);
if (actor) {
actor->ErrorPropagationOnMainThread(nullptr, false);
}
} else {
RefPtr<ServiceWorkerManager> swm =
ServiceWorkerManager::GetInstance();
if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), EmptyString(),
EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
JSEXN_ERR);
}
}
return true;
}
@ -159,14 +173,27 @@ class ReportGenericErrorRunnable final : public WorkerDebuggeeRunnable {
}
if (aWorkerPrivate->IsServiceWorker()) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), EmptyString(),
EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
JSEXN_ERR);
if (ServiceWorkerParentInterceptEnabled()) {
RefPtr<RemoteWorkerChild> actor(
aWorkerPrivate->GetRemoteWorkerControllerWeakRef());
Unused << NS_WARN_IF(!actor);
if (actor) {
actor->ErrorPropagationOnMainThread(nullptr, false);
}
} else {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
if (swm) {
swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
aWorkerPrivate->ServiceWorkerScope(),
aWorkerPrivate->ScriptURL(), EmptyString(),
EmptyString(), EmptyString(), 0, 0, JSREPORT_ERROR,
JSEXN_ERR);
}
}
return true;
}

Просмотреть файл

@ -36,6 +36,7 @@
#include "mozilla/dom/PerformanceStorageWorker.h"
#include "mozilla/dom/PromiseDebugging.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/RemoteWorkerService.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/WorkerBinding.h"
#include "mozilla/StorageAccess.h"
@ -53,6 +54,7 @@
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsPrintfCString.h"
#include "nsProxyRelease.h"
#include "nsQueryObject.h"
#include "nsRFPService.h"
#include "nsSandboxFlags.h"
@ -4846,6 +4848,40 @@ RemoteWorkerChild* WorkerPrivate::GetRemoteWorkerController() {
return mRemoteWorkerController;
}
void WorkerPrivate::SetRemoteWorkerControllerWeakRef(
ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef) {
MOZ_ASSERT(aWeakRef);
MOZ_ASSERT(!mRemoteWorkerControllerWeakRef);
MOZ_ASSERT(IsServiceWorker());
mRemoteWorkerControllerWeakRef = std::move(aWeakRef);
}
ThreadSafeWeakPtr<RemoteWorkerChild>
WorkerPrivate::GetRemoteWorkerControllerWeakRef() {
MOZ_ASSERT(IsServiceWorker());
return mRemoteWorkerControllerWeakRef;
}
RefPtr<GenericPromise> WorkerPrivate::SetServiceWorkerSkipWaitingFlag() {
AssertIsOnWorkerThread();
MOZ_ASSERT(IsServiceWorker());
RefPtr<RemoteWorkerChild> rwc(mRemoteWorkerControllerWeakRef);
if (!rwc) {
return GenericPromise::CreateAndReject(NS_ERROR_DOM_ABORT_ERR, __func__);
}
RefPtr<GenericPromise> promise =
rwc->MaybeSendSetServiceWorkerSkipWaitingFlag();
NS_ProxyRelease("WorkerPrivate::mRemoteWorkerControllerWeakRef",
RemoteWorkerService::Thread(), rwc.forget());
return promise;
}
nsAString& WorkerPrivate::Id() {
AssertIsOnMainThread();

Просмотреть файл

@ -12,14 +12,17 @@
#include "mozilla/Attributes.h"
#include "mozilla/CondVar.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RelativeTimeline.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/ThreadSafeWeakPtr.h"
#include "nsContentUtils.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIEventTarget.h"
#include "nsTObserverArray.h"
#include "js/ContextOptions.h"
#include "mozilla/dom/RemoteWorkerChild.h"
#include "mozilla/dom/Worker.h"
#include "mozilla/dom/WorkerLoadInfo.h"
#include "mozilla/dom/workerinternals/JSSettings.h"
@ -43,7 +46,6 @@ class Function;
class MessagePort;
class MessagePortIdentifier;
class PerformanceStorage;
class RemoteWorkerChild;
class TimeoutHandler;
class WorkerControlRunnable;
class WorkerCSPEventListener;
@ -789,6 +791,13 @@ class WorkerPrivate : public RelativeTimeline {
void SetRemoteWorkerController(RemoteWorkerChild* aController);
void SetRemoteWorkerControllerWeakRef(
ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef);
ThreadSafeWeakPtr<RemoteWorkerChild> GetRemoteWorkerControllerWeakRef();
RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag();
// We can assume that an nsPIDOMWindow will be available for Freeze, Thaw
// as these are only used for globals going in and out of the bfcache.
bool Freeze(nsPIDOMWindowInner* aWindow);
@ -1065,6 +1074,9 @@ class WorkerPrivate : public RelativeTimeline {
// Only touched on the parent thread. This is set only if IsSharedWorker().
RefPtr<RemoteWorkerChild> mRemoteWorkerController;
// This is set only if IsServiceWorker().
ThreadSafeWeakPtr<RemoteWorkerChild> mRemoteWorkerControllerWeakRef;
JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init
TimeStamp mKillTime;
WorkerStatus mParentStatus;

Просмотреть файл

@ -25,6 +25,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseWorkerProxy.h"
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
#include "mozilla/dom/ServiceWorkerUtils.h"
#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/SimpleGlobalObject.h"
#include "mozilla/dom/TimeoutHandler.h"
@ -858,6 +859,21 @@ already_AddRefed<Promise> ServiceWorkerGlobalScope::SkipWaiting(
return nullptr;
}
if (ServiceWorkerParentInterceptEnabled()) {
mWorkerPrivate->SetServiceWorkerSkipWaitingFlag()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[promise](bool aOk) {
Unused << NS_WARN_IF(!aOk);
promise->MaybeResolveWithUndefined();
},
[promise](nsresult aRv) {
MOZ_ASSERT(NS_FAILED(aRv));
promise->MaybeResolveWithUndefined();
});
return promise.forget();
}
RefPtr<PromiseWorkerProxy> promiseProxy =
PromiseWorkerProxy::Create(mWorkerPrivate, promise);
if (!promiseProxy) {

Просмотреть файл

@ -71,6 +71,7 @@ LOCAL_INCLUDES += [
'/dom/base',
'/dom/bindings',
'/dom/system',
'/dom/workers/remoteworkers',
'/js/xpconnect/loader',
'/netwerk/base',
'/xpcom/build',

Просмотреть файл

@ -69,6 +69,8 @@ parent:
async Close();
async SetServiceWorkerSkipWaitingFlag() returns (bool aOk);
child:
async PFetchEventOpProxy(ServiceWorkerFetchEventOpArgs aArgs);

Просмотреть файл

@ -25,6 +25,8 @@ protocol PRemoteWorkerController {
async Terminated();
async SetServiceWorkerSkipWaitingFlag() returns (bool aOk);
parent:
async PFetchEventOp(ServiceWorkerFetchEventOpArgs aArgs);

Просмотреть файл

@ -454,6 +454,9 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(RemoteWorkerData&& aData) {
}
if (mIsServiceWorker) {
RefPtr<RemoteWorkerChild> self = this;
workerPrivate->SetRemoteWorkerControllerWeakRef(
ThreadSafeWeakPtr<RemoteWorkerChild>(self));
} else {
workerPrivate->SetRemoteWorkerController(this);
}
@ -927,6 +930,42 @@ IPCResult RemoteWorkerChild::RecvExecServiceWorkerOp(
return IPC_OK();
}
RefPtr<GenericPromise>
RemoteWorkerChild::MaybeSendSetServiceWorkerSkipWaitingFlag() {
RefPtr<GenericPromise::Private> promise =
new GenericPromise::Private(__func__);
RefPtr<RemoteWorkerChild> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__, [self = std::move(
self),
promise] {
MOZ_ACCESS_THREAD_BOUND(self->mLauncherData, launcherData);
if (!launcherData->mIPCActive) {
promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
self->SendSetServiceWorkerSkipWaitingFlag()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[promise](
const SetServiceWorkerSkipWaitingFlagPromise::ResolveOrRejectValue&
aResult) {
if (NS_WARN_IF(aResult.IsReject())) {
promise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__);
return;
}
promise->Resolve(aResult.ResolveValue(), __func__);
});
});
GetOwningEventTarget()->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
return promise;
}
/**
* PFetchEventOpProxy methods
*/

Просмотреть файл

@ -63,7 +63,7 @@ class RemoteWorkerChild final
RefPtr<GenericNonExclusivePromise> GetTerminationPromise();
void CloseWorkerOnMainThread();
RefPtr<GenericPromise> MaybeSendSetServiceWorkerSkipWaitingFlag();
private:
class InitializeWorkerRunnable;

Просмотреть файл

@ -278,6 +278,21 @@ RefPtr<ServiceWorkerOpPromise> RemoteWorkerController::ExecServiceWorkerOp(
return promise;
}
RefPtr<GenericPromise> RemoteWorkerController::SetServiceWorkerSkipWaitingFlag()
const {
AssertIsOnBackgroundThread();
MOZ_ASSERT(mObserver);
RefPtr<GenericPromise::Private> promise =
new GenericPromise::Private(__func__);
static_cast<RemoteWorkerControllerParent*>(mObserver.get())
->MaybeSendSetServiceWorkerSkipWaitingFlag(
[promise](bool aOk) { promise->Resolve(aOk, __func__); });
return promise;
}
RemoteWorkerController::PendingSharedWorkerOp::PendingSharedWorkerOp(
Type aType, uint64_t aWindowID)
: mType(aType), mWindowID(aWindowID) {

Просмотреть файл

@ -135,6 +135,8 @@ class RemoteWorkerController final {
RefPtr<ServiceWorkerOpPromise> ExecServiceWorkerOp(
ServiceWorkerOpArgs&& aArgs);
RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag() const;
private:
RemoteWorkerController(const RemoteWorkerData& aData,
RemoteWorkerObserver* aObserver);

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsError.h"
#include "nsThreadUtils.h"
#include "ServiceWorkerPrivateImpl.h"
#include "mozilla/Assertions.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Unused.h"
@ -96,6 +97,27 @@ IPCResult RemoteWorkerControllerChild::RecvTerminated() {
return IPC_OK();
}
IPCResult RemoteWorkerControllerChild::RecvSetServiceWorkerSkipWaitingFlag(
SetServiceWorkerSkipWaitingFlagResolver&& aResolve) {
AssertIsOnMainThread();
if (mObserver) {
static_cast<ServiceWorkerPrivateImpl*>(mObserver.get())
->SetSkipWaitingFlag()
->Then(GetCurrentThreadSerialEventTarget(), __func__,
[resolve = std::move(aResolve)](
const GenericPromise::ResolveOrRejectValue& aResult) {
resolve(aResult.IsResolve() ? aResult.ResolveValue() : false);
});
return IPC_OK();
}
aResolve(false);
return IPC_OK();
}
void RemoteWorkerControllerChild::RevokeObserver(
RemoteWorkerObserver* aObserver) {
AssertIsOnMainThread();

Просмотреть файл

@ -48,6 +48,9 @@ class RemoteWorkerControllerChild final : public PRemoteWorkerControllerChild {
mozilla::ipc::IPCResult RecvTerminated();
mozilla::ipc::IPCResult RecvSetServiceWorkerSkipWaitingFlag(
SetServiceWorkerSkipWaitingFlagResolver&& aResolve);
RefPtr<RemoteWorkerObserver> mObserver;
bool mIPCActive = true;

Просмотреть файл

@ -42,6 +42,25 @@ RefPtr<RemoteWorkerParent> RemoteWorkerControllerParent::GetRemoteWorkerParent()
return mRemoteWorkerController->mActor;
}
void RemoteWorkerControllerParent::MaybeSendSetServiceWorkerSkipWaitingFlag(
std::function<void(bool)>&& aCallback) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(aCallback);
if (!mIPCActive) {
aCallback(false);
return;
}
SendSetServiceWorkerSkipWaitingFlag()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[callback = std::move(aCallback)](
const SetServiceWorkerSkipWaitingFlagPromise::ResolveOrRejectValue&
aResult) {
callback(aResult.IsResolve() ? aResult.ResolveValue() : false);
});
}
RemoteWorkerControllerParent::~RemoteWorkerControllerParent() {
AssertIsOnBackgroundThread();
MOZ_ASSERT(!mIPCActive);

Просмотреть файл

@ -31,6 +31,9 @@ class RemoteWorkerControllerParent final : public PRemoteWorkerControllerParent,
// Returns the corresponding RemoteWorkerParent (if any).
RefPtr<RemoteWorkerParent> GetRemoteWorkerParent() const;
void MaybeSendSetServiceWorkerSkipWaitingFlag(
std::function<void(bool)>&& aCallback);
private:
~RemoteWorkerControllerParent();

Просмотреть файл

@ -165,5 +165,22 @@ void RemoteWorkerParent::SetController(RemoteWorkerController* aController) {
mController = aController;
}
IPCResult RemoteWorkerParent::RecvSetServiceWorkerSkipWaitingFlag(
SetServiceWorkerSkipWaitingFlagResolver&& aResolve) {
AssertIsOnBackgroundThread();
MOZ_ASSERT(XRE_IsParentProcess());
if (mController) {
mController->SetServiceWorkerSkipWaitingFlag()->Then(
GetCurrentThreadSerialEventTarget(), __func__,
[resolve = aResolve](bool /* unused */) { resolve(true); },
[resolve = aResolve](nsresult /* unused */) { resolve(false); });
} else {
aResolve(false);
}
return IPC_OK();
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -44,6 +44,9 @@ class RemoteWorkerParent final : public PRemoteWorkerParent {
mozilla::ipc::IPCResult RecvCreated(const bool& aStatus);
mozilla::ipc::IPCResult RecvSetServiceWorkerSkipWaitingFlag(
SetServiceWorkerSkipWaitingFlagResolver&& aResolve);
bool mDeleteSent = false;
RefPtr<RemoteWorkerController> mController;
};

Просмотреть файл

@ -28,6 +28,7 @@ UNIFIED_SOURCES += [
]
LOCAL_INCLUDES += [
'/dom/serviceworkers',
'/xpcom/build',
]