Commit c7077414 authored by Jae Hoon Kim's avatar Jae Hoon Kim Committed by Commit Bot

Expose dlcservice DBus API with DlcserviceClient

This creates the DlcserviceClient to call into dlcservice daemon's exposed
DBus API. The dlcservice daemon provides management of DLC
(Downloadable Content) modules. Exposures from DlcserviceClient is to
allow for Install/Uninstall/GetInstalled in a manner that wraps the
respective DBus API exported from the dlcservice daemon in a Chrome
style callable interface.

Information on building a DLC and how what dlcservice daemon is can be
followed at:
https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/dlcservice

Bug: 1000711
Test: autoninja -C out/Default chromeos_unittests && testing/xvfb.py out/Default/chromeos_unittests --gtest_filter=DlcserviceClientTest*
Test: autoninja -C out/Default unit_tests && testing/xvfb.py ./out/Default/unit_tests
Test: autoninja -C out_${SDK_BOARD}/Release chrome nacl_helper && deploy_chrome --build-dir=out_${SDK_BOARD}/Release --to=$TEST_IP
Test: modifications to actually call into to DlcserviceClient with nebraska.py as payload path server. $> restart ui
Test: Custom CHROMEOS_AUSERVER within /mnt/stateful_partition/etc/lsb-release on DUT with local nebraska.py port.
Change-Id: Ia269cab18d7fcc4c1c6d0ee72fb3383b11af38a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1802682
Commit-Queue: Jae Hoon Kim <kimjae@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#697691}
parent 6ea2b48a
......@@ -108,6 +108,8 @@ source_set("chromeos") {
"//chromeos/dbus/cryptohome:cryptohome_proto",
"//chromeos/dbus/cryptohome:cryptohome_signkey_proto",
"//chromeos/dbus/cups_proxy",
"//chromeos/dbus/dlcservice",
"//chromeos/dbus/dlcservice:dlcservice_proto",
"//chromeos/dbus/kerberos",
"//chromeos/dbus/kerberos:kerberos_proto",
"//chromeos/dbus/machine_learning",
......@@ -2902,6 +2904,7 @@ source_set("unit_tests") {
"//chromeos/dbus/auth_policy",
"//chromeos/dbus/cryptohome",
"//chromeos/dbus/cryptohome:attestation_proto",
"//chromeos/dbus/dlcservice:test_support",
"//chromeos/dbus/power",
"//chromeos/dbus/services:test_support",
"//chromeos/dbus/session_manager",
......
......@@ -17,6 +17,7 @@
#include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
#include "chromeos/dbus/cups_proxy/cups_proxy_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/dlcservice/dlcservice_client.h"
#include "chromeos/dbus/initialize_dbus_client.h"
#include "chromeos/dbus/kerberos/kerberos_client.h"
#include "chromeos/dbus/machine_learning/machine_learning_client.h"
......@@ -63,6 +64,7 @@ void InitializeDBus() {
InitializeDBusClient<CrosHealthdClient>(bus);
InitializeDBusClient<CryptohomeClient>(bus);
InitializeDBusClient<CupsProxyClient>(bus);
InitializeDBusClient<DlcserviceClient>(bus);
InitializeDBusClient<KerberosClient>(bus);
InitializeDBusClient<MachineLearningClient>(bus);
InitializeDBusClient<MediaAnalyticsClient>(bus);
......@@ -98,6 +100,7 @@ void ShutdownDBus() {
MediaAnalyticsClient::Shutdown();
MachineLearningClient::Shutdown();
KerberosClient::Shutdown();
DlcserviceClient::Shutdown();
CupsProxyClient::Shutdown();
CryptohomeClient::Shutdown();
CrosHealthdClient::Shutdown();
......
......@@ -210,6 +210,7 @@ source_set("unit_tests") {
"//chromeos/dbus/biod:test_support",
"//chromeos/dbus/cryptohome",
"//chromeos/dbus/cryptohome:attestation_proto",
"//chromeos/dbus/dlcservice:test_support",
"//chromeos/dbus/power:power_manager_proto",
"//chromeos/dbus/power:test_support",
"//chromeos/dbus/session_manager",
......
# Copyright 2019 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.
import("//third_party/protobuf/proto_library.gni")
assert(is_chromeos, "Non-ChromeOS builds cannot depend on //chromeos")
component("dlcservice") {
defines = [ "IS_DLCSERVICE_CLIENT_IMPL" ]
public_deps = [
":dlcservice_proto",
"//chromeos/dbus:common",
"//chromeos/dbus:dbus",
]
deps = [
"//base",
"//dbus",
]
sources = [
"dlcservice_client.cc",
"dlcservice_client.h",
"fake_dlcservice_client.cc",
"fake_dlcservice_client.h",
]
}
source_set("test_support") {
testonly = true
public_deps = [
":dlcservice",
]
deps = [
":dlcservice_proto",
"//base",
"//base/test:test_support",
"//dbus:test_support",
"//testing/gmock",
"//testing/gtest",
]
sources = [
"dlcservice_client_unittest.cc",
]
}
proto_library("dlcservice_proto") {
sources = [
"//third_party/cros_system_api/dbus/dlcservice/dlcservice.proto",
]
proto_out_dir = "chromeos/dbus/dlcservice"
}
This diff is collapsed.
// Copyright (c) 2019 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.
#ifndef CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
#define CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
#include <stdint.h>
#include <string>
#include "base/callback.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "chromeos/dbus/dbus_client.h"
#include "chromeos/dbus/dbus_client_implementation_type.h"
#include "chromeos/dbus/dlcservice/dlcservice.pb.h"
#include "dbus/message.h"
#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
namespace chromeos {
// DlcserviceClient is used to communicate with the dlcservice daemon which
// manages DLC (Downloadable Content) modules. DlcserviceClient will allow for
// CrOS features to be installed and uninstalled at runtime of the system. If
// more details about dlcservice are required, please consult
// https://chromium.git.corp.google.com/chromiumos/platform2/+/HEAD/dlcservice
class COMPONENT_EXPORT(DLCSERVICE_CLIENT) DlcserviceClient {
public:
// The callback used for |Install()|, if the error is something other than
// |dlcservice::kErrorNone| the call has failed. For large DLC(s) to install,
// there may be delay between the time of this call and the callback being
// invoked.
using InstallCallback = base::OnceCallback<void(
const std::string& err,
const dlcservice::DlcModuleList& dlc_module_list)>;
// The callback used for |Uninstall()|, if the error is something other than
// |dlcservice::kErrorNone| the call has failed.
using UninstallCallback = base::OnceCallback<void(const std::string& err)>;
// The callback used for |GetInstalled()|, if the error is something other
// than |dlcservice::kErrorNone| the call has failed. It is very rare case for
// |GetInstalled()| call to fail.
using GetInstalledCallback = base::OnceCallback<void(
const std::string& err,
const dlcservice::DlcModuleList& dlc_module_list)>;
virtual void Install(const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) = 0;
virtual void Uninstall(const std::string& dlc_id,
UninstallCallback callback) = 0;
virtual void GetInstalled(GetInstalledCallback callback) = 0;
// Creates and initializes the global instance. |bus| must not be nullptr.
static void Initialize(dbus::Bus* bus);
// Creates and initializes a fake global instance if not already created.
static void InitializeFake();
// Destroys the global instance.
static void Shutdown();
// Returns the global instance which may be nullptr if not initialized.
static DlcserviceClient* Get();
protected:
friend class DlcserviceClientTest;
// Initialize/Shutdown should be used instead.
DlcserviceClient();
virtual ~DlcserviceClient();
private:
DISALLOW_COPY_AND_ASSIGN(DlcserviceClient);
};
} // namespace chromeos
#endif // CHROMEOS_DBUS_DLCSERVICE_DLCSERVICE_CLIENT_H_
// Copyright (c) 2019 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/dlcservice/dlcservice_client.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_object_proxy.h"
#include "dbus/object_path.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::WithArg;
namespace chromeos {
class DlcserviceClientTest : public testing::Test {
public:
void SetUp() override {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
mock_bus_ = base::MakeRefCounted<::testing::NiceMock<dbus::MockBus>>(
dbus::Bus::Options());
mock_proxy_ = base::MakeRefCounted<dbus::MockObjectProxy>(
mock_bus_.get(), dlcservice::kDlcServiceServiceName,
dbus::ObjectPath(dlcservice::kDlcServiceServicePath));
EXPECT_CALL(
*mock_bus_.get(),
GetObjectProxy(dlcservice::kDlcServiceServiceName,
dbus::ObjectPath(dlcservice::kDlcServiceServicePath)))
.WillOnce(Return(mock_proxy_.get()));
EXPECT_CALL(*mock_proxy_.get(),
DoConnectToSignal(dlcservice::kDlcServiceInterface, _, _, _))
.WillOnce(Invoke(this, &DlcserviceClientTest::ConnectToSignal));
EXPECT_CALL(*mock_proxy_.get(), DoCallMethodWithErrorResponse(_, _, _))
.WillOnce(
Invoke(this, &DlcserviceClientTest::CallMethodWithErrorResponse));
DlcserviceClient::Initialize(mock_bus_.get());
client_ = DlcserviceClient::Get();
base::RunLoop().RunUntilIdle();
}
void TearDown() override { DlcserviceClient::Shutdown(); }
protected:
base::test::SingleThreadTaskEnvironment task_environment_;
DlcserviceClient* client_;
scoped_refptr<dbus::MockBus> mock_bus_;
scoped_refptr<dbus::MockObjectProxy> mock_proxy_;
std::unique_ptr<dbus::Response> response_;
std::unique_ptr<dbus::ErrorResponse> err_response_;
private:
void ConnectToSignal(
const std::string& interface_name,
const std::string& signal_name,
dbus::ObjectProxy::SignalCallback signal_callback,
dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
EXPECT_EQ(interface_name, dlcservice::kDlcServiceInterface);
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(std::move(*on_connected_callback), interface_name,
signal_name, true /* success */));
}
void CallMethodWithErrorResponse(
dbus::MethodCall* method_call,
int timeout_ms,
dbus::ObjectProxy::ResponseOrErrorCallback* callback) {
task_environment_.GetMainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(*callback), response_.get(),
err_response_.get()));
}
};
TEST_F(DlcserviceClientTest, GetInstalledSuccessTest) {
response_ = dbus::Response::CreateEmpty();
dbus::MessageWriter writer(response_.get());
dlcservice::DlcModuleList dlc_module_list;
writer.AppendProtoAsArrayOfBytes(dlc_module_list);
DlcserviceClient::GetInstalledCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorNone, err);
});
client_->GetInstalled(std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, GetInstalledFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kGetInstalledMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::GetInstalledCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->GetInstalled(std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, UninstallSuccessTest) {
response_ = dbus::Response::CreateEmpty();
DlcserviceClient::UninstallCallback callback = base::BindOnce(
[](const std::string& err) { EXPECT_EQ(dlcservice::kErrorNone, err); });
client_->Uninstall("some-dlc-id", std::move(callback));
base::RunLoop().RunUntilIdle();
}
TEST_F(DlcserviceClientTest, UninstallFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kUninstallMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::UninstallCallback callback =
base::BindOnce([](const std::string& err) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->Uninstall("some-dlc-id", std::move(callback));
base::RunLoop().RunUntilIdle();
}
// TODO(kimjae): Add test for |DlcserviceClient::Install()|.
TEST_F(DlcserviceClientTest, InstallFailureTest) {
dbus::MethodCall method_call(dlcservice::kDlcServiceInterface,
dlcservice::kInstallMethod);
method_call.SetSerial(123);
err_response_ = dbus::ErrorResponse::FromMethodCall(
&method_call, DBUS_ERROR_FAILED, "dlcservice/INTERNAL:msg");
DlcserviceClient::InstallCallback callback = base::BindOnce(
[](const std::string& err, const dlcservice::DlcModuleList&) {
EXPECT_EQ(dlcservice::kErrorInternal, err);
});
client_->Install(dlcservice::DlcModuleList(), std::move(callback));
base::RunLoop().RunUntilIdle();
}
} // namespace chromeos
// Copyright (c) 2012 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/dlcservice/fake_dlcservice_client.h"
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
namespace chromeos {
FakeDlcserviceClient::FakeDlcserviceClient() = default;
FakeDlcserviceClient::~FakeDlcserviceClient() = default;
void FakeDlcserviceClient::Install(
const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) {
VLOG(1) << "Requesting to install DLC(s).";
std::move(callback).Run(dlcservice::kErrorNone, dlcservice::DlcModuleList());
}
void FakeDlcserviceClient::Uninstall(const std::string& dlc_id,
UninstallCallback callback) {
VLOG(1) << "Requesting to uninstall DLC=" << dlc_id;
std::move(callback).Run(dlcservice::kErrorNone);
}
void FakeDlcserviceClient::GetInstalled(GetInstalledCallback callback) {
VLOG(1) << "Requesting to get installed DLC(s).";
std::move(callback).Run(dlcservice::kErrorNone, dlcservice::DlcModuleList());
}
} // namespace chromeos
// Copyright (c) 2012 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.
#ifndef CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
#define CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
#include <string>
#include "base/component_export.h"
#include "base/containers/queue.h"
#include "chromeos/dbus/dlcservice/dlcservice_client.h"
namespace chromeos {
// A fake implementation of DlcserviceClient. The user of this class can
// use set_update_engine_client_status() to set a fake last Status and
// GetLastStatus() returns the fake with no modification. Other methods do
// nothing.
class COMPONENT_EXPORT(DLCSERVICE_CLIENT) FakeDlcserviceClient
: public DlcserviceClient {
public:
FakeDlcserviceClient();
~FakeDlcserviceClient() override;
// DlcserviceClient:
void Install(const dlcservice::DlcModuleList& dlc_module_list,
InstallCallback callback) override;
void Uninstall(const std::string& dlc_id,
UninstallCallback callback) override;
void GetInstalled(GetInstalledCallback callback) override;
};
} // namespace chromeos
#endif // CHROMEOS_DBUS_DLCSERVICE_FAKE_DLCSERVICE_CLIENT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment