forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instance_holder.h
133 lines (110 loc) · 4.36 KB
/
instance_holder.h
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
// Copyright 2015 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 COMPONENTS_ARC_INSTANCE_HOLDER_H_
#define COMPONENTS_ARC_INSTANCE_HOLDER_H_
#include <string>
#include <type_traits>
#include <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
// A macro to call InstanceHolder<T>::GetInstanceForVersionDoNotCallDirectly().
// In order to avoid exposing method names from within the Mojo bindings, we
// will rely on stringification and the fact that the method min versions have a
// consistent naming scheme.
#define ARC_GET_INSTANCE_FOR_METHOD(holder, method_name) \
(holder)->GetInstanceForVersionDoNotCallDirectly( \
std::remove_pointer<decltype( \
holder)>::type::Instance::k##method_name##MinVersion, \
#method_name)
namespace arc {
// Holds a Mojo instance+version pair. This also allows for listening for state
// changes for the particular instance. T should be a Mojo interface type
// (arc::mojom::XxxInstance).
template <typename T>
class InstanceHolder {
public:
// Notifies about connection events for individual instances.
class Observer {
public:
// Called once the instance is ready.
virtual void OnInstanceReady() {}
// Called when the connection to the instance is closed.
virtual void OnInstanceClosed() {}
protected:
virtual ~Observer() = default;
};
using Instance = T;
InstanceHolder() = default;
// Returns true if the Mojo interface is ready at least for its version 0
// interface. Use an Observer if you want to be notified when this is ready.
// This can only be called on the thread that this class was created on.
bool has_instance() const { return instance_; }
// Gets the Mojo interface that's intended to call for
// |method_name_for_logging|, but only if its reported version is at least
// |min_version|. Returns nullptr if the instance is either not ready or does
// not have the requested version, and logs appropriately.
// This function should not be called directly. Instead, use the
// ARC_GET_INSTANCE_FOR_METHOD() macro.
T* GetInstanceForVersionDoNotCallDirectly(
uint32_t min_version,
const char method_name_for_logging[]) {
if (!instance_) {
VLOG(1) << "Instance " << T::Name_ << " not available.";
return nullptr;
}
if (version_ < min_version) {
LOG(ERROR) << "Instance for " << T::Name_
<< "::" << method_name_for_logging
<< " version mismatch. Expected " << min_version << " got "
<< version_;
return nullptr;
}
return instance_;
}
// Adds or removes observers. This can only be called on the thread that this
// class was created on. RemoveObserver does nothing if |observer| is not in
// the list.
void AddObserver(Observer* observer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
observer_list_.AddObserver(observer);
if (instance_)
observer->OnInstanceReady();
}
void RemoveObserver(Observer* observer) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
observer_list_.RemoveObserver(observer);
}
// Sets |instance| with |version|.
// This can be called in both case; on ready, and on closed.
// Passing nullptr to |instance| means closing.
void SetInstance(T* instance, uint32_t version = T::Version_) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(instance == nullptr || instance_ == nullptr);
// Note: This can be called with nullptr even if |instance_| is still
// nullptr for just in case clean up purpose. No-op in such a case.
if (instance == instance_)
return;
instance_ = instance;
version_ = version;
if (instance_) {
for (auto& observer : observer_list_)
observer.OnInstanceReady();
} else {
for (auto& observer : observer_list_)
observer.OnInstanceClosed();
}
}
private:
// This class does not have ownership. The pointers should be managed by the
// callee.
T* instance_ = nullptr;
uint32_t version_ = 0;
THREAD_CHECKER(thread_checker_);
base::ObserverList<Observer> observer_list_;
DISALLOW_COPY_AND_ASSIGN(InstanceHolder<T>);
};
} // namespace arc
#endif // COMPONENTS_ARC_INSTANCE_HOLDER_H_