| // Copyright 2020 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. |
| |
| #include "chromeos/dbus/chromebox_for_meetings/cfm_hotline_client.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "chromeos/dbus/chromebox_for_meetings/cfm_observer.h" |
| #include "chromeos/dbus/chromebox_for_meetings/fake_cfm_hotline_client.h" |
| #include "dbus/bus.h" |
| #include "dbus/message.h" |
| #include "third_party/cros_system_api/dbus/service_constants.h" |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| CfmHotlineClient* g_instance = nullptr; |
| |
| class CfmHotlineClientImpl : public CfmHotlineClient { |
| public: |
| CfmHotlineClientImpl() = default; |
| CfmHotlineClientImpl(const CfmHotlineClientImpl&) = delete; |
| CfmHotlineClientImpl& operator=(const CfmHotlineClientImpl&) = delete; |
| ~CfmHotlineClientImpl() override = default; |
| |
| void Init(dbus::Bus* const bus) { |
| dbus_proxy_ = |
| bus->GetObjectProxy(::cfm::broker::kServiceName, |
| dbus::ObjectPath(::cfm::broker::kServicePath)); |
| |
| dbus_proxy_->ConnectToSignal( |
| ::cfm::broker::kServiceInterfaceName, |
| ::cfm::broker::kMojoServiceRequestedSignal, |
| base::BindRepeating( |
| &CfmHotlineClientImpl::OnServiceRequestedSignalReceived, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::BindRepeating(&CfmHotlineClientImpl::OnSignalConnected, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void WaitForServiceToBeAvailable( |
| dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) |
| override { |
| dbus_proxy_->WaitForServiceToBeAvailable(std::move(callback)); |
| } |
| |
| void BootstrapMojoConnection( |
| base::ScopedFD fd, |
| BootstrapMojoConnectionCallback result_callback) override { |
| dbus::MethodCall method_call(::cfm::broker::kServiceInterfaceName, |
| ::cfm::broker::kBootstrapMojoConnectionMethod); |
| dbus::MessageWriter writer(&method_call); |
| writer.AppendBool(/*is_outgoing_invitation=*/true); |
| writer.AppendFileDescriptor(fd.get()); |
| dbus_proxy_->CallMethod( |
| &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| base::BindOnce(&CfmHotlineClientImpl::OnBootstrapMojoConnectionResponse, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(result_callback))); |
| } |
| |
| void AddObserver(cfm::CfmObserver* observer) override { |
| observer_list_.AddObserver(observer); |
| } |
| |
| void RemoveObserver(cfm::CfmObserver* observer) override { |
| observer_list_.RemoveObserver(observer); |
| } |
| |
| private: |
| void OnServiceRequestedSignalReceived(dbus::Signal* signal) { |
| dbus::MessageReader reader(signal); |
| std::string service_id; |
| |
| if (!reader.PopString(&service_id)) { |
| LOG(ERROR) << "Invalid detection signal: " << signal->ToString(); |
| return; |
| } |
| |
| for (auto& observer : observer_list_) { |
| if (observer.ServiceRequestReceived(service_id)) { |
| // A service has been found that can fulfill the request |
| // Note: Only one service will match the requested service_id. |
| break; |
| } |
| } |
| } |
| |
| void OnSignalConnected(const std::string& interface, |
| const std::string& signal, |
| bool succeeded) { |
| LOG_IF(ERROR, !succeeded) |
| << "Connection to " << interface << " " << signal << " failed."; |
| } |
| |
| // Passes the invitation token of |dbus_response| on to |result_callback|. |
| void OnBootstrapMojoConnectionResponse( |
| BootstrapMojoConnectionCallback result_callback, |
| dbus::Response* const response) { |
| std::move(result_callback).Run(response != nullptr); |
| } |
| |
| dbus::ObjectProxy* dbus_proxy_ = nullptr; |
| cfm::CfmObserverList observer_list_; |
| |
| // Note: This should remain the last member so it'll be destroyed and |
| // invalidate its weak pointers before any other members are destroyed. |
| base::WeakPtrFactory<CfmHotlineClientImpl> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace |
| |
| CfmHotlineClient::CfmHotlineClient() { |
| DCHECK(!g_instance); |
| g_instance = this; |
| } |
| |
| CfmHotlineClient::~CfmHotlineClient() { |
| DCHECK_EQ(this, g_instance); |
| g_instance = nullptr; |
| } |
| |
| // static |
| void CfmHotlineClient::Initialize(dbus::Bus* bus) { |
| DCHECK(bus); |
| (new CfmHotlineClientImpl())->Init(bus); |
| } |
| |
| // static |
| void CfmHotlineClient::InitializeFake() { |
| new FakeCfmHotlineClient(); |
| } |
| |
| // static |
| void CfmHotlineClient::Shutdown() { |
| if (g_instance) { |
| delete g_instance; |
| } |
| } |
| |
| // static |
| bool CfmHotlineClient::IsInitialized() { |
| return g_instance; |
| } |
| |
| // static |
| CfmHotlineClient* CfmHotlineClient::Get() { |
| CHECK(IsInitialized()); |
| return g_instance; |
| } |
| |
| } // namespace chromeos |