1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113

content / browser / browser_interface_broker_impl.h [blame]

// Copyright 2019 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_BROWSER_BROWSER_INTERFACE_BROKER_IMPL_H_
#define CONTENT_BROWSER_BROWSER_INTERFACE_BROKER_IMPL_H_

#include "base/memory/raw_ptr.h"
#include "content/browser/browser_interface_binders.h"
#include "content/browser/mojo_binder_policy_applier.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/browser_interface_broker.mojom.h"

namespace content {

// content's implementation of the BrowserInterfaceBroker interface that binds
// interfaces requested by the renderer. Every execution context type (frame,
// worker etc) owns an instance and registers appropriate handlers, called
// "binders" (see internal::PopulateBinderMap and
// internal::PopulateBinderMapWithContext).
//
// By default, BrowserInterfaceBrokerImpl runs the binder that was registered
// for a given interface when the interface is requested. However, in some cases
// such as prerendering pages, it may be desirable to defer running the binder,
// or take another action. Setting a non-null `MojoBinderPolicyApplier` enables
// this behavior.
//
// Note: BrowserInterfaceBrokerImpl will eventually replace the usage of
// InterfaceProvider and browser manifests, as well as DocumentInterfaceBroker.
template <typename ExecutionContextHost, typename InterfaceBinderContext>
class BrowserInterfaceBrokerImpl : public blink::mojom::BrowserInterfaceBroker {
 public:
  explicit BrowserInterfaceBrokerImpl(ExecutionContextHost* host)
      : host_(host) {
    // The populate functions here define all the interfaces that will be
    // exposed through the broker.
    //
    // The `host` is a templated type (one of RenderFrameHostImpl,
    // ServiceWorkerHost, etc.). which allows the populate steps here to call a
    // set of overloaded functions based on that type. Thus each type of `host`
    // can expose a different set of interfaces, which is determined statically
    // at compile time.
    internal::PopulateBinderMap(host, &binder_map_);
    internal::PopulateBinderMapWithContext(host, &binder_map_with_context_);
  }

  // Disallows copy and move operations.
  BrowserInterfaceBrokerImpl(const BrowserInterfaceBrokerImpl& other) = delete;
  BrowserInterfaceBrokerImpl& operator=(
      const BrowserInterfaceBrokerImpl& other) = delete;
  BrowserInterfaceBrokerImpl(BrowserInterfaceBrokerImpl&&) = delete;
  BrowserInterfaceBrokerImpl& operator=(BrowserInterfaceBrokerImpl&&) = delete;

  // blink::mojom::BrowserInterfaceBroker
  void GetInterface(mojo::GenericPendingReceiver receiver) override {
    DCHECK(receiver.interface_name().has_value());
    if (!policy_applier_) {
      BindInterface(std::move(receiver));
    } else {
      std::string interface_name = receiver.interface_name().value();
      // base::Unretained is safe because `this` outlives `policy_applier_`.
      policy_applier_->ApplyPolicyToNonAssociatedBinder(
          interface_name,
          base::BindOnce(&BrowserInterfaceBrokerImpl::BindInterface,
                         base::Unretained(this), std::move(receiver)));
    }
  }

  // Sets MojoBinderPolicyApplier to control when to bind interfaces.
  void ApplyMojoBinderPolicies(MojoBinderPolicyApplier* policy_applier) {
    DCHECK(policy_applier);
    DCHECK(!policy_applier_);
    policy_applier_ = policy_applier;
  }

  // Stops applying policies to binding requests.
  void ReleaseMojoBinderPolicies() {
    DCHECK(policy_applier_);
    // Reset `policy_applier_` to disable capability control.
    policy_applier_ = nullptr;
  }

  void GetBinderMapInterfacesForTesting(std::vector<std::string>& out) {
    binder_map_.GetInterfacesForTesting(out);
    binder_map_with_context_.GetInterfacesForTesting(out);
  }

 private:
  void BindInterface(mojo::GenericPendingReceiver receiver) {
    if (!binder_map_.TryBind(&receiver)) {
      if (!binder_map_with_context_.TryBind(internal::GetContextForHost(host_),
                                            &receiver)) {
        host_->ReportNoBinderForInterface("No binder found for interface " +
                                          *receiver.interface_name());
      }
    }
  }

  const raw_ptr<ExecutionContextHost> host_;
  mojo::BinderMap binder_map_;
  mojo::BinderMapWithContext<InterfaceBinderContext> binder_map_with_context_;

  // The lifetime of `policy_applier_` is managed by the owner of this instance.
  // The owner should call `ReleaseMojoBinderPolicies()` when it destroys the
  // applier.
  raw_ptr<MojoBinderPolicyApplier> policy_applier_ = nullptr;
};

}  // namespace content

#endif  // CONTENT_BROWSER_BROWSER_INTERFACE_BROKER_IMPL_H_