// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_PUBLIC_BROWSER_WEB_UI_BROWSER_INTERFACE_BROKER_REGISTRY_H_ #define CONTENT_PUBLIC_BROWSER_WEB_UI_BROWSER_INTERFACE_BROKER_REGISTRY_H_ #include <map> #include "base/memory/raw_ptr.h" #include "content/common/content_export.h" #include "content/public/browser/per_web_ui_browser_interface_broker.h" #include "content/public/browser/web_ui_controller.h" namespace content { // A lightweight class to help interface registration. Shouldn't be used outside // of registration process. template <typename ControllerType> class InterfaceRegistrationHelper { … }; // Maintains a mapping from WebUIController::Type to a list of interfaces // exposed to MojoJS, and provides methods to set up an interface broker that // only brokers the registered interfaces for the WebUIController. // // To register interfaces for WebUI, use the following code: // // registry.ForWebUI<ControllerType> // .Add<Interface1>() // .Add<Interface2>(); // // Background: // // Renderer exposed Mojo interfaces in general use a mojo::BinderMap where // *all* interface binders are registered. When the renderer requests an // interface, we look for the interface binder in that map and run it. // // At a high level, WebUI interfaces work slightly different. Rather than // using the general mojo::BinderMap that has all renderer-exposed // interfaces, each WebUI has its own mojo::BinderMap that contains only the // interfaces exposed to the WebUI. When a WebUI's JS requests an interface, // it uses that mojo::BinderMap and not the general one. // // The implementation of this is done through // WebUIBrowserInterfaceBrokerRegistry which works as follows: // // 1. When we register interfaces for a WebUI, we create a // a vector of "binder initializers" and add it to a map i.e. // (WebUI type -> vector<BinderInitializer>). These binder initializers // are repeating callbacks that wrap a call to BinderMap::Add() with an // interface binder. Interface binders themselves are repeating callbacks // that bind Mojo interfaces. Ideally, we would store the binders directly // and pass them to the BinderMap in step 2., but BinderMap::Add() requires // a template argument, so we need the binder initializer wrapper. // 2. When a WebUI starts loading, we check the binder initialializers map to // see if the WebUI is in the map, and if it is, we create a // PerWebUIBrowserInterfaceBroker, which subclasses BrowserInterfaceBroker. // PerWebUIBrowserInterfaceBroker owns a mojo::BinderMap and runs the // binder initializers for the WebUI, registering all the interface binders // for the WebUI in the mojo::BinderMap. // 3. The PerWebUIBrowserInterfaceBroker is then stored in the // WebUIController and a `BrowserInterfaceBroker` remote endpoint is sent // to the renderer. // 4. Through `BrowserInterfaceBroker::GetInterface()` the JS can request // other remote endpoints. class CONTENT_EXPORT WebUIBrowserInterfaceBrokerRegistry { … }; } // namespace content #endif // CONTENT_PUBLIC_BROWSER_WEB_UI_BROWSER_INTERFACE_BROKER_REGISTRY_H_