Commit 49d5b2e4 authored by Timothy Loh's avatar Timothy Loh Committed by Commit Bot

Add D-Bus and CrostiniManager logic for supporting package installation

This CL adds support in the CiceroneClient for the InstallLinuxPackage
function and the InstallLinuxPackageProgress signal. These are then
exposed via the CrostiniManager as InstallLinuxPackage and an observer
interface InstallLinuxPackageProgressObserver.

This CL also tidies up the existing Cicerone D-Bus calls to use the
default timeout instead of an infinite timeout.

This will be followed up by a CL adding UI for these:
https://chromium-review.googlesource.com/c/chromium/src/+/1126812

Bug: 822464
Change-Id: Ia293d8baa7f69c5417924c3492f54353bfeb352e
Reviewed-on: https://chromium-review.googlesource.com/1126811Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Commit-Queue: Timothy Loh <timloh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575555}
parent 8b9b9154
......@@ -773,6 +773,34 @@ void CrostiniManager::GetContainerAppIcons(
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CrostiniManager::InstallLinuxPackage(
Profile* profile,
std::string vm_name,
std::string container_name,
std::string package_path,
InstallLinuxPackageCallback callback) {
if (!GetCiceroneClient()->IsInstallLinuxPackageProgressSignalConnected()) {
// Technically we could still start the install, but we wouldn't be able to
// detect when the install completes, successfully or otherwise.
LOG(ERROR)
<< "Attempted to install package when progress signal not connected.";
std::move(callback).Run(ConciergeClientResult::INSTALL_LINUX_PACKAGE_FAILED,
std::string());
return;
}
vm_tools::cicerone::InstallLinuxPackageRequest request;
request.set_owner_id(CryptohomeIdForProfile(profile));
request.set_vm_name(std::move(vm_name));
request.set_container_name(std::move(container_name));
request.set_file_path(std::move(package_path));
GetCiceroneClient()->InstallLinuxPackage(
std::move(request),
base::BindOnce(&CrostiniManager::OnInstallLinuxPackage,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void CrostiniManager::GetContainerSshKeys(
std::string vm_name,
std::string container_name,
......@@ -880,6 +908,28 @@ void CrostiniManager::AddShutdownContainerCallback(
std::move(shutdown_callback));
}
void CrostiniManager::AddInstallLinuxPackageProgressObserver(
Profile* profile,
InstallLinuxPackageProgressObserver* observer) {
install_linux_package_progress_observers_.emplace(
CryptohomeIdForProfile(profile), observer);
}
void CrostiniManager::RemoveInstallLinuxPackageProgressObserver(
Profile* profile,
InstallLinuxPackageProgressObserver* observer) {
auto range = install_linux_package_progress_observers_.equal_range(
CryptohomeIdForProfile(profile));
for (auto it = range.first; it != range.second; ++it) {
if (it->second != observer) {
install_linux_package_progress_observers_.erase(it);
return;
}
}
NOTREACHED();
}
void CrostiniManager::OnCreateDiskImage(
CreateDiskImageCallback callback,
base::Optional<vm_tools::concierge::CreateDiskImageResponse> reply) {
......@@ -1061,6 +1111,41 @@ void CrostiniManager::OnContainerShutdown(
shutdown_container_callbacks_.erase(range.first, range.second);
}
void CrostiniManager::OnInstallLinuxPackageProgress(
const vm_tools::cicerone::InstallLinuxPackageProgressSignal& signal) {
if (signal.progress_percent() < 0 || signal.progress_percent() > 100) {
LOG(ERROR) << "Received install progress with invalid progress of "
<< signal.progress_percent() << "%.";
return;
}
InstallLinuxPackageProgressStatus status;
switch (signal.status()) {
case vm_tools::cicerone::InstallLinuxPackageProgressSignal::SUCCEEDED:
status = InstallLinuxPackageProgressStatus::SUCCEEDED;
break;
case vm_tools::cicerone::InstallLinuxPackageProgressSignal::FAILED:
status = InstallLinuxPackageProgressStatus::FAILED;
break;
case vm_tools::cicerone::InstallLinuxPackageProgressSignal::DOWNLOADING:
status = InstallLinuxPackageProgressStatus::DOWNLOADING;
break;
case vm_tools::cicerone::InstallLinuxPackageProgressSignal::INSTALLING:
status = InstallLinuxPackageProgressStatus::INSTALLING;
break;
default:
NOTREACHED();
}
auto range =
install_linux_package_progress_observers_.equal_range(signal.owner_id());
for (auto it = range.first; it != range.second; ++it) {
it->second->OnInstallLinuxPackageProgress(
signal.vm_name(), signal.container_name(), status,
signal.progress_percent(), signal.failure_details());
}
}
void CrostiniManager::OnLaunchContainerApplication(
LaunchContainerApplicationCallback callback,
base::Optional<vm_tools::cicerone::LaunchContainerApplicationResponse>
......@@ -1101,6 +1186,39 @@ void CrostiniManager::OnGetContainerAppIcons(
std::move(callback).Run(ConciergeClientResult::SUCCESS, icons);
}
void CrostiniManager::OnInstallLinuxPackage(
InstallLinuxPackageCallback callback,
base::Optional<vm_tools::cicerone::InstallLinuxPackageResponse> reply) {
if (!reply.has_value()) {
LOG(ERROR) << "Failed to install Linux package. Empty response.";
std::move(callback).Run(
ConciergeClientResult::LAUNCH_CONTAINER_APPLICATION_FAILED,
std::string());
return;
}
vm_tools::cicerone::InstallLinuxPackageResponse response = reply.value();
if (response.status() ==
vm_tools::cicerone::InstallLinuxPackageResponse::FAILED) {
LOG(ERROR) << "Failed to install Linux package: "
<< response.failure_reason();
std::move(callback).Run(ConciergeClientResult::INSTALL_LINUX_PACKAGE_FAILED,
response.failure_reason());
return;
}
if (response.status() ==
vm_tools::cicerone::InstallLinuxPackageResponse::INSTALL_ALREADY_ACTIVE) {
LOG(WARNING) << "Failed to install Linux package, install already active.";
std::move(callback).Run(
ConciergeClientResult::INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE,
std::string());
return;
}
std::move(callback).Run(ConciergeClientResult::SUCCESS, std::string());
}
void CrostiniManager::OnGetContainerSshKeys(
GetContainerSshKeysCallback callback,
base::Optional<vm_tools::concierge::ContainerSshKeysResponse> reply) {
......
......@@ -41,9 +41,18 @@ enum class ConciergeClientResult {
DISK_TYPE_ERROR,
CONTAINER_START_FAILED,
LAUNCH_CONTAINER_APPLICATION_FAILED,
INSTALL_LINUX_PACKAGE_FAILED,
INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE,
UNKNOWN_ERROR,
};
enum class InstallLinuxPackageProgressStatus {
SUCCEEDED,
FAILED,
DOWNLOADING,
INSTALLING,
};
// Return type when getting app icons from within a container.
struct Icon {
std::string desktop_file_id;
......@@ -52,6 +61,21 @@ struct Icon {
std::string content;
};
class InstallLinuxPackageProgressObserver {
public:
// A successfully started package install will continually fire progress
// events until it returns a status of SUCCEEDED or FAILED. The
// |progress_percent| field is given as a percentage of the given step,
// DOWNLOADING or INSTALLING. |failure_reason| is returned from the container
// for a FAILED case, and not necessarily localized.
virtual void OnInstallLinuxPackageProgress(
const std::string& vm_name,
const std::string& container_name,
InstallLinuxPackageProgressStatus status,
int progress_percent,
const std::string& failure_reason) = 0;
};
// CrostiniManager is a singleton which is used to check arguments for
// ConciergeClient and CiceroneClient. ConciergeClient is dedicated to
// communication with the Concierge service, CiceroneClient is dedicated to
......@@ -94,6 +118,12 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
using GetContainerAppIconsCallback =
base::OnceCallback<void(ConciergeClientResult result,
std::vector<Icon>& icons)>;
// The type of the callback for CrostiniManager::InstallLinuxPackage.
// |failure_reason| is returned from the container upon failure
// (INSTALL_LINUX_PACKAGE_FAILED), and not necessarily localized.
using InstallLinuxPackageCallback =
base::OnceCallback<void(ConciergeClientResult result,
const std::string& failure_reason)>;
// The type of the callback for CrostiniManager::GetContainerSshKeys.
using GetContainerSshKeysCallback =
base::OnceCallback<void(ConciergeClientResult result,
......@@ -212,6 +242,15 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
int scale,
GetContainerAppIconsCallback callback);
// Begin installation of a Linux Package inside the container. If the
// installation is successfully started, further updates will be sent to
// added InstallLinuxPackageProgressObservers.
void InstallLinuxPackage(Profile* profile,
std::string vm_name,
std::string container_name,
std::string package_path,
InstallLinuxPackageCallback callback);
// Asynchronously gets SSH server public key of container and trusted SSH
// client private key which can be used to connect to the container.
// |callback| is called after the method call finishes.
......@@ -259,6 +298,14 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
std::string container_name,
ShutdownContainerCallback shutdown_callback);
// Add/remove observers for package install progress.
void AddInstallLinuxPackageProgressObserver(
Profile* profile,
InstallLinuxPackageProgressObserver* observer);
void RemoveInstallLinuxPackageProgressObserver(
Profile* profile,
InstallLinuxPackageProgressObserver* observer);
// ConciergeClient::Observer:
void OnContainerStartupFailed(
const vm_tools::concierge::ContainerStartedSignal& signal) override;
......@@ -268,6 +315,9 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
const vm_tools::cicerone::ContainerStartedSignal& signal) override;
void OnContainerShutdown(
const vm_tools::cicerone::ContainerShutdownSignal& signal) override;
void OnInstallLinuxPackageProgress(
const vm_tools::cicerone::InstallLinuxPackageProgressSignal& signal)
override;
void RemoveCrostini(Profile* profile,
std::string vm_name,
......@@ -350,6 +400,11 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
GetContainerAppIconsCallback callback,
base::Optional<vm_tools::cicerone::ContainerAppIconResponse> reply);
// Callback for CrostiniManager::InstallLinuxPackage.
void OnInstallLinuxPackage(
InstallLinuxPackageCallback callback,
base::Optional<vm_tools::cicerone::InstallLinuxPackageResponse> reply);
// Callback for CrostiniManager::GetContainerSshKeys. Called after the
// Concierge service finishes.
void OnGetContainerSshKeys(
......@@ -384,6 +439,10 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
std::multimap<std::pair<std::string, std::string>, std::string>
running_containers_;
// Keyed by owner_id.
std::multimap<std::string, InstallLinuxPackageProgressObserver*>
install_linux_package_progress_observers_;
// 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<CrostiniManager> weak_ptr_factory_;
......
......@@ -108,6 +108,16 @@ class CrostiniManagerTest : public testing::Test {
std::move(closure).Run();
}
void InstallLinuxPackageCallback(base::OnceClosure closure,
ConciergeClientResult expected_result,
const std::string& expected_failure_reason,
ConciergeClientResult result,
const std::string& failure_reason) {
EXPECT_EQ(expected_result, result);
EXPECT_EQ(expected_failure_reason, failure_reason);
std::move(closure).Run();
}
CrostiniManagerTest()
: fake_cicerone_client_(new chromeos::FakeCiceroneClient()),
fake_concierge_client_(new chromeos::FakeConciergeClient()),
......@@ -367,6 +377,45 @@ TEST_F(CrostiniManagerTest, StartContainerSuccess) {
run_loop()->Run();
}
TEST_F(CrostiniManagerTest, InstallLinuxPackageSignalNotConnectedError) {
fake_cicerone_client_->set_install_linux_package_progress_signal_connected(
false);
CrostiniManager::GetInstance()->InstallLinuxPackage(
profile(), kVmName, kContainerName, "/tmp/package.deb",
base::BindOnce(&CrostiniManagerTest::InstallLinuxPackageCallback,
base::Unretained(this), run_loop()->QuitClosure(),
ConciergeClientResult::INSTALL_LINUX_PACKAGE_FAILED,
std::string()));
run_loop()->Run();
}
TEST_F(CrostiniManagerTest, InstallLinuxPackageSignalSuccess) {
vm_tools::cicerone::InstallLinuxPackageResponse response;
response.set_status(vm_tools::cicerone::InstallLinuxPackageResponse::STARTED);
fake_cicerone_client_->set_install_linux_package_response(response);
CrostiniManager::GetInstance()->InstallLinuxPackage(
profile(), kVmName, kContainerName, "/tmp/package.deb",
base::BindOnce(&CrostiniManagerTest::InstallLinuxPackageCallback,
base::Unretained(this), run_loop()->QuitClosure(),
ConciergeClientResult::SUCCESS, std::string()));
run_loop()->Run();
}
TEST_F(CrostiniManagerTest, InstallLinuxPackageSignalFailure) {
vm_tools::cicerone::InstallLinuxPackageResponse response;
std::string failure_reason = "Unit tests can't install Linux packages!";
response.set_status(vm_tools::cicerone::InstallLinuxPackageResponse::FAILED);
response.set_failure_reason(failure_reason);
fake_cicerone_client_->set_install_linux_package_response(response);
CrostiniManager::GetInstance()->InstallLinuxPackage(
profile(), kVmName, kContainerName, "/tmp/package.deb",
base::BindOnce(&CrostiniManagerTest::InstallLinuxPackageCallback,
base::Unretained(this), run_loop()->QuitClosure(),
ConciergeClientResult::INSTALL_LINUX_PACKAGE_FAILED,
failure_reason));
run_loop()->Run();
}
class CrostiniManagerRestartTest : public CrostiniManagerTest,
public CrostiniManager::RestartObserver {
public:
......
......@@ -36,6 +36,10 @@ class CiceroneClientImpl : public CiceroneClient {
return is_container_shutdown_signal_connected_;
}
bool IsInstallLinuxPackageProgressSignalConnected() override {
return is_install_linux_package_progress_signal_connected_;
}
void LaunchContainerApplication(
const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
......@@ -53,7 +57,7 @@ class CiceroneClientImpl : public CiceroneClient {
}
cicerone_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(
&CiceroneClientImpl::OnDBusProtoResponse<
vm_tools::cicerone::LaunchContainerApplicationResponse>,
......@@ -76,12 +80,34 @@ class CiceroneClientImpl : public CiceroneClient {
}
cicerone_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
vm_tools::cicerone::ContainerAppIconResponse>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void InstallLinuxPackage(
const vm_tools::cicerone::InstallLinuxPackageRequest& request,
DBusMethodCallback<vm_tools::cicerone::InstallLinuxPackageResponse>
callback) override {
dbus::MethodCall method_call(
vm_tools::cicerone::kVmCiceroneInterface,
vm_tools::cicerone::kInstallLinuxPackageMethod);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode InstallLinuxPackageRequest protobuf";
std::move(callback).Run(base::nullopt);
return;
}
cicerone_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&CiceroneClientImpl::OnDBusProtoResponse<
vm_tools::cicerone::InstallLinuxPackageResponse>,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WaitForServiceToBeAvailable(
dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback)
override {
......@@ -111,6 +137,14 @@ class CiceroneClientImpl : public CiceroneClient {
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
weak_ptr_factory_.GetWeakPtr()));
cicerone_proxy_->ConnectToSignal(
vm_tools::cicerone::kVmCiceroneInterface,
vm_tools::cicerone::kInstallLinuxPackageProgressSignal,
base::BindRepeating(
&CiceroneClientImpl::OnInstallLinuxPackageProgressSignal,
weak_ptr_factory_.GetWeakPtr()),
base::BindOnce(&CiceroneClientImpl::OnSignalConnected,
weak_ptr_factory_.GetWeakPtr()));
}
private:
......@@ -155,6 +189,18 @@ class CiceroneClientImpl : public CiceroneClient {
}
}
void OnInstallLinuxPackageProgressSignal(dbus::Signal* signal) {
vm_tools::cicerone::InstallLinuxPackageProgressSignal proto;
dbus::MessageReader reader(signal);
if (!reader.PopArrayOfBytesAsProto(&proto)) {
LOG(ERROR) << "Failed to parse proto from DBus Signal";
return;
}
for (auto& observer : observer_list_) {
observer.OnInstallLinuxPackageProgress(proto);
}
}
void OnSignalConnected(const std::string& interface_name,
const std::string& signal_name,
bool is_connected) {
......@@ -167,6 +213,9 @@ class CiceroneClientImpl : public CiceroneClient {
is_container_started_signal_connected_ = is_connected;
} else if (signal_name == vm_tools::cicerone::kContainerShutdownSignal) {
is_container_shutdown_signal_connected_ = is_connected;
} else if (signal_name ==
vm_tools::cicerone::kInstallLinuxPackageProgressSignal) {
is_install_linux_package_progress_signal_connected_ = is_connected;
} else {
NOTREACHED();
}
......@@ -178,6 +227,7 @@ class CiceroneClientImpl : public CiceroneClient {
bool is_container_started_signal_connected_ = false;
bool is_container_shutdown_signal_connected_ = false;
bool is_install_linux_package_progress_signal_connected_ = false;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
......
......@@ -30,6 +30,12 @@ class CHROMEOS_EXPORT CiceroneClient : public DBusClient {
virtual void OnContainerShutdown(
const vm_tools::cicerone::ContainerShutdownSignal& signal) = 0;
// This is signaled from the container while a package is being installed
// via InstallLinuxPackage.
virtual void OnInstallLinuxPackageProgress(
const vm_tools::cicerone::InstallLinuxPackageProgressSignal&
signal) = 0;
protected:
virtual ~Observer() = default;
};
......@@ -50,6 +56,9 @@ class CHROMEOS_EXPORT CiceroneClient : public DBusClient {
// is called.
virtual bool IsContainerShutdownSignalConnected() = 0;
// This should be true prior to calling InstallLinuxPackage.
virtual bool IsInstallLinuxPackageProgressSignalConnected() = 0;
// Launches an application inside a running Container.
// |callback| is called after the method call finishes.
virtual void LaunchContainerApplication(
......@@ -64,6 +73,13 @@ class CHROMEOS_EXPORT CiceroneClient : public DBusClient {
DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse>
callback) = 0;
// Installs a package inside the container.
// |callback| is called after the method call finishes.
virtual void InstallLinuxPackage(
const vm_tools::cicerone::InstallLinuxPackageRequest& request,
DBusMethodCallback<vm_tools::cicerone::InstallLinuxPackageResponse>
callback) = 0;
// Registers |callback| to run when the Cicerone service becomes available.
// If the service is already available, or if connecting to the name-owner-
// changed signal fails, |callback| will be run once asynchronously.
......
......@@ -13,6 +13,10 @@ FakeCiceroneClient::FakeCiceroneClient() {
launch_container_application_response_.set_success(true);
container_app_icon_response_.Clear();
install_linux_package_response_.Clear();
install_linux_package_response_.set_status(
vm_tools::cicerone::InstallLinuxPackageResponse::STARTED);
}
FakeCiceroneClient::~FakeCiceroneClient() = default;
......@@ -32,6 +36,10 @@ bool FakeCiceroneClient::IsContainerShutdownSignalConnected() {
return is_container_shutdown_signal_connected_;
}
bool FakeCiceroneClient::IsInstallLinuxPackageProgressSignalConnected() {
return is_install_linux_package_progress_signal_connected;
}
void FakeCiceroneClient::LaunchContainerApplication(
const vm_tools::cicerone::LaunchContainerApplicationRequest& request,
DBusMethodCallback<vm_tools::cicerone::LaunchContainerApplicationResponse>
......@@ -49,6 +57,15 @@ void FakeCiceroneClient::GetContainerAppIcons(
base::BindOnce(std::move(callback), container_app_icon_response_));
}
void FakeCiceroneClient::InstallLinuxPackage(
const vm_tools::cicerone::InstallLinuxPackageRequest& request,
DBusMethodCallback<vm_tools::cicerone::InstallLinuxPackageResponse>
callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), install_linux_package_response_));
}
void FakeCiceroneClient::WaitForServiceToBeAvailable(
dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
......
......@@ -29,6 +29,9 @@ class CHROMEOS_EXPORT FakeCiceroneClient : public CiceroneClient {
// is called.
bool IsContainerShutdownSignalConnected() override;
// This should be true prior to calling InstallLinuxPackage.
bool IsInstallLinuxPackageProgressSignalConnected() override;
// Fake version of the method that launches an application inside a running
// Container. |callback| is called after the method call finishes.
void LaunchContainerApplication(
......@@ -43,6 +46,14 @@ class CHROMEOS_EXPORT FakeCiceroneClient : public CiceroneClient {
DBusMethodCallback<vm_tools::cicerone::ContainerAppIconResponse> callback)
override;
// Fake version of the method that installs an application inside a running
// Container. |callback| is called after the method call finishes. This does
// not cause progress events to be fired.
void InstallLinuxPackage(
const vm_tools::cicerone::InstallLinuxPackageRequest& request,
DBusMethodCallback<vm_tools::cicerone::InstallLinuxPackageResponse>
callback) override;
// Fake version of the method that waits for the Cicerone service to be
// availble. |callback| is called after the method call finishes.
void WaitForServiceToBeAvailable(
......@@ -58,28 +69,43 @@ class CHROMEOS_EXPORT FakeCiceroneClient : public CiceroneClient {
is_container_shutdown_signal_connected_ = connected;
}
// Set InstallLinuxPackageProgressSignalConnected state
void set_install_linux_package_progress_signal_connected(bool connected) {
is_install_linux_package_progress_signal_connected = connected;
}
void set_launch_container_application_response(
const vm_tools::cicerone::LaunchContainerApplicationResponse&
launch_container_application_response) {
launch_container_application_response_ =
launch_container_application_response;
}
void set_container_app_icon_response(
const vm_tools::cicerone::ContainerAppIconResponse&
container_app_icon_response) {
container_app_icon_response_ = container_app_icon_response;
}
void set_install_linux_package_response(
const vm_tools::cicerone::InstallLinuxPackageResponse&
install_linux_package_response) {
install_linux_package_response_ = install_linux_package_response;
}
protected:
void Init(dbus::Bus* bus) override {}
private:
bool is_container_started_signal_connected_ = true;
bool is_container_shutdown_signal_connected_ = true;
bool is_install_linux_package_progress_signal_connected = true;
vm_tools::cicerone::LaunchContainerApplicationResponse
launch_container_application_response_;
vm_tools::cicerone::ContainerAppIconResponse container_app_icon_response_;
vm_tools::cicerone::InstallLinuxPackageResponse
install_linux_package_response_;
base::ObserverList<Observer> observer_list_;
DISALLOW_COPY_AND_ASSIGN(FakeCiceroneClient);
......
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