Commit 64ab6403 authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

CrOS crostini: sshfs mount immediately when container starts

Perform sshfs mount to termina/penguin immediately when container
starts.  Mounting code has moved from the chrome.fileManagerPrivate
extension functions into CrostiniManager.

This change will make FilesApp more responsive to users who are
likely to use terminal or some other crostini app before using FilesApp.

Bug: 846917
Change-Id: I9fc246e45e54390e7a75f15a5571a24218cf2d5c
Reviewed-on: https://chromium-review.googlesource.com/1158317Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580094}
parent 5a74abd2
...@@ -5072,6 +5072,12 @@ ...@@ -5072,6 +5072,12 @@
<message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE" desc="Text shown in the Crostini installer dialog when the container inside the VM is starting"> <message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE" desc="Text shown in the Crostini installer dialog when the container inside the VM is starting">
This process may take a few minutes. Starting the Linux container. This process may take a few minutes. Starting the Linux container.
</message> </message>
<message name="IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_MESSAGE" desc="Text shown in the Crostini installer dialog when fetching ssh keys">
This process may take a few minutes. Starting the Linux container.
</message>
<message name="IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_MESSAGE" desc="Text shown in the Crostini installer dialog when doing sshfs mount of container">
This process may take a few minutes. Starting the Linux container.
</message>
<message name="IDS_CROSTINI_INSTALLER_RETRY_BUTTON" desc="Retry button of the Crostini installer dialog that starts the install steps again."> <message name="IDS_CROSTINI_INSTALLER_RETRY_BUTTON" desc="Retry button of the Crostini installer dialog that starts the install steps again.">
Retry Retry
</message> </message>
...@@ -5093,6 +5099,12 @@ ...@@ -5093,6 +5099,12 @@
<message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR" desc="Text shown in the Crostini installer dialog when the container fails to start inside the VM"> <message name="IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR" desc="Text shown in the Crostini installer dialog when the container fails to start inside the VM">
The Linux container didn't start. Please try again. The Linux container didn't start. Please try again.
</message> </message>
<message name="IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_ERROR" desc="Text shown in the Crostini installer dialog when there is an error fetching ssh keys">
Error configuring the Linux container to access files. Please try again.
</message>
<message name="IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_ERROR" desc="Text shown in the Crostini installer dialog when the container ssh mount fails">
Error mounting Linux files. Please try again.
</message>
<message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files."> <message name="IDS_CROSTINI_UNINSTALLER_TITLE" desc="Title of the Crostini uninstaller, a dialog for uninstalling Linux, the associated VM and Linux files.">
Delete Linux (Beta) Delete Linux (Beta)
</message> </message>
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_remover.h" #include "chrome/browser/chromeos/crostini/crostini_remover.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/file_manager/path_util.h"
#include "chrome/browser/chromeos/file_manager/volume_manager.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/component_updater/cros_component_installer_chromeos.h" #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -23,9 +25,11 @@ ...@@ -23,9 +25,11 @@
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/application_launch.h"
#include "chromeos/dbus/concierge_client.h" #include "chromeos/dbus/concierge_client.h"
#include "chromeos/dbus/cros_disks_client.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon_client.h" #include "chromeos/dbus/debug_daemon_client.h"
#include "chromeos/dbus/image_loader_client.h" #include "chromeos/dbus/image_loader_client.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -33,6 +37,7 @@ ...@@ -33,6 +37,7 @@
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "net/base/escape.h" #include "net/base/escape.h"
#include "net/base/network_change_notifier.h" #include "net/base/network_change_notifier.h"
#include "storage/browser/fileapi/external_mount_points.h"
namespace crostini { namespace crostini {
...@@ -59,10 +64,9 @@ class CrostiniRestarterService : public KeyedService { ...@@ -59,10 +64,9 @@ class CrostiniRestarterService : public KeyedService {
~CrostiniRestarterService() override = default; ~CrostiniRestarterService() override = default;
CrostiniManager::RestartId Register( CrostiniManager::RestartId Register(
Profile* profile,
std::string vm_name, std::string vm_name,
std::string crypothome_id,
std::string container_name, std::string container_name,
std::string container_username,
CrostiniManager::RestartCrostiniCallback callback, CrostiniManager::RestartCrostiniCallback callback,
CrostiniManager::RestartObserver* observer); CrostiniManager::RestartObserver* observer);
...@@ -114,15 +118,18 @@ class CrostiniRestarterServiceFactory ...@@ -114,15 +118,18 @@ class CrostiniRestarterServiceFactory
} }
}; };
class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> { class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter>,
public chromeos::disks::DiskMountManager::Observer {
public: public:
CrostiniRestarter(CrostiniRestarterService* restarter_service, CrostiniRestarter(CrostiniRestarterService* restarter_service,
Profile* profile,
std::string vm_name, std::string vm_name,
std::string cryptohome_id, std::string cryptohome_id,
std::string container_name, std::string container_name,
std::string container_username, std::string container_username,
CrostiniManager::RestartCrostiniCallback callback) CrostiniManager::RestartCrostiniCallback callback)
: vm_name_(std::move(vm_name)), : profile_(profile),
vm_name_(std::move(vm_name)),
cryptohome_id_(std::move(cryptohome_id)), cryptohome_id_(std::move(cryptohome_id)),
container_name_(std::move(container_name)), container_name_(std::move(container_name)),
container_username_(std::move(container_username)), container_username_(std::move(container_username)),
...@@ -136,11 +143,11 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> { ...@@ -136,11 +143,11 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
return; return;
CrostiniManager* crostini_manager = CrostiniManager::GetInstance(); CrostiniManager* crostini_manager = CrostiniManager::GetInstance();
// Finish Restart immediately if testing. // Go to StartContainerFinished immediately if testing.
if (crostini_manager->skip_restart_for_testing()) { if (crostini_manager->skip_restart_for_testing()) {
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&CrostiniRestarter::FinishRestart, base::BindOnce(&CrostiniRestarter::StartContainerFinished,
base::WrapRefCounted(this), base::WrapRefCounted(this),
ConciergeClientResult::SUCCESS)); ConciergeClientResult::SUCCESS));
return; return;
...@@ -170,7 +177,7 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> { ...@@ -170,7 +177,7 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
private: private:
friend class base::RefCountedThreadSafe<CrostiniRestarter>; friend class base::RefCountedThreadSafe<CrostiniRestarter>;
~CrostiniRestarter() { ~CrostiniRestarter() override {
if (callback_) { if (callback_) {
LOG(ERROR) << "Destroying without having called the callback."; LOG(ERROR) << "Destroying without having called the callback.";
} }
...@@ -259,18 +266,109 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> { ...@@ -259,18 +266,109 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
void StartContainerFinished(ConciergeClientResult result) { void StartContainerFinished(ConciergeClientResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Tell observers.
for (auto& observer : observer_list_) {
observer.OnContainerStarted(result);
}
if (is_aborted_)
return;
if (result != ConciergeClientResult::SUCCESS) { if (result != ConciergeClientResult::SUCCESS) {
LOG(ERROR) << "Failed to start container."; LOG(ERROR) << "Failed to start container.";
FinishRestart(result);
return;
}
// If default termina/penguin, then do sshfs mount, else we are finished.
if (vm_name_ == kCrostiniDefaultVmName &&
container_name_ == kCrostiniDefaultContainerName) {
CrostiniManager::GetInstance()->GetContainerSshKeys(
vm_name_, container_name_, cryptohome_id_,
base::BindOnce(&CrostiniRestarter::GetContainerSshKeysFinished,
this));
} else {
FinishRestart(result);
}
}
void GetContainerSshKeysFinished(crostini::ConciergeClientResult result,
const std::string& container_public_key,
const std::string& host_private_key,
const std::string& hostname) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Tell observers.
for (auto& observer : observer_list_) {
observer.OnSshKeysFetched(result);
} }
if (is_aborted_) if (is_aborted_)
return; return;
FinishRestart(result); if (result != crostini::ConciergeClientResult::SUCCESS) {
LOG(ERROR) << "Failed to get ssh keys.";
FinishRestart(result);
return;
}
// Add DiskMountManager::OnMountEvent observer.
auto* dmgr = chromeos::disks::DiskMountManager::GetInstance();
dmgr->AddObserver(this);
// Call to sshfs to mount.
source_path_ = base::StringPrintf(
"sshfs://%s@%s:", container_username_.c_str(), hostname.c_str());
dmgr->MountPath(source_path_, "",
file_manager::util::GetCrostiniMountPointName(profile_),
file_manager::util::GetCrostiniMountOptions(
hostname, host_private_key, container_public_key),
chromeos::MOUNT_TYPE_NETWORK_STORAGE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
}
void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
chromeos::MountError error_code,
const chromeos::disks::DiskMountManager::MountPointInfo&
mount_info) override {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Ignore any other mount/unmount events.
if (event != chromeos::disks::DiskMountManager::MountEvent::MOUNTING ||
mount_info.source_path != source_path_) {
return;
}
// Remove DiskMountManager::OnMountEvent observer.
chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this);
if (error_code != chromeos::MountError::MOUNT_ERROR_NONE) {
LOG(ERROR) << "Error mounting crostini container: error_code="
<< error_code << ", source_path=" << mount_info.source_path
<< ", mount_path=" << mount_info.mount_path
<< ", mount_type=" << mount_info.mount_type
<< ", mount_condition=" << mount_info.mount_condition;
} else {
// Register filesystem and add volume to VolumeManager.
base::FilePath mount_path =
base::FilePath(FILE_PATH_LITERAL(mount_info.mount_path));
storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
file_manager::util::GetCrostiniMountPointName(profile_),
storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(),
mount_path);
// VolumeManager is null in unittest.
if (auto* vmgr = file_manager::VolumeManager::Get(profile_))
vmgr->AddSshfsCrostiniVolume(mount_path);
}
// Abort not checked until end of function. On abort, do not call
// FinishRestart, but still remove observer and add volume as per above.
if (is_aborted_)
return;
FinishRestart(ConciergeClientResult::SUCCESS);
} }
Profile* profile_;
std::string vm_name_; std::string vm_name_;
std::string cryptohome_id_; std::string cryptohome_id_;
std::string container_name_; std::string container_name_;
std::string container_username_; std::string container_username_;
std::string source_path_;
CrostiniManager::RestartCrostiniCallback callback_; CrostiniManager::RestartCrostiniCallback callback_;
base::ObserverList<CrostiniManager::RestartObserver> observer_list_; base::ObserverList<CrostiniManager::RestartObserver> observer_list_;
CrostiniManager::RestartId restart_id_; CrostiniManager::RestartId restart_id_;
...@@ -283,15 +381,14 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> { ...@@ -283,15 +381,14 @@ class CrostiniRestarter : public base::RefCountedThreadSafe<CrostiniRestarter> {
CrostiniManager::RestartId CrostiniRestarter::next_restart_id_ = 0; CrostiniManager::RestartId CrostiniRestarter::next_restart_id_ = 0;
CrostiniManager::RestartId CrostiniRestarterService::Register( CrostiniManager::RestartId CrostiniRestarterService::Register(
Profile* profile,
std::string vm_name, std::string vm_name,
std::string cryptohome_id,
std::string container_name, std::string container_name,
std::string container_username,
CrostiniManager::RestartCrostiniCallback callback, CrostiniManager::RestartCrostiniCallback callback,
CrostiniManager::RestartObserver* observer) { CrostiniManager::RestartObserver* observer) {
auto restarter = base::MakeRefCounted<CrostiniRestarter>( auto restarter = base::MakeRefCounted<CrostiniRestarter>(
this, std::move(vm_name), std::move(cryptohome_id), this, profile, std::move(vm_name), CryptohomeIdForProfile(profile),
std::move(container_name), std::move(container_username), std::move(container_name), ContainerUserNameForProfile(profile),
std::move(callback)); std::move(callback));
if (observer) if (observer)
restarter->AddObserver(observer); restarter->AddObserver(observer);
...@@ -979,8 +1076,7 @@ CrostiniManager::RestartId CrostiniManager::RestartCrostini( ...@@ -979,8 +1076,7 @@ CrostiniManager::RestartId CrostiniManager::RestartCrostini(
RestartObserver* observer) { RestartObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return CrostiniRestarterServiceFactory::GetForProfile(profile)->Register( return CrostiniRestarterServiceFactory::GetForProfile(profile)->Register(
std::move(vm_name), CryptohomeIdForProfile(profile), profile, std::move(vm_name), std::move(container_name),
std::move(container_name), ContainerUserNameForProfile(profile),
std::move(callback), observer); std::move(callback), observer);
} }
......
...@@ -43,6 +43,7 @@ enum class ConciergeClientResult { ...@@ -43,6 +43,7 @@ enum class ConciergeClientResult {
LAUNCH_CONTAINER_APPLICATION_FAILED, LAUNCH_CONTAINER_APPLICATION_FAILED,
INSTALL_LINUX_PACKAGE_FAILED, INSTALL_LINUX_PACKAGE_FAILED,
INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE, INSTALL_LINUX_PACKAGE_ALREADY_ACTIVE,
SSHFS_MOUNT_ERROR,
UNKNOWN_ERROR, UNKNOWN_ERROR,
}; };
...@@ -142,6 +143,8 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer, ...@@ -142,6 +143,8 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
virtual void OnConciergeStarted(ConciergeClientResult result) = 0; virtual void OnConciergeStarted(ConciergeClientResult result) = 0;
virtual void OnDiskImageCreated(ConciergeClientResult result) = 0; virtual void OnDiskImageCreated(ConciergeClientResult result) = 0;
virtual void OnVmStarted(ConciergeClientResult result) = 0; virtual void OnVmStarted(ConciergeClientResult result) = 0;
virtual void OnContainerStarted(ConciergeClientResult result) = 0;
virtual void OnSshKeysFetched(ConciergeClientResult result) = 0;
}; };
// Checks if the cros-termina component is installed. // Checks if the cros-termina component is installed.
......
...@@ -3,15 +3,19 @@ ...@@ -3,15 +3,19 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "base/base64.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_cicerone_client.h" #include "chromeos/dbus/fake_cicerone_client.h"
#include "chromeos/dbus/fake_concierge_client.h" #include "chromeos/dbus/fake_concierge_client.h"
#include "chromeos/disks/mock_disk_mount_manager.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "storage/browser/fileapi/external_mount_points.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace crostini { namespace crostini {
...@@ -450,6 +454,18 @@ class CrostiniManagerRestartTest : public CrostiniManagerTest, ...@@ -450,6 +454,18 @@ class CrostiniManagerRestartTest : public CrostiniManagerTest,
} }
} }
void OnContainerStarted(ConciergeClientResult result) override {
if (abort_on_container_started_) {
Abort();
}
}
void OnSshKeysFetched(ConciergeClientResult result) override {
if (abort_on_ssh_keys_fetched_) {
Abort();
}
}
protected: protected:
void Abort() { void Abort() {
CrostiniManager::GetInstance()->AbortRestartCrostini(profile(), CrostiniManager::GetInstance()->AbortRestartCrostini(profile(),
...@@ -457,13 +473,32 @@ class CrostiniManagerRestartTest : public CrostiniManagerTest, ...@@ -457,13 +473,32 @@ class CrostiniManagerRestartTest : public CrostiniManagerTest,
run_loop()->Quit(); run_loop()->Quit();
} }
void SshfsMount(const std::string& source_path,
const std::string& source_format,
const std::string& mount_label,
const std::vector<std::string>& mount_options,
chromeos::MountType type,
chromeos::MountAccessMode access_mode) {
disk_mount_manager_mock_->NotifyMountEvent(
chromeos::disks::DiskMountManager::MountEvent::MOUNTING,
chromeos::MountError::MOUNT_ERROR_NONE,
chromeos::disks::DiskMountManager::MountPointInfo(
source_path, "/media/fuse/" + mount_label,
chromeos::MountType::MOUNT_TYPE_NETWORK_STORAGE,
chromeos::disks::MountCondition::MOUNT_CONDITION_NONE));
run_loop()->Quit();
}
CrostiniManager::RestartId restart_id_ = CrostiniManager::RestartId restart_id_ =
CrostiniManager::kUninitializedRestartId; CrostiniManager::kUninitializedRestartId;
bool abort_on_component_loaded_ = false; bool abort_on_component_loaded_ = false;
bool abort_on_concierge_started_ = false; bool abort_on_concierge_started_ = false;
bool abort_on_disk_image_created_ = false; bool abort_on_disk_image_created_ = false;
bool abort_on_vm_started_ = false; bool abort_on_vm_started_ = false;
bool abort_on_container_started_ = false;
bool abort_on_ssh_keys_fetched_ = false;
int restart_crostini_callback_count_ = 0; int restart_crostini_callback_count_ = 0;
chromeos::disks::MockDiskMountManager* disk_mount_manager_mock_;
}; };
TEST_F(CrostiniManagerRestartTest, RestartSuccess) { TEST_F(CrostiniManagerRestartTest, RestartSuccess) {
...@@ -476,6 +511,8 @@ TEST_F(CrostiniManagerRestartTest, RestartSuccess) { ...@@ -476,6 +511,8 @@ TEST_F(CrostiniManagerRestartTest, RestartSuccess) {
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called()); EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called()); EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_TRUE(fake_concierge_client_->start_container_called()); EXPECT_TRUE(fake_concierge_client_->start_container_called());
// Mount only performed for termina/penguin.
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(1, restart_crostini_callback_count_); EXPECT_EQ(1, restart_crostini_callback_count_);
} }
...@@ -490,6 +527,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnComponentLoaded) { ...@@ -490,6 +527,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnComponentLoaded) {
EXPECT_FALSE(fake_concierge_client_->create_disk_image_called()); EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called()); EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
EXPECT_FALSE(fake_concierge_client_->start_container_called()); EXPECT_FALSE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(0, restart_crostini_callback_count_); EXPECT_EQ(0, restart_crostini_callback_count_);
} }
...@@ -504,6 +542,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnConciergeStarted) { ...@@ -504,6 +542,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnConciergeStarted) {
EXPECT_FALSE(fake_concierge_client_->create_disk_image_called()); EXPECT_FALSE(fake_concierge_client_->create_disk_image_called());
EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called()); EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
EXPECT_FALSE(fake_concierge_client_->start_container_called()); EXPECT_FALSE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(0, restart_crostini_callback_count_); EXPECT_EQ(0, restart_crostini_callback_count_);
} }
...@@ -518,6 +557,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnDiskImageCreated) { ...@@ -518,6 +557,7 @@ TEST_F(CrostiniManagerRestartTest, AbortOnDiskImageCreated) {
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called()); EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called()); EXPECT_FALSE(fake_concierge_client_->start_termina_vm_called());
EXPECT_FALSE(fake_concierge_client_->start_container_called()); EXPECT_FALSE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(0, restart_crostini_callback_count_); EXPECT_EQ(0, restart_crostini_callback_count_);
} }
...@@ -532,9 +572,41 @@ TEST_F(CrostiniManagerRestartTest, AbortOnVmStarted) { ...@@ -532,9 +572,41 @@ TEST_F(CrostiniManagerRestartTest, AbortOnVmStarted) {
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called()); EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called()); EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_FALSE(fake_concierge_client_->start_container_called()); EXPECT_FALSE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(0, restart_crostini_callback_count_); EXPECT_EQ(0, restart_crostini_callback_count_);
} }
TEST_F(CrostiniManagerRestartTest, AbortOnContainerStarted) {
abort_on_container_started_ = true;
// Use termina/penguin names to allow fetch ssh keys.
restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
profile(), kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
base::Unretained(this), run_loop()->QuitClosure()),
this);
run_loop()->Run();
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_TRUE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(0, restart_crostini_callback_count_);
}
TEST_F(CrostiniManagerRestartTest, OnlyMountTerminaPenguin) {
// Use names other than termina/penguin. Will not mount sshfs.
restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
profile(), kVmName, kContainerName,
base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
base::Unretained(this), run_loop()->QuitClosure()),
this);
run_loop()->Run();
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_TRUE(fake_concierge_client_->start_container_called());
EXPECT_FALSE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(1, restart_crostini_callback_count_);
}
TEST_F(CrostiniManagerRestartTest, MultiRestartAllowed) { TEST_F(CrostiniManagerRestartTest, MultiRestartAllowed) {
CrostiniManager::GetInstance()->RestartCrostini( CrostiniManager::GetInstance()->RestartCrostini(
profile(), kVmName, kContainerName, profile(), kVmName, kContainerName,
...@@ -556,4 +628,48 @@ TEST_F(CrostiniManagerRestartTest, MultiRestartAllowed) { ...@@ -556,4 +628,48 @@ TEST_F(CrostiniManagerRestartTest, MultiRestartAllowed) {
EXPECT_EQ(3, restart_crostini_callback_count_); EXPECT_EQ(3, restart_crostini_callback_count_);
} }
TEST_F(CrostiniManagerRestartTest, MountForTerminaPenguin) {
// DiskMountManager mock. Verify that correct values are received
// from concierge and passed to DiskMountManager.
disk_mount_manager_mock_ = new chromeos::disks::MockDiskMountManager;
chromeos::disks::DiskMountManager::InitializeForTesting(
disk_mount_manager_mock_);
disk_mount_manager_mock_->SetupDefaultReplies();
std::string known_hosts;
base::Base64Encode("[hostname]:2222 pubkey", &known_hosts);
std::string identity;
base::Base64Encode("privkey", &identity);
std::vector<std::string> mount_options = {
"UserKnownHostsBase64=" + known_hosts, "IdentityBase64=" + identity,
"Port=2222"};
EXPECT_CALL(*disk_mount_manager_mock_,
MountPath("sshfs://testing_profile@hostname:", "",
"crostini_test_termina_penguin", mount_options,
chromeos::MOUNT_TYPE_NETWORK_STORAGE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE))
.WillOnce(Invoke(
this,
&CrostiniManagerRestartTest_MountForTerminaPenguin_Test::SshfsMount));
// Use termina/penguin to perform mount.
restart_id_ = CrostiniManager::GetInstance()->RestartCrostini(
profile(), kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
base::Unretained(this), base::DoNothing::Once()));
run_loop()->Run();
EXPECT_TRUE(fake_concierge_client_->create_disk_image_called());
EXPECT_TRUE(fake_concierge_client_->start_termina_vm_called());
EXPECT_TRUE(fake_concierge_client_->start_container_called());
EXPECT_TRUE(fake_concierge_client_->get_container_ssh_keys_called());
EXPECT_EQ(1, restart_crostini_callback_count_);
base::FilePath path;
EXPECT_TRUE(
storage::ExternalMountPoints::GetSystemInstance()->GetRegisteredPath(
"crostini_test_termina_penguin", &path));
EXPECT_EQ(base::FilePath("/media/fuse/crostini_test_termina_penguin"), path);
chromeos::disks::DiskMountManager::Shutdown();
}
} // namespace crostini } // namespace crostini
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h" #include "chrome/browser/chromeos/crostini/crostini_package_installer_service.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/drive/file_system_util.h"
...@@ -66,7 +65,6 @@ ...@@ -66,7 +65,6 @@
#include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/app_window/app_window_registry.h"
#include "google_apis/drive/auth_service.h" #include "google_apis/drive/auth_service.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "storage/browser/fileapi/external_mount_points.h"
#include "storage/common/fileapi/file_system_types.h" #include "storage/common/fileapi/file_system_types.h"
#include "ui/base/webui/web_ui_util.h" #include "ui/base/webui/web_ui_util.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -671,92 +669,9 @@ void FileManagerPrivateMountCrostiniContainerFunction::RestartCallback( ...@@ -671,92 +669,9 @@ void FileManagerPrivateMountCrostiniContainerFunction::RestartCallback(
crostini::ConciergeClientResult result) { crostini::ConciergeClientResult result) {
if (result != crostini::ConciergeClientResult::SUCCESS) { if (result != crostini::ConciergeClientResult::SUCCESS) {
Respond(Error( Respond(Error(
base::StringPrintf("Error restarting crostini container: %d", result))); base::StringPrintf("Error mounting crostini container: %d", result)));
return; return;
} }
crostini::CrostiniManager::GetInstance()->GetContainerSshKeys(
kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
CryptohomeIdForProfile(Profile::FromBrowserContext(browser_context())),
base::BindOnce(
&FileManagerPrivateMountCrostiniContainerFunction::SshKeysCallback,
this));
}
void FileManagerPrivateMountCrostiniContainerFunction::SshKeysCallback(
crostini::ConciergeClientResult result,
const std::string& container_public_key,
const std::string& host_private_key,
const std::string& hostname) {
if (result != crostini::ConciergeClientResult::SUCCESS) {
Respond(Error(
base::StringPrintf("Error fetching crostini ssh keys: %d", result)));
return;
}
// Add an observer for OnMountEvent and keep this object alive to receive it.
chromeos::disks::DiskMountManager* manager =
chromeos::disks::DiskMountManager::GetInstance();
manager->AddObserver(this);
self_ = this;
// Call to sshfs to mount.
// Path = sshfs://<username>@<hostname>:
// Label = crostini_<cryptohome_id>_<vm_name>_<container_name>
Profile* profile = Profile::FromBrowserContext(browser_context());
std::string port = "2222";
source_path_ = base::StringPrintf(
"sshfs://%s@%s:", ContainerUserNameForProfile(profile).c_str(),
hostname.c_str());
mount_label_ = file_manager::util::GetCrostiniMountPointName(profile);
std::vector<std::string> mount_options;
std::string base64_known_hosts;
std::string base64_identity;
base::Base64Encode(host_private_key, &base64_identity);
base::Base64Encode(
base::StringPrintf("[%s]:%s %s", hostname.c_str(), port.c_str(),
container_public_key.c_str()),
&base64_known_hosts);
mount_options.push_back("UserKnownHostsBase64=" + base64_known_hosts);
mount_options.push_back("IdentityBase64=" + base64_identity);
mount_options.push_back("Port=" + port);
manager->MountPath(source_path_, "", mount_label_, mount_options,
chromeos::MOUNT_TYPE_NETWORK_STORAGE,
chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
}
void FileManagerPrivateMountCrostiniContainerFunction::OnMountEvent(
chromeos::disks::DiskMountManager::MountEvent event,
chromeos::MountError error_code,
const chromeos::disks::DiskMountManager::MountPointInfo& mount_info) {
// Ignore any other mount/unmount events.
if (event != chromeos::disks::DiskMountManager::MountEvent::MOUNTING ||
mount_info.source_path != source_path_) {
return;
}
// Remove observer and self ref.
chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this);
auto self = std::move(self_);
if (error_code != chromeos::MountError::MOUNT_ERROR_NONE) {
Respond(Error(base::StringPrintf(
"Error mounting crostini container: error_code=%d, "
"source_path=%s, mount_path=%s, mount_type=%d, mount_condition=%d",
error_code, mount_info.source_path.c_str(),
mount_info.mount_path.c_str(), mount_info.mount_type,
mount_info.mount_condition)));
return;
}
// Register filesystem and add volume to VolumeManager.
base::FilePath mount_path =
base::FilePath(FILE_PATH_LITERAL(mount_info.mount_path));
storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
mount_label_, storage::kFileSystemTypeNativeLocal,
storage::FileSystemMountOption(), mount_path);
file_manager::VolumeManager::Get(browser_context())
->AddSshfsCrostiniVolume(mount_path);
Respond(NoArguments()); Respond(NoArguments());
} }
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include "chrome/browser/extensions/chrome_extension_function.h" #include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h" #include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/common/extensions/api/file_manager_private.h" #include "chrome/common/extensions/api/file_manager_private.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "google_apis/drive/drive_api_error_codes.h" #include "google_apis/drive/drive_api_error_codes.h"
#include "storage/browser/fileapi/file_system_url.h" #include "storage/browser/fileapi/file_system_url.h"
...@@ -283,8 +282,7 @@ class FileManagerPrivateIsCrostiniEnabledFunction ...@@ -283,8 +282,7 @@ class FileManagerPrivateIsCrostiniEnabledFunction
// Implements the chrome.fileManagerPrivate.mountCrostiniContainer method. // Implements the chrome.fileManagerPrivate.mountCrostiniContainer method.
// Starts and mounts crostini container. // Starts and mounts crostini container.
class FileManagerPrivateMountCrostiniContainerFunction class FileManagerPrivateMountCrostiniContainerFunction
: public LoggedAsyncExtensionFunction, : public LoggedAsyncExtensionFunction {
public chromeos::disks::DiskMountManager::Observer {
public: public:
DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.mountCrostiniContainer", DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.mountCrostiniContainer",
FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER) FILEMANAGERPRIVATE_MOUNTCROSTINICONTAINER)
...@@ -295,22 +293,10 @@ class FileManagerPrivateMountCrostiniContainerFunction ...@@ -295,22 +293,10 @@ class FileManagerPrivateMountCrostiniContainerFunction
bool RunAsync() override; bool RunAsync() override;
void RestartCallback(crostini::ConciergeClientResult); void RestartCallback(crostini::ConciergeClientResult);
void SshKeysCallback(crostini::ConciergeClientResult,
const std::string& container_public_key,
const std::string& host_private_key,
const std::string& hostname);
// DiskMountManager::Observer
void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
chromeos::MountError error_code,
const chromeos::disks::DiskMountManager::MountPointInfo&
mount_info) override;
private: private:
std::string source_path_; std::string source_path_;
std::string mount_label_; std::string mount_label_;
// Self reference used to keep object alive to receive OnMountEvent.
scoped_refptr<FileManagerPrivateMountCrostiniContainerFunction> self_;
}; };
// Implements the chrome.fileManagerPrivate.installLinuxPackage method. // Implements the chrome.fileManagerPrivate.installLinuxPackage method.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/chromeos/file_manager/path_util.h" #include "chrome/browser/chromeos/file_manager/path_util.h"
#include "base/barrier_closure.h" #include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/sys_info.h" #include "base/sys_info.h"
#include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h" #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h"
...@@ -132,6 +133,25 @@ base::FilePath GetCrostiniMountDirectory(Profile* profile) { ...@@ -132,6 +133,25 @@ base::FilePath GetCrostiniMountDirectory(Profile* profile) {
return base::FilePath("/media/fuse/" + GetCrostiniMountPointName(profile)); return base::FilePath("/media/fuse/" + GetCrostiniMountPointName(profile));
} }
std::vector<std::string> GetCrostiniMountOptions(
const std::string& hostname,
const std::string& host_private_key,
const std::string& container_public_key) {
const std::string port = "2222";
std::vector<std::string> options;
std::string base64_known_hosts;
std::string base64_identity;
base::Base64Encode(host_private_key, &base64_identity);
base::Base64Encode(
base::StringPrintf("[%s]:%s %s", hostname.c_str(), port.c_str(),
container_public_key.c_str()),
&base64_known_hosts);
options.push_back("UserKnownHostsBase64=" + base64_known_hosts);
options.push_back("IdentityBase64=" + base64_identity);
options.push_back("Port=" + port);
return options;
}
std::string ConvertFileSystemURLToPathInsideCrostini( std::string ConvertFileSystemURLToPathInsideCrostini(
Profile* profile, Profile* profile,
const storage::FileSystemURL& file_system_url) { const storage::FileSystemURL& file_system_url) {
......
...@@ -52,6 +52,12 @@ std::string GetCrostiniMountPointName(Profile* profile); ...@@ -52,6 +52,12 @@ std::string GetCrostiniMountPointName(Profile* profile);
// The actual directory the crostini "Linux Files" folder is mounted. // The actual directory the crostini "Linux Files" folder is mounted.
base::FilePath GetCrostiniMountDirectory(Profile* profile); base::FilePath GetCrostiniMountDirectory(Profile* profile);
// The sshfs mount options for crostini "Linux Files" mount.
std::vector<std::string> GetCrostiniMountOptions(
const std::string& hostname,
const std::string& host_private_key,
const std::string& container_public_key);
// Convert a cracked url to a path inside the Crostini VM. // Convert a cracked url to a path inside the Crostini VM.
std::string ConvertFileSystemURLToPathInsideCrostini( std::string ConvertFileSystemURLToPathInsideCrostini(
Profile* profile, Profile* profile,
......
...@@ -161,7 +161,7 @@ bool CrostiniInstallerView::Accept() { ...@@ -161,7 +161,7 @@ bool CrostiniInstallerView::Accept() {
// Kick off the Crostini Restart sequence. We will be added as an observer. // Kick off the Crostini Restart sequence. We will be added as an observer.
restart_id_ = crostini::CrostiniManager::GetInstance()->RestartCrostini( restart_id_ = crostini::CrostiniManager::GetInstance()->RestartCrostini(
profile_, kCrostiniDefaultVmName, kCrostiniDefaultContainerName, profile_, kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
base::BindOnce(&CrostiniInstallerView::StartContainerFinished, base::BindOnce(&CrostiniInstallerView::MountContainerFinished,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
this); this);
return false; return false;
...@@ -253,6 +253,36 @@ void CrostiniInstallerView::OnVmStarted(ConciergeClientResult result) { ...@@ -253,6 +253,36 @@ void CrostiniInstallerView::OnVmStarted(ConciergeClientResult result) {
StepProgress(); StepProgress();
} }
void CrostiniInstallerView::OnContainerStarted(ConciergeClientResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
state_ = State::START_CONTAINER;
if (result != ConciergeClientResult::SUCCESS) {
LOG(ERROR) << "Failed to start container with error code: "
<< static_cast<int>(result);
HandleError(
l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR),
SetupResult::kErrorStartingContainer);
return;
}
VLOG(1) << "Started container successfully";
StepProgress();
}
void CrostiniInstallerView::OnSshKeysFetched(ConciergeClientResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
state_ = State::FETCH_SSH_KEYS;
if (result != ConciergeClientResult::SUCCESS) {
LOG(ERROR) << "Failed to fetch ssh keys with error code: "
<< static_cast<int>(result);
HandleError(
l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_ERROR),
SetupResult::kErrorFetchingSshKeys);
return;
}
VLOG(1) << "Fetched ssh keys successfully";
StepProgress();
}
// static // static
CrostiniInstallerView* CrostiniInstallerView::GetActiveViewForTesting() { CrostiniInstallerView* CrostiniInstallerView::GetActiveViewForTesting() {
return g_crostini_installer_view; return g_crostini_installer_view;
...@@ -375,16 +405,16 @@ void CrostiniInstallerView::HandleError(const base::string16& error_message, ...@@ -375,16 +405,16 @@ void CrostiniInstallerView::HandleError(const base::string16& error_message,
GetWidget()->GetRootView()->Layout(); GetWidget()->GetRootView()->Layout();
} }
void CrostiniInstallerView::StartContainerFinished( void CrostiniInstallerView::MountContainerFinished(
ConciergeClientResult result) { ConciergeClientResult result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
state_ = State::START_CONTAINER; state_ = State::MOUNT_CONTAINER;
if (result != ConciergeClientResult::SUCCESS) { if (result != ConciergeClientResult::SUCCESS) {
LOG(ERROR) << "Failed to start container with error code: " LOG(ERROR) << "Failed to mount container with error code: "
<< static_cast<int>(result); << static_cast<int>(result);
HandleError( HandleError(
l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_START_CONTAINER_ERROR), l10n_util::GetStringUTF16(IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_ERROR),
SetupResult::kErrorStartingContainer); SetupResult::kErrorMountingContainer);
return; return;
} }
StepProgress(); StepProgress();
...@@ -392,7 +422,7 @@ void CrostiniInstallerView::StartContainerFinished( ...@@ -392,7 +422,7 @@ void CrostiniInstallerView::StartContainerFinished(
} }
void CrostiniInstallerView::ShowLoginShell() { void CrostiniInstallerView::ShowLoginShell() {
DCHECK_EQ(state_, State::START_CONTAINER); DCHECK_EQ(state_, State::MOUNT_CONTAINER);
state_ = State::SHOW_LOGIN_SHELL; state_ = State::SHOW_LOGIN_SHELL;
crostini::CrostiniManager::GetInstance()->LaunchContainerTerminal( crostini::CrostiniManager::GetInstance()->LaunchContainerTerminal(
...@@ -432,6 +462,10 @@ void CrostiniInstallerView::SetMessageLabel() { ...@@ -432,6 +462,10 @@ void CrostiniInstallerView::SetMessageLabel() {
message_id = IDS_CROSTINI_INSTALLER_START_TERMINA_VM_MESSAGE; message_id = IDS_CROSTINI_INSTALLER_START_TERMINA_VM_MESSAGE;
} else if (state_ == State::START_TERMINA_VM) { } else if (state_ == State::START_TERMINA_VM) {
message_id = IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE; message_id = IDS_CROSTINI_INSTALLER_START_CONTAINER_MESSAGE;
} else if (state_ == State::START_CONTAINER) {
message_id = IDS_CROSTINI_INSTALLER_FETCH_SSH_KEYS_MESSAGE;
} else if (state_ == State::FETCH_SSH_KEYS) {
message_id = IDS_CROSTINI_INSTALLER_MOUNT_CONTAINER_MESSAGE;
} }
if (message_id != 0) { if (message_id != 0) {
message_label_->SetText(l10n_util::GetStringUTF16(message_id)); message_label_->SetText(l10n_util::GetStringUTF16(message_id));
......
...@@ -43,7 +43,9 @@ class CrostiniInstallerView ...@@ -43,7 +43,9 @@ class CrostiniInstallerView
kErrorCreatingDiskImage = 5, kErrorCreatingDiskImage = 5,
kErrorStartingTermina = 6, kErrorStartingTermina = 6,
kErrorStartingContainer = 7, kErrorStartingContainer = 7,
kErrorOffline = 8, kErrorFetchingSshKeys = 8,
kErrorMountingContainer = 9,
kErrorOffline = 10,
kCount kCount
}; };
...@@ -66,6 +68,8 @@ class CrostiniInstallerView ...@@ -66,6 +68,8 @@ class CrostiniInstallerView
void OnConciergeStarted(crostini::ConciergeClientResult result) override; void OnConciergeStarted(crostini::ConciergeClientResult result) override;
void OnDiskImageCreated(crostini::ConciergeClientResult result) override; void OnDiskImageCreated(crostini::ConciergeClientResult result) override;
void OnVmStarted(crostini::ConciergeClientResult result) override; void OnVmStarted(crostini::ConciergeClientResult result) override;
void OnContainerStarted(crostini::ConciergeClientResult result) override;
void OnSshKeysFetched(crostini::ConciergeClientResult result) override;
static CrostiniInstallerView* GetActiveViewForTesting(); static CrostiniInstallerView* GetActiveViewForTesting();
...@@ -80,6 +84,8 @@ class CrostiniInstallerView ...@@ -80,6 +84,8 @@ class CrostiniInstallerView
CREATE_DISK_IMAGE, // Creating the image for the Termina VM. CREATE_DISK_IMAGE, // Creating the image for the Termina VM.
START_TERMINA_VM, // Starting the Termina VM. START_TERMINA_VM, // Starting the Termina VM.
START_CONTAINER, // Starting the container inside the Termina VM. START_CONTAINER, // Starting the container inside the Termina VM.
FETCH_SSH_KEYS, // Fetch ssh keys from concierge.
MOUNT_CONTAINER, // Do sshfs mount of container.
SHOW_LOGIN_SHELL, // Showing a new crosh window. SHOW_LOGIN_SHELL, // Showing a new crosh window.
INSTALL_END = SHOW_LOGIN_SHELL, // Marker enum for last install state. INSTALL_END = SHOW_LOGIN_SHELL, // Marker enum for last install state.
}; };
...@@ -88,7 +94,7 @@ class CrostiniInstallerView ...@@ -88,7 +94,7 @@ class CrostiniInstallerView
~CrostiniInstallerView() override; ~CrostiniInstallerView() override;
void HandleError(const base::string16& error_message, SetupResult result); void HandleError(const base::string16& error_message, SetupResult result);
void StartContainerFinished(crostini::ConciergeClientResult result); void MountContainerFinished(crostini::ConciergeClientResult result);
void ShowLoginShell(); void ShowLoginShell();
void StepProgress(); void StepProgress();
void SetMessageLabel(); void SetMessageLabel();
......
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