Commit c3b15298 authored by Julian Watson's avatar Julian Watson Committed by Commit Bot

Crostini backup restore: Display failed space info in notification

Bug: 932339
Change-Id: Ib835835ac8e58262091232be7ba285c2901f3746
Cq-Depend: chromium:1630343,chromium:1630135
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1631157
Commit-Queue: Julian Watson <juwa@google.com>
Reviewed-by: default avatarJoel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#669104}
parent e9ec579c
...@@ -3713,6 +3713,9 @@ ...@@ -3713,6 +3713,9 @@
<message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to architecture mismatch."> <message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_ARCHITECTURE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to architecture mismatch.">
Cannot import container architecture type <ph name="ARCHITECTURE_CONTAINER">$1<ex>arm64</ex></ph> with this device which is <ph name="ARCHITECTURE_DEVICE">$2<ex>x86_64</ex></ph>. You can try restoring this container into a different device, or you can access the files inside this container image by opening in Files app. Cannot import container architecture type <ph name="ARCHITECTURE_CONTAINER">$1<ex>arm64</ex></ph> with this device which is <ph name="ARCHITECTURE_DEVICE">$2<ex>x86_64</ex></ph>. You can try restoring this container into a different device, or you can access the files inside this container image by opening in Files app.
</message> </message>
<message name="IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE" desc="Message displayed in the notification when import (restore) of the Linux container fails due to insufficient space.">
Cannot restore due to lack of storage space. Free up <ph name="SPACE_REQUIRED">$1<ex>10Gb</ex></ph> from the device and try again.
</message>
<!-- Time limit notification --> <!-- Time limit notification -->
<message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device."> <message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device.">
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/text/bytes_formatting.h"
namespace crostini { namespace crostini {
...@@ -324,6 +325,9 @@ void CrostiniExportImport::OnImportComplete( ...@@ -324,6 +325,9 @@ void CrostiniExportImport::OnImportComplete(
CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE: CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE:
enum_hist_result = ImportContainerResult::kFailedArchitecture; enum_hist_result = ImportContainerResult::kFailedArchitecture;
break; break;
case crostini::CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE:
enum_hist_result = ImportContainerResult::kFailedSpace;
break;
default: default:
enum_hist_result = ImportContainerResult::kFailed; enum_hist_result = ImportContainerResult::kFailed;
} }
...@@ -345,7 +349,9 @@ void CrostiniExportImport::OnImportContainerProgress( ...@@ -345,7 +349,9 @@ void CrostiniExportImport::OnImportContainerProgress(
int progress_percent, int progress_percent,
uint64_t progress_speed, uint64_t progress_speed,
const std::string& architecture_device, const std::string& architecture_device,
const std::string& architecture_container) { const std::string& architecture_container,
uint64_t available_space,
uint64_t minimum_required_space) {
ContainerId container_id(vm_name, container_name); ContainerId container_id(vm_name, container_name);
auto it = notifications_.find(container_id); auto it = notifications_.find(container_id);
DCHECK(it != notifications_.end()) DCHECK(it != notifications_.end())
...@@ -371,6 +377,12 @@ void CrostiniExportImport::OnImportContainerProgress( ...@@ -371,6 +377,12 @@ void CrostiniExportImport::OnImportContainerProgress(
base::ASCIIToUTF16(architecture_container), base::ASCIIToUTF16(architecture_container),
base::ASCIIToUTF16(architecture_device))); base::ASCIIToUTF16(architecture_device)));
break; break;
case ImportContainerProgressStatus::FAILURE_SPACE:
DCHECK_GE(minimum_required_space, available_space);
it->second->set_message_failed(l10n_util::GetStringFUTF16(
IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_FAILED_SPACE,
ui::FormatBytes(minimum_required_space - available_space)));
break;
default: default:
LOG(WARNING) << "Unknown Export progress status " << int(status); LOG(WARNING) << "Unknown Export progress status " << int(status);
} }
......
...@@ -45,7 +45,8 @@ enum class ImportContainerResult { ...@@ -45,7 +45,8 @@ enum class ImportContainerResult {
kFailedVmStopped = 2, kFailedVmStopped = 2,
kFailedVmStarted = 3, kFailedVmStarted = 3,
kFailedArchitecture = 4, kFailedArchitecture = 4,
kMaxValue = kFailedArchitecture, kFailedSpace = 5,
kMaxValue = kFailedSpace,
}; };
// CrostiniExportImport is a keyed profile service to manage exporting and // CrostiniExportImport is a keyed profile service to manage exporting and
...@@ -94,6 +95,7 @@ class CrostiniExportImport : public KeyedService, ...@@ -94,6 +95,7 @@ class CrostiniExportImport : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail); FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail);
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
TestImportFailArchitecture); TestImportFailArchitecture);
FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFailSpace);
// ui::SelectFileDialog::Listener implementation. // ui::SelectFileDialog::Listener implementation.
void FileSelected(const base::FilePath& path, void FileSelected(const base::FilePath& path,
...@@ -113,14 +115,15 @@ class CrostiniExportImport : public KeyedService, ...@@ -113,14 +115,15 @@ class CrostiniExportImport : public KeyedService,
uint64_t progress_speed) override; uint64_t progress_speed) override;
// crostini::ImportContainerProgressObserver implementation. // crostini::ImportContainerProgressObserver implementation.
void OnImportContainerProgress( void OnImportContainerProgress(const std::string& vm_name,
const std::string& vm_name, const std::string& container_name,
const std::string& container_name, crostini::ImportContainerProgressStatus status,
crostini::ImportContainerProgressStatus status, int progress_percent,
int progress_percent, uint64_t progress_speed,
uint64_t progress_speed, const std::string& architecture_device,
const std::string& architecture_device, const std::string& architecture_container,
const std::string& architecture_container) override; uint64_t available_space,
uint64_t minimum_required_space) override;
void ExportAfterSharing(const ContainerId& container_id, void ExportAfterSharing(const ContainerId& container_id,
const base::FilePath& filename, const base::FilePath& filename,
......
...@@ -21,6 +21,12 @@ ...@@ -21,6 +21,12 @@
namespace crostini { namespace crostini {
struct ImportProgressOptionalArguments {
int progress_percent{};
uint64_t available_space{};
uint64_t min_required_space{};
};
class CrostiniExportImportTest : public testing::Test { class CrostiniExportImportTest : public testing::Test {
public: public:
void SendExportProgress( void SendExportProgress(
...@@ -37,16 +43,17 @@ class CrostiniExportImportTest : public testing::Test { ...@@ -37,16 +43,17 @@ class CrostiniExportImportTest : public testing::Test {
void SendImportProgress( void SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status status, vm_tools::cicerone::ImportLxdContainerProgressSignal_Status status,
int progress_percent) { const ImportProgressOptionalArguments& arguments = {}) {
vm_tools::cicerone::ImportLxdContainerProgressSignal signal; vm_tools::cicerone::ImportLxdContainerProgressSignal signal;
signal.set_owner_id(CryptohomeIdForProfile(profile())); signal.set_owner_id(CryptohomeIdForProfile(profile()));
signal.set_vm_name(kCrostiniDefaultVmName); signal.set_vm_name(kCrostiniDefaultVmName);
signal.set_container_name(kCrostiniDefaultContainerName); signal.set_container_name(kCrostiniDefaultContainerName);
signal.set_status(status); signal.set_status(status);
signal.set_progress_percent(progress_percent); signal.set_progress_percent(arguments.progress_percent);
signal.set_progress_percent(progress_percent);
signal.set_architecture_device("arch_dev"); signal.set_architecture_device("arch_dev");
signal.set_architecture_container("arch_con"); signal.set_architecture_container("arch_con");
signal.set_available_space(arguments.available_space);
signal.set_min_required_space(arguments.min_required_space);
fake_cicerone_client_->NotifyImportLxdContainerProgress(signal); fake_cicerone_client_->NotifyImportLxdContainerProgress(signal);
} }
...@@ -184,7 +191,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) { ...@@ -184,7 +191,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress( SendImportProgress(
vm_tools::cicerone:: vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UPLOAD, ImportLxdContainerProgressSignal_Status_IMPORTING_UPLOAD,
20); {.progress_percent = 20});
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING); CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 10); EXPECT_EQ(notification->get_notification()->progress(), 10);
...@@ -193,7 +200,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) { ...@@ -193,7 +200,7 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress( SendImportProgress(
vm_tools::cicerone:: vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK, ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
20); {.progress_percent = 20});
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING); CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 60); EXPECT_EQ(notification->get_notification()->progress(), 60);
...@@ -203,14 +210,14 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) { ...@@ -203,14 +210,14 @@ TEST_F(CrostiniExportImportTest, TestImportSuccess) {
SendImportProgress( SendImportProgress(
vm_tools::cicerone:: vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK, ImportLxdContainerProgressSignal_Status_IMPORTING_UNPACK,
40); {.progress_percent = 40});
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::RUNNING); CrostiniExportImportNotification::Status::RUNNING);
EXPECT_EQ(notification->get_notification()->progress(), 60); EXPECT_EQ(notification->get_notification()->progress(), 60);
// Done. // Done.
SendImportProgress( SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE, 0); vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_DONE);
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::DONE); CrostiniExportImportNotification::Status::DONE);
} }
...@@ -224,7 +231,7 @@ TEST_F(CrostiniExportImportTest, TestImportFail) { ...@@ -224,7 +231,7 @@ TEST_F(CrostiniExportImportTest, TestImportFail) {
// Failed. // Failed.
SendImportProgress( SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED, 0); vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED);
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED); CrostiniExportImportNotification::Status::FAILED);
std::string msg("Restoring couldn't be completed due to an error"); std::string msg("Restoring couldn't be completed due to an error");
...@@ -242,8 +249,7 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) { ...@@ -242,8 +249,7 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) {
// Failed Architecture. // Failed Architecture.
SendImportProgress( SendImportProgress(
vm_tools::cicerone:: vm_tools::cicerone::
ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE, ImportLxdContainerProgressSignal_Status_FAILED_ARCHITECTURE);
0);
EXPECT_EQ(notification->get_status(), EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED); CrostiniExportImportNotification::Status::FAILED);
std::string msg( std::string msg(
...@@ -254,4 +260,28 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) { ...@@ -254,4 +260,28 @@ TEST_F(CrostiniExportImportTest, TestImportFailArchitecture) {
EXPECT_EQ(notification->get_notification()->message(), EXPECT_EQ(notification->get_notification()->message(),
base::UTF8ToUTF16(msg)); base::UTF8ToUTF16(msg));
} }
TEST_F(CrostiniExportImportTest, TestImportFailSpace) {
crostini_export_import()->FileSelected(
tarball_, 0, reinterpret_cast<void*>(ExportImportType::IMPORT));
run_loop_->RunUntilIdle();
CrostiniExportImportNotification* notification =
crostini_export_import()->GetNotificationForTesting(container_id_);
// Failed Space.
SendImportProgress(
vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_FAILED_SPACE,
{
.available_space = 20ul * 1'024 * 1'024 * 1'024, // 20Gb
.min_required_space = 35ul * 1'024 * 1'024 * 1'024 // 35Gb
});
EXPECT_EQ(notification->get_status(),
CrostiniExportImportNotification::Status::FAILED);
std::string msg =
"Cannot restore due to lack of storage space. Free up 15.0 GB from the "
"device and try again.";
EXPECT_EQ(notification->get_notification()->message(),
base::UTF8ToUTF16(msg));
}
} // namespace crostini } // namespace crostini
...@@ -2615,6 +2615,12 @@ void CrostiniManager::OnImportLxdContainerProgress( ...@@ -2615,6 +2615,12 @@ void CrostiniManager::OnImportLxdContainerProgress(
call_original_callback = true; call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE; result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE;
break; break;
case vm_tools::cicerone::ImportLxdContainerProgressSignal::FAILED_SPACE:
call_observers = true;
status = ImportContainerProgressStatus::FAILURE_SPACE;
call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_SPACE;
break;
default: default:
call_original_callback = true; call_original_callback = true;
result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED; result = CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED;
...@@ -2628,7 +2634,8 @@ void CrostiniManager::OnImportLxdContainerProgress( ...@@ -2628,7 +2634,8 @@ void CrostiniManager::OnImportLxdContainerProgress(
observer.OnImportContainerProgress( observer.OnImportContainerProgress(
signal.vm_name(), signal.container_name(), status, signal.vm_name(), signal.container_name(), status,
signal.progress_percent(), signal.progress_speed(), signal.progress_percent(), signal.progress_speed(),
signal.architecture_device(), signal.architecture_container()); signal.architecture_device(), signal.architecture_container(),
signal.available_space(), signal.min_required_space());
} }
} }
......
...@@ -72,6 +72,7 @@ enum class CrostiniResult { ...@@ -72,6 +72,7 @@ enum class CrostiniResult {
CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED, CONTAINER_EXPORT_IMPORT_FAILED_VM_STARTED,
CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE, CONTAINER_EXPORT_IMPORT_FAILED_ARCHITECTURE,
NOT_ALLOWED, NOT_ALLOWED,
CONTAINER_EXPORT_IMPORT_FAILED_SPACE,
}; };
enum class InstallLinuxPackageProgressStatus { enum class InstallLinuxPackageProgressStatus {
...@@ -102,6 +103,7 @@ enum class ImportContainerProgressStatus { ...@@ -102,6 +103,7 @@ enum class ImportContainerProgressStatus {
UPLOAD, UPLOAD,
UNPACK, UNPACK,
FAILURE_ARCHITECTURE, FAILURE_ARCHITECTURE,
FAILURE_SPACE,
}; };
struct VmInfo { struct VmInfo {
...@@ -199,7 +201,9 @@ class ImportContainerProgressObserver { ...@@ -199,7 +201,9 @@ class ImportContainerProgressObserver {
int progress_percent, int progress_percent,
uint64_t progress_speed, uint64_t progress_speed,
const std::string& architecture_device, const std::string& architecture_device,
const std::string& architecture_container) = 0; const std::string& architecture_container,
uint64_t available_space,
uint64_t minimum_required_space) = 0;
}; };
class InstallerViewStatusObserver : public base::CheckedObserver { class InstallerViewStatusObserver : public base::CheckedObserver {
......
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