diff --git a/devtools/docs/contributor/backend/actor-hierarchy.md b/devtools/docs/contributor/backend/actor-hierarchy.md index 2b8277aa77e1d..f6c53900eaa6f 100644 --- a/devtools/docs/contributor/backend/actor-hierarchy.md +++ b/devtools/docs/contributor/backend/actor-hierarchy.md @@ -1,47 +1,89 @@ # How actors are organized -To start with, actors are living within devtools/server/actors folder. +tl;dr; The Root actor exposes Descriptor actors which describe a debuggable context. +The Descriptor then exposes a dedicated Watcher actor. +The Watcher actor notifies about many target actors (one per smaller debuggable context: WindowGlobal, worker,...) +and also notifies about all resources (console messages, sources, network events,...). + +To start with, actors are living within [devtools/server/actors][actors-folder] folder. They are organized in a hierarchy for easier lifecycle and memory management: once a parent is removed from the pool, its children are removed as well. -(See actor-registration.md for more information about how to implement one) +(See [actor-registration.md](actor-registration.md) for more information about how to implement a new one) The overall hierarchy of actors looks like this: ``` -RootActor: First one, automatically instantiated when we start connecting. - | Mostly meant to instantiate new actors. + ### RootActor: + | + | First one, automatically instantiated when we start connecting + | with a fixed actor ID set to "root". + | + | It is mostly meant to instantiate all the following actors. + | + |-- Global-scoped actors: + | + | Actors exposing features related to the main process, that are not + | specific to any particular target (document, tab, add-on, or worker). + | These actors are registered with `global: true` in: + | devtools/server/actors/utils/actor-registry.js + | + | Examples: + | * PreferenceActor (for Firefox prefs) + | * DeviceActor (for fetching and toggling runtime specifics) + | * PerfActor (used by the profiler.firefox.com profiler) + | * ... + | + \-- Descriptor actors + | + | These actors expose information about a particular context that DevTools can focus on: + | * a tab (TabDescriptor) + | * a (service/shared/chrome) worker (WorkerDescriptor) + | * a Web Extension (WebExtensionDescriptor) + | * the browser (ProcessDescriptor) | - |-- Global-scoped actors: - | Actors exposing features related to the main process, that are not - | specific to any particular target (document, tab, add-on, or worker). - | These actors are registered with `global: true` in - | devtools/server/actors/utils/actor-registry.js - | Examples include: - | PreferenceActor (for Firefox prefs) + | This actor is mostly informative. It exposes a WatcherActor to actually debug this context. + | This is typically used by about:debugging to display all available debuggable contexts. | - \-- Descriptor Actor's -or- Watcher Actor - | - \ -- Target actors: - Actors that represent the main "thing" being targeted by a given toolbox, - such as a tab, frame, worker, add-on, etc. and track its lifetime. - Generally, there is a target actor for each thing you can point a - toolbox at. - Examples include: - WindowGlobalTargetActor (for a WindowGlobal, such as a tab or a remote iframe) - ProcessTargetActor - WorkerTargetActor (for various kind of workers) - | - \-- Target-scoped actors: - Actors exposing one particular feature set. They are children of a - given target actor and the data they return is filtered to reflect - the target. - These actors are registered with `target: true` in - devtools/server/actors/utils/actor-registry.js - Examples include: - WebConsoleActor - InspectorActor - These actors may extend this hierarchy by having their own children, - like LongStringActor, WalkerActor, etc. + \ -- WatcherActor + | + | Each descriptor actor exposes a dedicated Watcher actor instance. + | This actor allows to observe target actors and resources. + | + \ -- Target actors: + | + | Within a given descriptor/watcher context, targets represents fine grained debuggable contexts. + | While the descriptor and watcher stays alive until the devtools are closed or the debuggable context + | was close (tab closed, worker destroyed or browser closed), + | the targets have a shorter lifecycle and a narrowed scope. + | + | The typical target actors are WindowGlobal target actors. + | This represents one specific WindowGlobal. A tab is typically made of many of them. + | Each iframe will have its dedicated WindowGlobal. + | Each navigation will also spawn a new dedicated WindowGlobal. + | When debugging an add-on, you will have one WindowGlobal target for the background page, + | one for each popup, ... + | + | The other targets actors are: + | * worker targets + | * process targets (only used in the Browser Toolbox to debug the browser itself made of many processes) + | + \ -- Target-scoped actors: + + Actors exposing one particular feature set. They are children of a + given target actor and the data they return is filtered to reflect + the target. + These actors are registered with `target: true` in + devtools/server/actors/utils/actor-registry.js + + Examples: + * WebConsoleActor (for evaluating javascript) + * InspectorActor (to observe and modify the DOM Elements) + * ThreadActor (for setting breakpoints and pause/step/resume) + * StorageActor (for managing storage data) + * AccessibilityActor (to observe accessibility information) + + These actors may extend this hierarchy by having their own children, + like LongStringActor, WalkerActor, SourceActor, NodeActor, etc. ``` ## RootActor @@ -50,84 +92,95 @@ The root actor is special. It is automatically created when a client connects. It has a special `actorID` which is unique and is "root". All other actors have an `actorID` which is computed dynamically, so that you need to ask an existing actor to create an Actor -and returns its `actorID`. That's the main role of RootActor. +and returns its `actorID`. +That's the main role of RootActor. It will expose all the descriptor actors, +which is only the start of spawning the watcher, target and target-scoped actors. ``` RootActor (root.js) | |-- TabDescriptorActor (descriptors/tab.js) - | Targets frames (such as a tab) living in the parent or child process. + | + | Designates tabs running in the parent or child process. + | | Returned by "listTabs" or "getTab" requests. | - |-- WorkerTargetActor (worker.js) - | Targets a worker (applies to various kinds like web worker, service - | worker, etc.). - | Returned by "listWorkers" request to the root actor to get all workers. + |-- WorkerDescriptorActor (descriptors/worker.js) + | + | Designates any type of worker: web worker, service worker, shared worker, chrome worker. + | + | Returned by "listWorkers" request to the root actor to get all workers. (/!\ this is an expensive method) | Returned by "listWorkers" request to a WindowGlobalTargetActor to get - | workers for a specific document/WindowGlobal. + | workers for a specific document/WindowGlobal. (this is a legacy, to be removed codepath) | Returned by "listWorkers" request to a ContentProcessTargetActor to get - | workers for the chrome of the child process. + | workers for the chrome of the child process. (this is a legacy, to be removed codepath) | - |-- ParentProcessTargetActor (parent-process.js) - | Targets all resources in the parent process of Firefox (chrome documents, - | JSMs, JS XPCOM, etc.). - | Extends the abstract class WindowGlobalTargetActor. - | Extended by WebExtensionTargetActor. - | Returned by "getProcess" request without any argument. + |-- ParentProcessDescriptorActor (descriptors/process.js) | - |-- ContentProcessTargetActor (content-process.js) - | Targets all resources in a content process of Firefox (chrome sandboxes, - | frame scripts, documents, etc.) - | Returned by "getProcess" request with a id argument, matching the - | targeted process. + | Designates any parent or content processes. + | This exposes all chrome documents, JSMs/ESMs, JS XPCOM, etc. | - \-- WebExtensionActor (addon/webextension.js) - Represents a WebExtension add-on in the parent process. This gives some - metadata about the add-on and watches for uninstall events. This uses a - proxy to access the actual WebExtension in the WebExtension process via - the message manager. + | Returned by "listProcesses" and "getProcess". + | + \-- WebExtensionDescriptorActor (descriptors/webextension.js) + + Designates a WebExtension add-on in the parent process. This gives some + metadata about the add-on and watches for uninstall events. + Returned by "listAddons" request. - | - \-- WebExtensionTargetActor (targets/webextension.js) - Targets a WebExtension add-on. This runs in the WebExtension process. - The client issues an additional "connect" request to - WebExtensionActor to get this actor, which is different from the - approach used for frame target actors. - Extends ParentProcessTargetActor. - Returned by "connect" request to WebExtensionActor. ``` All these descriptor actors expose a `getTarget()` method which -returns the target actor for the descriptor's debuggable context -(tab, worker, process or add-on). +returns the target actor for the descriptor's debuggable context. But note that this is now considered as a deprecated codepath. Ideally, all targets should be retrieved via the new WatcherActor. For now, the WatcherActor only support tabs and entire browser debugging. Workers and add-ons still have to go through descriptor's getTarget. +## Watcher Actors + +Each descriptor exposes a dedicated Watcher actor (via getWatcher RDP method), +which is scoped to the debuggable context of the descriptor. + +This actor is about observing things. +It will notify you about: +* target actors via target-available-form and target-destroyed-form, +* resources via resource-available-form, resource-updated-form and resource-destroyed-form. + +## Resources + +Resources aren't necessary actors. That can be simple JSON objects describing a particular part of the Web. +Resources can be describing a console message, a JS source, a network event, ... + +Each resource is being observed by a dedicated ResourceWatcher class implemented in [devtools/server/actors/resources/][resources-folder] +where the index.js registers all the resource types. + +These `ResourceWatcher` classes should implement a `watch()` method to start watching for a given resource type +and a `destroy()` method to stop watching. One new instance will be instantiated each time we start watching for a given type. + +These classes can be instantiated in various ways: +* just from the parent process if the resource can only be observed from there (ex: network events and some storages). + In such case, the watch method will receive a watcher actor as argument. +* just from the target's thread, which can be a tab thread, or a worker thread. + In such case, the watch method will receive a target actor as argument. + ## Target Actors -Those are the actors exposed by the watcher actor, or, via descriptor's getTarget methods. -They are meant to track the lifetime of a given target: document, process, add-on, or worker. -It also allows to fetch the target-scoped actors connected to this target, -which are actors like console, inspector, thread (for debugger), style inspector, etc. +Those are the actors exposed by the watcher actor `target-available-form` event , or, via descriptor's `getTarget()` methods. +They are meant to track the lifetime of a very precise debuggable piece of the descriptor context: +* One precise document instance, also called `WindowGlobal`, +* One worker, +* One parent or content process. -Some target actors inherit from WindowGlobalTargetActor (defined in -window-global.js) which is meant for "window globals" which present -documents to the user. It automatically tracks the lifetime of the targeted -window global, but it also tracks its iframes and allows switching the -target to one of its iframes. +Its main purpose is to expose the target-scoped actor IDs, all contained in the target form. +The target form is exposed by watcher actor `target-available-form` event (or via the now deprecated descriptor's `getTarget()` method). -For historical reasons, target actors also handle creating the ThreadActor, used -to manage breakpoints in the debugger. Actors inheriting from -WindowGlobalTargetActor expose `attach`/`detach` requests, that allows to -start/stop the ThreadActor. +The target will be destroyed as soon as the related debuggable context. -Target-scoped actors are accessed via the target actor's RDP form which contains -the `actorID` for each target-scoped actor. +For historical reasons, target actors also handle creating the ThreadActor, used +to manage breakpoints in the debugger. -The target-scoped actors expect to find the following properties on the target -actor: +The target-scoped actors expect to find the following properties on the target actor: - threadActor: ThreadActor instance for the given target, only defined once `attach` request is called, or on construction. @@ -165,7 +218,7 @@ children of a given target actor. The data they return is filtered to reflect the target. For example, the InspectorActor that you fetch from a WindowGlobalTargetActor gives you information -about the markup and styles for only that frame. +about the markup and styles only for the context of the target. These actors may extend this hierarchy by having their own children, like LongStringActor, WalkerActor, etc. @@ -175,3 +228,9 @@ actor lists the actor ID for each one, but the actor modules aren't actually loaded and instantiated at that point. Once the first request for a given target-scoped actor is received by the server, that specific actor is instantiated just in time to service the request. + +The actor IDs of all these actors can be retrieve in the "form" of each target actor. +The "form" is notified by the Watcher actor via `target-avaible-form` RDP packet. + +[actors-folder]: https://searchfox.org/mozilla-central/source/devtools/server/actors/ +[resources-folder]: https://searchfox.org/mozilla-central/source/devtools/server/actors/resources/