File: service_factory.h

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (185 lines) | stat: -rw-r--r-- 6,454 bytes parent folder | download | duplicates (5)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// 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 MOJO_PUBLIC_CPP_BINDINGS_SERVICE_FACTORY_H_
#define MOJO_PUBLIC_CPP_BINDINGS_SERVICE_FACTORY_H_

#include <map>
#include <memory>

#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"

namespace mojo {

namespace internal {
template <typename Func>
struct ServiceFactoryTraits;
}

// ServiceFactory is a helper that Mojo consumers can use to conveniently handle
// dynamic service interface requests via a GenericPendingReceiver by matching
// the receiver's interface type against a series of strongly-typed factory
// function pointers, each with the signature:
//
//   std::unique_ptr<T>(mojo::PendingReceiver<Interface>)
//
// where |T| is any type (generally an implementation of |Interface|), and
// |Interface| is a mojom interface.
//
// Any time |RunService()| is called on the ServiceFactory, it will match the
// GenericPendingReceiver argument's interface type against the list of
// factories it has available and run the corresponding function, retaining
// ownership of the returned object until the corresponding receiver is
// disconnected.
//
// Typical usage might look something like:
//
//     auto RunFooService(mojo::PendingReceiver<foo::mojom::Foo> receiver) {
//       return std::make_unique<foo::FooImpl>(std::move(receiver));
//     }
//
//     auto RunBarService(mojo::PendingReceiver<bar::mojom::Bar> receiver) {
//       return std::make_unique<bar::BarImpl>(std::move(receiver));
//     }
//
//     void RegisterServices(mojo::ServiceFactory& services) {
//       services.Add(RunFooService);
//       services.Add(RunBarService);
//     }
//
//     void HandleServiceRequest(const mojo::ServiceFactory& factory,
//                               mojo::GenericPendingReceiver receiver) {
//       if (factory.CanRunService(receiver)) {
//         factory.RunService(std::move(receiver), base::NullCallback());
//         return;
//       }
//
//       // The receiver was for neither the Foo nor Bar service. Sad!
//       LOG(ERROR) << "Unknown service: " << *receiver.interface_name();
//     }
//
class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ServiceFactory {
 public:
  ServiceFactory();

  ServiceFactory(const ServiceFactory&) = delete;
  ServiceFactory& operator=(const ServiceFactory&) = delete;

  ~ServiceFactory();

  // Adds a new service to the factory. The argument may be any function that
  // accepts a single PendingReceiver<T> and returns a unique_ptr<T>, where T is
  // a service interface (that is, a generated mojom interface class
  // corresponding to some service's main interface.) Safely drops registration
  // if Interface is RuntimeFeature disabled. CanRunService() will return false
  // for these ignored Interfaces.
  template <typename Func>
  void Add(Func func) {
    using Interface = typename internal::ServiceFactoryTraits<Func>::Interface;
    if (internal::GetRuntimeFeature_IsEnabled<Interface>()) {
      constructors_[Interface::Name_] =
          base::BindRepeating(&RunConstructor<Func>, func);
    }
  }

  // If `receiver` is references an interface matching a service known to this
  // factory, this returns true. Otherwise it returns false. `receiver` MUST be
  // valid.
  bool CanRunService(const GenericPendingReceiver& receiver) const;

  // Consumes `receiver` and binds it to a new instance of the corresponding
  // service, constructed using the service's registered function within this
  // factory.
  //
  // `termination_callback`, if not null, will be invoked on the calling
  // TaskRunner whenever the new service instance is eventually destroyed.
  //
  // If the service represented by `receiver` is not known to this factory, it
  // is discarded and `termination_callback` is never run.
  bool RunService(GenericPendingReceiver receiver,
                  base::OnceClosure termination_callback);

 private:
  class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InstanceHolderBase {
   public:
    InstanceHolderBase();

    InstanceHolderBase(const InstanceHolderBase&) = delete;
    InstanceHolderBase& operator=(const InstanceHolderBase&) = delete;

    virtual ~InstanceHolderBase();

    void WatchPipe(MessagePipeHandle pipe,
                   base::OnceClosure disconnect_callback);

   private:
    void OnPipeSignaled(MojoResult result, const HandleSignalsState& state);

    SimpleWatcher watcher_;
    base::OnceClosure disconnect_callback_;
  };

  template <typename Impl>
  class InstanceHolder : public InstanceHolderBase {
   public:
    explicit InstanceHolder(std::unique_ptr<Impl> instance)
        : instance_(std::move(instance)) {}

    InstanceHolder(const InstanceHolder&) = delete;
    InstanceHolder& operator=(const InstanceHolder&) = delete;

    ~InstanceHolder() override = default;

   private:
    const std::unique_ptr<Impl> instance_;
  };

  template <typename Func>
  static std::unique_ptr<InstanceHolderBase> RunConstructor(
      Func fn,
      GenericPendingReceiver receiver) {
    using Interface = typename internal::ServiceFactoryTraits<Func>::Interface;
    using Impl = typename internal::ServiceFactoryTraits<Func>::Impl;
    auto impl = fn(receiver.As<Interface>());
    if (!impl)
      return nullptr;

    return std::make_unique<InstanceHolder<Impl>>(std::move(impl));
  }

  void OnInstanceDisconnected(InstanceHolderBase* instance);

  using Constructor =
      base::RepeatingCallback<std::unique_ptr<InstanceHolderBase>(
          GenericPendingReceiver)>;
  std::map<std::string, Constructor> constructors_;

  base::flat_set<std::unique_ptr<InstanceHolderBase>, base::UniquePtrComparator>
      instances_;

  base::WeakPtrFactory<ServiceFactory> weak_ptr_factory_{this};
};

namespace internal {

template <typename ImplType, typename InterfaceType>
struct ServiceFactoryTraits<std::unique_ptr<ImplType> (*)(
    PendingReceiver<InterfaceType>)> {
  using Interface = InterfaceType;
  using Impl = ImplType;
};

}  // namespace internal

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_SERVICE_FACTORY_H_