12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/dbus/system_clock_client.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/callback.h"
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/observer_list.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "dbus/bus.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "dbus/message.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "dbus/object_path.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "dbus/object_proxy.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The SystemClockClient implementation used in production.
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class SystemClockClientImpl : public SystemClockClient {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  SystemClockClientImpl()
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : can_set_time_(false),
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        can_set_time_initialized_(false),
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        system_clock_proxy_(NULL),
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        weak_ptr_factory_(this) {}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~SystemClockClientImpl() {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void AddObserver(Observer* observer) OVERRIDE {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    observers_.AddObserver(observer);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void RemoveObserver(Observer* observer) OVERRIDE {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    observers_.RemoveObserver(observer);
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasObserver(Observer* observer) OVERRIDE {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return observers_.HasObserver(observer);
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void SetTime(int64 time_in_seconds) OVERRIDE {
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Always try to set the time, because |can_set_time_| may be stale.
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    dbus::MethodCall method_call(system_clock::kSystemClockInterface,
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                 system_clock::kSystemClockSet);
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    dbus::MessageWriter writer(&method_call);
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    writer.AppendInt64(time_in_seconds);
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    system_clock_proxy_->CallMethod(&method_call,
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                    dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                    dbus::ObjectProxy::EmptyResponseCallback());
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual bool CanSetTime() OVERRIDE { return can_set_time_; }
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) protected:
56424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  virtual void Init(dbus::Bus* bus) OVERRIDE {
57424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    system_clock_proxy_ = bus->GetObjectProxy(
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        system_clock::kSystemClockServiceName,
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        dbus::ObjectPath(system_clock::kSystemClockServicePath));
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Check whether the system clock can be set.
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    GetCanSet();
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Monitor the D-Bus signal for TimeUpdated changes.
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    system_clock_proxy_->ConnectToSignal(
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        system_clock::kSystemClockInterface,
67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        system_clock::kSystemClockUpdated,
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&SystemClockClientImpl::TimeUpdatedReceived,
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()),
70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        base::Bind(&SystemClockClientImpl::TimeUpdatedConnected,
71424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr()));
72424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Called when a TimeUpdated signal is received.
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TimeUpdatedReceived(dbus::Signal* signal) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(1) << "TimeUpdated signal received: " << signal->ToString();
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dbus::MessageReader reader(signal);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FOR_EACH_OBSERVER(Observer, observers_, SystemClockUpdated());
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Check if the system clock can be changed now.
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    GetCanSet();
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Called when the TimeUpdated signal is initially connected.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void TimeUpdatedConnected(const std::string& interface_name,
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const std::string& signal_name,
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            bool success) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG_IF(ERROR, !success)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        << "Failed to connect to TimeUpdated signal.";
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Callback for CanSetTime method.
945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void OnGetCanSet(dbus::Response* response) {
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!response) {
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      VLOG(1) << "CanSetTime request failed.";
975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    dbus::MessageReader reader(response);
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool can_set_time;
1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!reader.PopBool(&can_set_time)) {
1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      LOG(ERROR) << "CanSetTime response invalid: " << response->ToString();
1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    }
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // Nothing to do if the CanSetTime response hasn't changed.
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (can_set_time_initialized_ && can_set_time_ == can_set_time)
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return;
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    can_set_time_initialized_ = true;
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    can_set_time_ = can_set_time;
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    FOR_EACH_OBSERVER(
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        Observer, observers_, SystemClockCanSetTimeChanged(can_set_time));
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Check whether the time can be set.
1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void GetCanSet() {
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    dbus::MethodCall method_call(system_clock::kSystemClockInterface,
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                 system_clock::kSystemClockCanSet);
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    dbus::MessageWriter writer(&method_call);
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    system_clock_proxy_->CallMethod(
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        &method_call,
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(&SystemClockClientImpl::OnGetCanSet,
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                   weak_ptr_factory_.GetWeakPtr()));
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Whether the time can be set. Value is false until the first
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // CanSetTime response is received.
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool can_set_time_;
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool can_set_time_initialized_;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dbus::ObjectProxy* system_clock_proxy_;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ObserverList<Observer> observers_;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtrFactory<SystemClockClientImpl> weak_ptr_factory_;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SystemClockClientImpl);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid SystemClockClient::Observer::SystemClockUpdated() {
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid SystemClockClient::Observer::SystemClockCanSetTimeChanged(
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    bool can_set_time) {
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SystemClockClient::SystemClockClient() {
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SystemClockClient::~SystemClockClient() {
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)SystemClockClient* SystemClockClient::Create() {
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return new SystemClockClientImpl();
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
161