Files
tubestation/toolkit/components/extensions/webidl-api/ExtensionBrowser.h
Luca Greco a5eef525d5 Bug 1728327 - Track ExtensionEventListener a background service worker registered by the time it is fully loaded. r=baku
This patch includes a proposed approach to keep track of the WebExtensions API event listeners
subscribed synchronously while the background service worker script was being loaded and executed,
because this are the listeners that we can assume to be available right after we spawn a worker
and be able to handle the API event that triggered the worker to be spawned.

The information about the "listeners subscribed synchronously while the worker script is being
loaded and executed" is then used by the ExtensionBrowser::HasWakeupEventListener method,
which will be called as part of handling the nsIServiceWorkerManager.wakeForExtensionAPIEvent
call.

Differential Revision: https://phabricator.services.mozilla.com/D130758
2021-12-15 18:29:37 +00:00

130 lines
4.8 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_extensions_ExtensionBrowser_h
#define mozilla_extensions_ExtensionBrowser_h
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
class nsIGlobalObject;
namespace mozilla {
class ErrorResult;
namespace extensions {
class ExtensionAlarms;
class ExtensionMockAPI;
class ExtensionPort;
class ExtensionRuntime;
class ExtensionTest;
bool ExtensionAPIAllowed(JSContext* aCx, JSObject* aGlobal);
void CreateAndDispatchInitWorkerContextRunnable();
already_AddRefed<Runnable> CreateWorkerLoadedRunnable(
const uint64_t aServiceWorkerDescriptorId,
const nsCOMPtr<nsIURI>& aWorkerBaseURI);
already_AddRefed<Runnable> CreateWorkerDestroyedRunnable(
const uint64_t aServiceWorkerDescriptorId,
const nsCOMPtr<nsIURI>& aWorkerBaseURI);
// An HashMap used to keep track of listeners registered synchronously while
// the worker script is executing, used internally by nsIServiceWorkerManager
// wakeforExtensionAPIEvent method to resolve to true if the worker script
// spawned did have a listener subscribed for the related API event name.
class ExtensionEventWakeupMap final
: public nsTHashMap<nsStringHashKey, uint64_t> {
static void ToMapKey(const nsAString& aAPINamespace,
const nsAString& aAPIName, nsAString& aResultMapKey);
public:
nsresult IncrementListeners(const nsAString& aAPINamespace,
const nsAString& aAPIName);
nsresult DecrementListeners(const nsAString& aAPINamespace,
const nsAString& aAPIName);
bool HasListener(const nsAString& aAPINamespace, const nsAString& aAPIName);
};
class ExtensionBrowser final : public nsISupports, public nsWrapperCache {
nsCOMPtr<nsIGlobalObject> mGlobal;
JS::Heap<JS::Value> mLastError;
bool mCheckedLastError;
RefPtr<ExtensionAlarms> mExtensionAlarms;
RefPtr<ExtensionMockAPI> mExtensionMockAPI;
RefPtr<ExtensionRuntime> mExtensionRuntime;
RefPtr<ExtensionTest> mExtensionTest;
nsTHashMap<nsStringHashKey, WeakPtr<ExtensionPort>> mPortsLookup;
// `[APINamespace].[APIName]` => int64 (listeners count)
ExtensionEventWakeupMap mExpectedEventWakeupMap;
~ExtensionBrowser() = default;
public:
explicit ExtensionBrowser(nsIGlobalObject* aGlobal);
// Helpers used for the expected behavior of the browser.runtime.lastError
// and browser.extension.lastError.
void SetLastError(JS::Handle<JS::Value> aLastError);
void GetLastError(JS::MutableHandle<JS::Value> aRetVal);
// ClearLastError is used by ChromeCompatCallbackHandler::RejectedCallback
// to clear the lastError property. When this method returns true the
// caller will know that the error value wasn't checked by the callback and
// should be reported to the console
bool ClearLastError();
// Helpers used to keep track of the event listeners added during the
// initial sync worker script execution.
nsresult TrackWakeupEventListener(JSContext* aCx,
const nsString& aAPINamespace,
const nsString& aAPIName);
nsresult UntrackWakeupEventListener(JSContext* aCx,
const nsString& aAPINamespace,
const nsString& aAPIName);
bool HasWakeupEventListener(const nsString& aAPINamespace,
const nsString& aAPIName);
// Helpers used for the ExtensionPort.
// Get an ExtensionPort instance given its port descriptor (returns an
// existing port if an instance is still tracked in the ports lookup table,
// otherwise it creates a new one).
already_AddRefed<ExtensionPort> GetPort(
JS::Handle<JS::Value> aDescriptorValue, ErrorResult& aRv);
// Remove the entry for an ExtensionPort tracked in the ports lookup map
// given its portId (called from the ExtensionPort destructor when the
// instance is being released).
void ForgetReleasedPort(const nsAString& aPortId);
// nsWrapperCache interface methods
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
// DOM bindings methods
nsIGlobalObject* GetParentObject() const;
ExtensionAlarms* GetExtensionAlarms();
ExtensionMockAPI* GetExtensionMockAPI();
ExtensionRuntime* GetExtensionRuntime();
ExtensionTest* GetExtensionTest();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ExtensionBrowser)
};
} // namespace extensions
} // namespace mozilla
#endif // mozilla_extensions_ExtensionBrowser_h