1 // Copyright 2019 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.
4
5 #include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/memory/weak_ptr.h"
11 #include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
12 #include "dbus/bus.h"
13 #include "dbus/message.h"
14 #include "dbus/object_proxy.h"
15 #include "mojo/public/cpp/platform/platform_channel.h"
16 #include "mojo/public/cpp/system/invitation.h"
17 #include "third_party/cros_system_api/dbus/service_constants.h"
18
19 namespace chromeos {
20
21 namespace {
22
23 CrosHealthdClient* g_instance = nullptr;
24
25 // Production implementation of CrosHealthdClient.
26 class CrosHealthdClientImpl : public CrosHealthdClient {
27 public:
28 CrosHealthdClientImpl() = default;
29 ~CrosHealthdClientImpl() override = default;
30
31 // CrosHealthdClient overrides:
32 mojo::Remote<cros_healthd::mojom::CrosHealthdServiceFactory>
BootstrapMojoConnection(BootstrapMojoConnectionCallback result_callback)33 BootstrapMojoConnection(
34 BootstrapMojoConnectionCallback result_callback) override {
35 // Invalidate any pending attempts to bootstrap the mojo connection.
36 bootstrap_weak_ptr_factory_.InvalidateWeakPtrs();
37
38 mojo::PlatformChannel platform_channel;
39 // Prepare a Mojo invitation to send through |platform_channel|.
40 mojo::OutgoingInvitation invitation;
41 // Include an initial Mojo pipe in the invitation.
42 mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(
43 diagnostics::kCrosHealthdMojoConnectionChannelToken);
44 mojo::OutgoingInvitation::Send(std::move(invitation),
45 base::kNullProcessHandle,
46 platform_channel.TakeLocalEndpoint());
47
48 // Bind our end of |pipe| to our CrosHealthdService remote. The daemon
49 // should bind its end to a CrosHealthdService implementation.
50 mojo::Remote<cros_healthd::mojom::CrosHealthdServiceFactory>
51 cros_healthd_service_factory;
52 cros_healthd_service_factory.Bind(
53 mojo::PendingRemote<cros_healthd::mojom::CrosHealthdServiceFactory>(
54 std::move(pipe), 0u /* version */));
55
56 cros_healthd_service_proxy_->WaitForServiceToBeAvailable(base::BindOnce(
57 &CrosHealthdClientImpl::OnDbusServiceAvailable,
58 bootstrap_weak_ptr_factory_.GetWeakPtr(), std::move(result_callback),
59 std::move(platform_channel)));
60
61 return cros_healthd_service_factory;
62 }
63
Init(dbus::Bus * const bus)64 void Init(dbus::Bus* const bus) {
65 cros_healthd_service_proxy_ = bus->GetObjectProxy(
66 diagnostics::kCrosHealthdServiceName,
67 dbus::ObjectPath(diagnostics::kCrosHealthdServicePath));
68 }
69
70 private:
71 dbus::ObjectProxy* cros_healthd_service_proxy_ = nullptr;
72
73 // When the service is available, attempt to bootstrap the mojo connection.
OnDbusServiceAvailable(BootstrapMojoConnectionCallback result_callback,mojo::PlatformChannel platform_channel,bool success)74 void OnDbusServiceAvailable(BootstrapMojoConnectionCallback result_callback,
75 mojo::PlatformChannel platform_channel,
76 bool success) {
77 // The service is not available.
78 if (!success) {
79 std::move(result_callback).Run(false);
80 return;
81 }
82
83 dbus::MethodCall method_call(
84 diagnostics::kCrosHealthdServiceInterface,
85 diagnostics::kCrosHealthdBootstrapMojoConnectionMethod);
86 dbus::MessageWriter writer(&method_call);
87 base::ScopedFD fd =
88 platform_channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD();
89 writer.AppendFileDescriptor(fd.get());
90 writer.AppendBool(/*is_chrome=*/true);
91 cros_healthd_service_proxy_->CallMethod(
92 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
93 base::BindOnce(
94 &CrosHealthdClientImpl::OnBootstrapMojoConnectionResponse,
95 bootstrap_weak_ptr_factory_.GetWeakPtr(),
96 std::move(result_callback)));
97 }
98
99 // Passes the success/failure of |dbus_response| on to |result_callback|.
OnBootstrapMojoConnectionResponse(BootstrapMojoConnectionCallback result_callback,dbus::Response * const dbus_response)100 void OnBootstrapMojoConnectionResponse(
101 BootstrapMojoConnectionCallback result_callback,
102 dbus::Response* const dbus_response) {
103 const bool success = dbus_response != nullptr;
104 std::move(result_callback).Run(success);
105 }
106
107 // Must be last class member. This WeakPtrFactory is specifically for the
108 // bootstrapping callbacks.
109 base::WeakPtrFactory<CrosHealthdClientImpl> bootstrap_weak_ptr_factory_{this};
110
111 DISALLOW_COPY_AND_ASSIGN(CrosHealthdClientImpl);
112 };
113
114 } // namespace
115
CrosHealthdClient()116 CrosHealthdClient::CrosHealthdClient() {
117 DCHECK(!g_instance);
118 g_instance = this;
119 }
120
~CrosHealthdClient()121 CrosHealthdClient::~CrosHealthdClient() {
122 DCHECK_EQ(this, g_instance);
123 g_instance = nullptr;
124 }
125
126 // static
Initialize(dbus::Bus * bus)127 void CrosHealthdClient::Initialize(dbus::Bus* bus) {
128 DCHECK(bus);
129 (new CrosHealthdClientImpl())->Init(bus);
130 }
131
132 // static
InitializeFake()133 void CrosHealthdClient::InitializeFake() {
134 new cros_healthd::FakeCrosHealthdClient();
135 }
136
137 // static
Shutdown()138 void CrosHealthdClient::Shutdown() {
139 DCHECK(g_instance);
140 delete g_instance;
141 }
142
143 // static
Get()144 CrosHealthdClient* CrosHealthdClient::Get() {
145 return g_instance;
146 }
147
148 } // namespace chromeos
149