summaryrefslogtreecommitdiff
path: root/chromium/mojo/public/cpp/bindings/service_factory.h
blob: baaf683056bfee36259d18a9099170df5a423245 (plain)
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
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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/bind.h"
#include "base/callback.h"
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.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();

  // 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.)
  template <typename Func>
  void Add(Func func) {
    using Interface = typename internal::ServiceFactoryTraits<Func>::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();
    virtual ~InstanceHolderBase();

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

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

    SimpleWatcher watcher_;
    base::OnceClosure disconnect_callback_;

    DISALLOW_COPY_AND_ASSIGN(InstanceHolderBase);
  };

  template <typename Interface>
  class InstanceHolder : public InstanceHolderBase {
   public:
    explicit InstanceHolder(std::unique_ptr<Interface> instance)
        : instance_(std::move(instance)) {}
    ~InstanceHolder() override = default;

   private:
    const std::unique_ptr<Interface> instance_;

    DISALLOW_COPY_AND_ASSIGN(InstanceHolder);
  };

  template <typename Func>
  static std::unique_ptr<InstanceHolderBase> RunConstructor(
      Func fn,
      GenericPendingReceiver receiver) {
    using Interface = typename internal::ServiceFactoryTraits<Func>::Interface;
    return std::make_unique<InstanceHolder<Interface>>(
        fn(receiver.As<Interface>()));
  }

  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};

  DISALLOW_COPY_AND_ASSIGN(ServiceFactory);
};

namespace internal {

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

}  // namespace internal

}  // namespace mojo

#endif  // MOJO_PUBLIC_CPP_BINDINGS_SERVICE_FACTORY_H_