See presentation slides about the WebAppProvider system architecture.
Use chrome://web-app-internals (generated here) to inspect internal web app state. Test failures will print this information out automatically to help with debugging.
The codebase has a number of useful DVLOGs (like in web_app_command_manager.cc and web_app_lock_manager.cc). Use the normal vmodule command line args to see these (e.g. --vmodule=web_app*=1).
For developers wanting to test the behavior of the web app itself, Chrome DevTools Protocol can be used. See Instruction of using PWA via CDP.
The task of turning websites into “apps” in the user's OS environment has many parts to it. Before going into the parts, here is where they live:
See the drawing source here.
WebAppProvider core system lives on the Profile object.WebAppUiManagerImpl also lives on the Profile object (to avoid deps issues).AppBrowserController (typically WebAppBrowserController for our interests) lives on the Browser object.WebAppTabHelper lives on the WebContents object.While most on-disk storage is done in the WebAppSyncBridge, the system also sometimes uses the PrefService. Most of these prefs live on the Profile (profile->GetPrefs()), but some prefs are in the global browser prefs (g_browser_process->local_state()).
Presentation: https://tinyurl.com/dpwa-architecture-public
Older presentation: https://tinyurl.com/bmo-public
The safest way to use the WebAppProvider system is using the WebAppCommandScheduler (via WebAppProvider::scheduler()), which serves as an entry point for operations on the system for safely reading or writing state. Unsafe state access is available via WebAppProvider::registrar_unsafe(), but this in not guaranteed to be consistent as an async operation could be occurring at any time (install, uninstall, update, etc).
For information about creating safe read/write operations on the system, see the commands README.md.
The goal is to have all of these behind an abstraction that has a fake to allow easy unit testing of our system. Some of these dependencies are behind a nice fake-able interface, and some are not (yet).
PreinstalledWebAppManager.content::WebContents: The WebAppProvider system interacts with content::WebContents for various tasks like loading URLs (via WebAppUrlLoader), retrieving web app manifest data and icons (via WebAppDataRetriever and WebAppIconDownloader respectively), and observing navigations and destruction. The WebContentsManager serves as a centralized point of dependency for these interactions and acts as a factory for these components, allowing for easier management and faking in tests via the FakeWebContentsManager.OsIntegrationManger and the respective sub-managers own this.FakeWebAppProvider.WebAppUiManager, and faked by the FakeWebAppUiManager.These store data for our system. Some of it is per-web-app, and some of it is global.
WebAppRegistrar: This attempts to unify the reading of much of this data, and also holds an in-memory copy of the database data (in WebApp objects).WebAppDatabase / WebAppSyncBridge: This stores the web_app.proto object in a database, which is the preferred place to store information about a web app.WebAppIconManager and stored on disk in the user's profile.PrefService is used to store information that is either global, or needs to persist after a web app is uninstalled. Most of these prefs live on the Profile (profile->GetPrefs()), but some prefs are in the global browser prefs (g_browser_process->local_state()). Some users of prefs:Accessing any of this information without an applicable ‘lock’ on the system is considered unsafe.
The WebAppProvider is the per-profile object housing most of the various web app subsystems, acting as the “main()” of the web app implementation where everything starts. Unit tests use the FakeWebAppProvider version which allows tests to swap out some managers with fakes (and does this by default for a few).
The objects that live on the WebAppProvider, often called ‘Managers’, are used to encapsulate common responsibilities or in-memory state that needs to be stored. See the respective header files for more detailed information:
WebAppCommandManager & WebAppCommandScheduler: The entry point for performing asynchronous operations safely via locks.WebAppRegistrar: Provides a queryable in-memory view of all installed web apps.WebAppSyncBridge: Synchronizes the in-memory registrar with the on-disk database and Chrome Sync; faked with an in-memory database and sync disabled by default.WebAppInstallManager: Orchestrates the installation of web apps.ManifestUpdateManager: Monitors and applies updates to web app manifests.ExternallyManagedAppManager: Handles installations from external sources like policies or preinstalled configurations.WebAppPolicyManager: Manages apps installed via enterprise policy.PreinstalledWebAppManager: Manages the installation of default “preinstalled” web apps.WebAppIconManager: Manages the loading and storage of app icons on disk.OsIntegrationManager: Manages all integrations with the host operating system. FakeOsIntegrationManager is used by default in unit tests.WebAppUiManager: Interface for performing UI operations like showing dialogs. FakeWebAppUiManager is used by default in unit tests.WebContentsManager: Factory for WebContents-based dependencies, wrapping the WebContents / network dependency for the entire system. FakeWebContentsManager is used by default in unit tests.FileUtilsWrapper: Utility for file system access. TestFileUtils is used by default in unit tests.Other relevant classes:
WebApp: The representation of an installed web app in RAM, reflecting how a site configures its web app manifest plus internal bookkeeping. This does not include information like policy information, so usage of this class is often discouraged over the WebAppRegistrar, which combined multiple sources of truth holistically.AppShimRegistry: (Mac-only) Stores state in Chrome's “Local State” (global preferences) to reason about installed PWAs across all profiles without loading those profiles into memory.Please see testing.md.