1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/dbus/metronome_client.h"
8 #include "base/rand_util.h"
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/observer_list.h"
13 #include "base/time/time.h"
14 #include "base/timer/timer.h"
15 #include "chromeos/chromeos_switches.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.h"
21 // TODO(benchan): Move these DBus constants to system_api.
24 const char kMetronomeInterface
[] = "org.chromium.Metronome";
25 const char kMetronomeServiceName
[] = "org.chromium.Metronome";
26 const char kMetronomeServicePath
[] = "/org/chromium/Metronome";
27 const char kTimestampUpdatedSignal
[] = "TimestampUpdated";
29 } // namespace metronome
35 ////////////////////////////////////////////////////////////////////////////////
37 // The MetronomeClient implementation.
38 class MetronomeClientImpl
: public MetronomeClient
{
41 : proxy_(nullptr), signal_connected_(false), weak_ptr_factory_(this) {}
43 ~MetronomeClientImpl() override
{}
46 void AddObserver(Observer
* observer
) override
;
47 void RemoveObserver(Observer
* observer
) override
;
51 void Init(dbus::Bus
* bus
) override
;
54 // Handles TimestampUpdated signal and notifies |observers_|.
55 void OnTimestampUpdated(dbus::Signal
* signal
);
57 // Handles the result of signal connection setup.
58 void OnSignalConnected(const std::string
& interface
,
59 const std::string
& signal
,
62 dbus::ObjectProxy
* proxy_
;
64 // True when |proxy_| has been connected.
65 bool signal_connected_
;
67 // List of observers interested in event notifications from us.
68 base::ObserverList
<Observer
> observers_
;
70 // Note: This should remain the last member so it'll be destroyed and
71 // invalidate its weak pointers before any other members are destroyed.
72 base::WeakPtrFactory
<MetronomeClientImpl
> weak_ptr_factory_
;
74 DISALLOW_COPY_AND_ASSIGN(MetronomeClientImpl
);
77 void MetronomeClientImpl::AddObserver(Observer
* observer
) {
79 if (!signal_connected_
) {
80 signal_connected_
= true;
81 proxy_
->ConnectToSignal(metronome::kMetronomeInterface
,
82 metronome::kTimestampUpdatedSignal
,
83 base::Bind(&MetronomeClientImpl::OnTimestampUpdated
,
84 weak_ptr_factory_
.GetWeakPtr()),
85 base::Bind(&MetronomeClientImpl::OnSignalConnected
,
86 weak_ptr_factory_
.GetWeakPtr()));
88 observers_
.AddObserver(observer
);
91 void MetronomeClientImpl::RemoveObserver(Observer
* observer
) {
93 observers_
.RemoveObserver(observer
);
96 void MetronomeClientImpl::Init(dbus::Bus
* bus
) {
98 bus
->GetObjectProxy(metronome::kMetronomeServiceName
,
99 dbus::ObjectPath(metronome::kMetronomeServicePath
));
102 void MetronomeClientImpl::OnTimestampUpdated(dbus::Signal
* signal
) {
103 dbus::MessageReader
reader(signal
);
104 uint64 beacon_timestamp
= 0;
105 uint64 local_timestamp
= 0;
106 if (!reader
.PopUint64(&beacon_timestamp
) ||
107 !reader
.PopUint64(&local_timestamp
)) {
108 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
111 FOR_EACH_OBSERVER(Observer
, observers_
,
112 OnTimestampUpdated(beacon_timestamp
, local_timestamp
));
115 void MetronomeClientImpl::OnSignalConnected(const std::string
& interface
,
116 const std::string
& signal
,
118 LOG_IF(ERROR
, !succeeded
) << "Connect to " << interface
<< " " << signal
122 ////////////////////////////////////////////////////////////////////////////////
124 // A fake implementation of MetronomeClient. It does not provide true
125 // synchronization and only exists to exercise the interfaces.
126 class MetronomeClientFakeImpl
: public MetronomeClient
{
128 MetronomeClientFakeImpl()
129 : random_offset_(base::RandInt(-1000000, 1000000)) {}
131 ~MetronomeClientFakeImpl() override
{ beacon_timer_
.Stop(); }
134 void AddObserver(Observer
* observer
) override
{
136 observers_
.AddObserver(observer
);
139 void RemoveObserver(Observer
* observer
) override
{
141 observers_
.RemoveObserver(observer
);
145 void Init(dbus::Bus
* bus
) override
{
146 beacon_timer_
.Start(FROM_HERE
,
147 base::TimeDelta::FromMilliseconds(1000),
149 &MetronomeClientFakeImpl::UpdateBeacon
);
153 void UpdateBeacon() {
154 base::Time now_time
= base::Time::Now();
155 base::TimeTicks now_ticks
= base::TimeTicks::Now();
156 uint64 fake_beacon_timestamp
= now_time
.ToInternalValue() +
157 base::RandInt(-1000, 1000);
158 uint64 fake_local_timestamp
= now_ticks
.ToInternalValue() + random_offset_
+
159 base::RandInt(-1000, 1000);
161 Observer
, observers_
,
162 OnTimestampUpdated(fake_beacon_timestamp
, fake_local_timestamp
));
165 int64 random_offset_
;
166 base::RepeatingTimer
<MetronomeClientFakeImpl
> beacon_timer_
;
168 // List of observers interested in event notifications from us.
169 base::ObserverList
<Observer
> observers_
;
171 DISALLOW_COPY_AND_ASSIGN(MetronomeClientFakeImpl
);
174 ////////////////////////////////////////////////////////////////////////////////
176 // A stub implementation of MetronomeClient. It allows unit tests to complete.
177 class MetronomeClientStubImpl
: public MetronomeClient
{
179 MetronomeClientStubImpl() {}
180 ~MetronomeClientStubImpl() override
{}
183 void AddObserver(Observer
* observer
) override
{}
184 void RemoveObserver(Observer
* observer
) override
{}
187 void Init(dbus::Bus
* bus
) override
{}
190 DISALLOW_COPY_AND_ASSIGN(MetronomeClientStubImpl
);
195 ////////////////////////////////////////////////////////////////////////////////
197 MetronomeClient::MetronomeClient() {
200 MetronomeClient::~MetronomeClient() {
204 MetronomeClient
* MetronomeClient::Create(DBusClientImplementationType type
) {
205 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
206 return new MetronomeClientImpl();
207 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
209 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
210 switches::kTestMetronomeTimer
)) {
211 return new MetronomeClientFakeImpl();
213 return new MetronomeClientStubImpl();
216 } // namespace chromeos