// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/dbus/private_computing/private_computing_client.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/strcat.h"
#include "base/task/single_thread_task_runner.h"
#include "chromeos/ash/components/dbus/private_computing/fake_private_computing_client.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
#include "third_party/cros_system_api/dbus/private_computing/dbus-constants.h"
namespace ash {
namespace {
PrivateComputingClient* g_instance = nullptr;
const char kDbusCallFailure[] = "Failed to call private computing.";
const char kProtoMessageParsingFailure[] =
"Failed to parse response message from private computing.";
// Tries to parse a proto message from |response| into |proto| and returns null
// if successful. If |response| is nullptr or the message cannot be parsed it
// will return an appropriate error message.
const char* DeserializeProto(dbus::Response* response,
google::protobuf::MessageLite* proto) {
if (!response)
return kDbusCallFailure;
dbus::MessageReader reader(response);
if (!reader.PopArrayOfBytesAsProto(proto))
return kProtoMessageParsingFailure;
return nullptr;
}
// "Real" implementation of PrivateComputingClient talking to the
// PrivateComputing daemon on the Chrome OS side.
class PrivateComputingClientImpl : public PrivateComputingClient {
public:
PrivateComputingClientImpl() = default;
PrivateComputingClientImpl(const PrivateComputingClientImpl&) = delete;
PrivateComputingClientImpl& operator=(const PrivateComputingClientImpl&) =
delete;
~PrivateComputingClientImpl() override = default;
void Init(dbus::Bus* bus) {
proxy_ = bus->GetObjectProxy(
private_computing::kPrivateComputingServiceName,
dbus::ObjectPath(private_computing::kPrivateComputingServicePath));
}
// PrivateComputingClient:
void SaveLastPingDatesStatus(
const private_computing::SaveStatusRequest& request,
SaveStatusCallback callback) override {
dbus::MethodCall method_call(private_computing::kPrivateComputingInterface,
private_computing::kSaveLastPingDatesStatus);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
private_computing::SaveStatusResponse response;
response.set_error_message(
base::StrCat({"Failure to call d-bus method: ",
private_computing::kSaveLastPingDatesStatus}));
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), response));
return;
}
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(
&PrivateComputingClientImpl::HandleSaveLastPingDatesStatusResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void GetLastPingDatesStatus(GetStatusCallback callback) override {
dbus::MethodCall method_call(private_computing::kPrivateComputingInterface,
private_computing::kGetLastPingDatesStatus);
dbus::MessageWriter writer(&method_call);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(
&PrivateComputingClientImpl::HandleGetLastPingDatesStatusResponse,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
TestInterface* GetTestInterface() override { return nullptr; }
private:
// Handle a DBus response from the private computing chromeos daemon,
// invoking the callback that the method was originally called with the
// success response.
void HandleSaveLastPingDatesStatusResponse(SaveStatusCallback callback,
dbus::Response* response) {
private_computing::SaveStatusResponse response_proto;
const char* error_message = DeserializeProto(response, &response_proto);
if (error_message) {
LOG(ERROR)
<< "Response from SaveLastPingDatesStatus contains error message "
<< error_message;
response_proto.set_error_message(error_message);
}
std::move(callback).Run(response_proto);
}
// Handle a DBus response from the private computing chromeos daemon,
// invoking the callback that the method was originally called with the
// success response.
void HandleGetLastPingDatesStatusResponse(GetStatusCallback callback,
dbus::Response* response) {
private_computing::GetStatusResponse response_proto;
const char* error_message = DeserializeProto(response, &response_proto);
if (error_message) {
LOG(ERROR)
<< "Response from GetLastPingDatesStatus contains error message "
<< error_message;
response_proto.set_error_message(error_message);
}
std::move(callback).Run(response_proto);
}
raw_ptr<dbus::ObjectProxy> proxy_ = nullptr;
// Note: This should remain the last member so that it will be destroyed
// first, invalidating its weak pointers, before the other members are
// destroyed.
base::WeakPtrFactory<PrivateComputingClientImpl> weak_ptr_factory_{this};
};
} // namespace
PrivateComputingClient::PrivateComputingClient() {
DCHECK(!g_instance);
g_instance = this;
}
PrivateComputingClient::~PrivateComputingClient() {
DCHECK_EQ(this, g_instance);
g_instance = nullptr;
}
// static
void PrivateComputingClient::Initialize(dbus::Bus* bus) {
DCHECK(bus);
(new PrivateComputingClientImpl())->Init(bus);
}
// static
void PrivateComputingClient::InitializeFake() {
new FakePrivateComputingClient();
}
// static
void PrivateComputingClient::Shutdown() {
DCHECK(g_instance);
delete g_instance;
}
// static
PrivateComputingClient* PrivateComputingClient::Get() {
return g_instance;
}
} // namespace ash