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