Skip to content

Commit

Permalink
Implement IndexedDB migration in MoveMigrator
Browse files Browse the repository at this point in the history
Some extension data (such as data from 1st-party extensions
and System Web Apps, with AppIds specified in `kExtensionKeepList`)
is expected to stay in Ash even after the migration to Lacros.

This commit builds on top of the move migrator and adds
extra logic to keep the extension data stored in IndexedDB.

Test: unit_tests
Bug: 1261730
Change-Id: I5970bf6bd28ce42dedbb3bf1e0195829ec373148
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3509063
Reviewed-by: Yuta Hijikata <ythjkt@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Commit-Queue: Andrea Orru <andreaorru@chromium.org>
Cr-Commit-Position: refs/heads/main@{#983699}
  • Loading branch information
Andrea Orru authored and Chromium LUCI CQ committed Mar 22, 2022
1 parent 0322fea commit cacf6d3
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 2 deletions.
16 changes: 16 additions & 0 deletions chrome/browser/ash/crosapi/browser_data_migrator_util.cc
Expand Up @@ -138,6 +138,10 @@ absl::optional<uint64_t> g_extra_bytes_required_to_be_freed_for_testing;
constexpr char kMetaPrefix[] = "META:chrome-extension://";
constexpr char kKeyPrefix[] = "_chrome-extension://";

// IndexedDB extension suffixes.
constexpr char kIndexedDBBlobExtension[] = ".indexeddb.blob";
constexpr char kIndexedDBLevelDBExtension[] = ".indexeddb.leveldb";

} // namespace

CancelFlag::CancelFlag() : cancelled_(false) {}
Expand Down Expand Up @@ -571,6 +575,18 @@ leveldb::Status GetExtensionKeys(leveldb::DB* db,
return it->status();
}

IndexedDBPaths GetIndexedDBPaths(const base::FilePath& profile_path,
const char* extension_id) {
const base::FilePath indexed_db_dir = profile_path.Append(kIndexedDBFilePath);
const base::FilePath base_path = indexed_db_dir.Append(
"chrome_extension_" + std::string(extension_id) + "_0");

return {
base_path.AddExtension(kIndexedDBBlobExtension),
base_path.AddExtension(kIndexedDBLevelDBExtension),
};
}

bool MigrateLevelDB(const base::FilePath& original_path,
const base::FilePath& target_path,
const LevelDBType leveldb_type) {
Expand Down
14 changes: 14 additions & 0 deletions chrome/browser/ash/crosapi/browser_data_migrator_util.h
Expand Up @@ -208,6 +208,9 @@ constexpr const char* const kExtensionsAshOnly[] = {
// Extensions path.
constexpr char kExtensionsFilePath[] = "Extensions";

// IndexedDB path.
constexpr char kIndexedDBFilePath[] = "IndexedDB";

// `Local Storage` paths.
constexpr char kLocalStorageFilePath[] = "Local Storage";
constexpr char kLocalStorageLeveldbName[] = "leveldb";
Expand All @@ -228,6 +231,12 @@ enum class LevelDBType {
// Map from ExtensionID -> { leveldb keys..}.
using ExtensionKeys = std::map<std::string, std::vector<std::string>>;

// Structure containing both IndexedDB paths for an extension.
struct IndexedDBPaths {
base::FilePath blob_path;
base::FilePath leveldb_path;
};

constexpr char kTotalSize[] = "Ash.UserDataStatsRecorder.DataSize.TotalSize";

// UMA name prefix to record sizes of files/dirs in profile data directory. The
Expand Down Expand Up @@ -390,6 +399,11 @@ int64_t ComputeDirectorySizeWithoutLinks(const base::FilePath& dir_path);
// Record the total size of the user's profile data directory in MB.
void RecordTotalSize(int64_t size);

// Given an extension id, return the paths of the associated blob
// and leveldb directories inside IndexedDB.
IndexedDBPaths GetIndexedDBPaths(const base::FilePath& profile_path,
const char* extension_id);

// Migrate the LevelDB instance at `original_path` to `target_path`,
// Filter out all the extensions that are not in `kExtensionsAshOnly`.
// `leveldb_type` determines the schema type.
Expand Down
39 changes: 39 additions & 0 deletions chrome/browser/ash/crosapi/move_migrator.cc
Expand Up @@ -550,6 +550,45 @@ bool MoveMigrator::MoveSplitItemsToOriginalDir(
}
}

// Move IndexedDB objects related to extensions in the keeplist back to
// Ash's profile directory.
const base::FilePath lacros_indexed_db_dir =
tmp_profile_dir.Append(browser_data_migrator_util::kIndexedDBFilePath);
if (base::PathExists(lacros_indexed_db_dir)) {
const base::FilePath ash_indexed_db_dir = original_profile_dir.Append(
browser_data_migrator_util::kIndexedDBFilePath);
if (!base::CreateDirectory(ash_indexed_db_dir)) {
PLOG(ERROR) << "CreateDirectory() failed for "
<< ash_indexed_db_dir.value();
return false;
}

for (const char* extension_id :
browser_data_migrator_util::kExtensionKeepList) {
const auto& [blob_path, leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(tmp_profile_dir,
extension_id);
if (base::PathExists(blob_path)) {
const base::FilePath ash_blob_path =
ash_indexed_db_dir.Append(blob_path.BaseName());
if (!base::Move(blob_path, ash_blob_path)) {
PLOG(ERROR) << "Failed moving " << blob_path.value() << " to "
<< ash_blob_path.value();
return false;
}
}
if (base::PathExists(leveldb_path)) {
const base::FilePath ash_leveldb_path =
ash_indexed_db_dir.Append(leveldb_path.BaseName());
if (!base::Move(leveldb_path, ash_indexed_db_dir)) {
PLOG(ERROR) << "Failed moving " << leveldb_path.value() << " to "
<< ash_leveldb_path.value();
return false;
}
}
}
}

return true;
}

Expand Down
100 changes: 98 additions & 2 deletions chrome/browser/ash/crosapi/move_migrator_unittest.cc
Expand Up @@ -10,6 +10,7 @@

#include "base/bind.h"
#include "base/containers/contains.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
Expand Down Expand Up @@ -148,16 +149,52 @@ void SetUpExtensionState(const base::FilePath& profile_path) {
ASSERT_TRUE(status.ok());
}

void SetUpIndexedDB(const base::FilePath& profile_path,
bool ash = true,
bool lacros = true) {
if (lacros) {
const auto [move_extension_blob_path, move_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(profile_path,
kMoveExtensionId);
ASSERT_TRUE(base::CreateDirectory(move_extension_blob_path));
ASSERT_TRUE(base::CreateDirectory(move_extension_leveldb_path));
ASSERT_EQ(base::WriteFile(move_extension_blob_path.Append(kDataFilePath),
kDataContent, kDataSize),
kDataSize);
ASSERT_EQ(base::WriteFile(move_extension_leveldb_path.Append(kDataFilePath),
kDataContent, kDataSize),
kDataSize);
}

if (ash) {
const char* keep_extension_id =
browser_data_migrator_util::kExtensionKeepList[0];
const auto [keep_extension_blob_path, keep_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(profile_path,
keep_extension_id);
ASSERT_TRUE(base::CreateDirectory(keep_extension_blob_path));
ASSERT_TRUE(base::CreateDirectory(keep_extension_leveldb_path));
ASSERT_EQ(base::WriteFile(keep_extension_blob_path.Append(kDataFilePath),
kDataContent, kDataSize),
kDataSize);
ASSERT_EQ(base::WriteFile(keep_extension_leveldb_path.Append(kDataFilePath),
kDataContent, kDataSize),
kDataSize);
}
}

void SetUpProfileDirectory(const base::FilePath& path) {
// Setup `path` as below.
// |- Bookmarks/
// |- Cache/
// |- Cookies
// |- Downloads/
// |- Extensions/
// |- Extension State/
// |- Policy/
// |- Extensions/
// |- IndexedDB/
// |- Local Storage/
// |- Login Data/
// |- Policy/

ASSERT_TRUE(base::CreateDirectory(path.Append(kCacheFilePath)));
ASSERT_EQ(base::WriteFile(path.Append(kCacheFilePath).Append(kDataFilePath),
Expand Down Expand Up @@ -187,6 +224,7 @@ void SetUpProfileDirectory(const base::FilePath& path) {
SetUpExtensions(path);
SetUpLocalStorage(path);
SetUpExtensionState(path);
SetUpIndexedDB(path);
}

std::map<std::string, std::string> ReadLevelDB(const base::FilePath& path) {
Expand Down Expand Up @@ -322,6 +360,10 @@ TEST(MoveMigratorTest, MoveLacrosItemsToNewDir) {
EXPECT_FALSE(base::PathExists(original_profile_dir.Append(kCookiesFilePath)));
EXPECT_TRUE(base::PathExists(tmp_profile_dir.Append(kBookmarksFilePath)));
EXPECT_TRUE(base::PathExists(tmp_profile_dir.Append(kCookiesFilePath)));
EXPECT_TRUE(base::PathExists(
tmp_profile_dir.Append(browser_data_migrator_util::kExtensionsFilePath)));
EXPECT_TRUE(base::PathExists(
tmp_profile_dir.Append(browser_data_migrator_util::kIndexedDBFilePath)));
}

TEST(MoveMigratorTest, MoveLacrosItemsToNewDirFailIfNoWritePermForLacrosItem) {
Expand Down Expand Up @@ -443,13 +485,16 @@ class MoveMigratorMigrateTest : public ::testing::Test {
// migration.
// |- Downloads
// |- Extensions
// |- IndexedDB
// |- Local Storage
// |- Login Data
// |- Policy
// |- lacros/First Run
// |- lacros/Default/
// |- Bookmarks
// |- Cookies
// |- Extensions
// |- IndexedDB
// |- Local Storage
// |- Policy

Expand Down Expand Up @@ -513,6 +558,38 @@ class MoveMigratorMigrateTest : public ::testing::Test {
// Lacros contains all the keys.
auto lacros_local_storage = ReadLevelDB(lacros_local_storage_path);
EXPECT_EQ(5, lacros_local_storage.size());

// Ash contains only IndexedDB folders of extensions in keeplist.
{
const auto [keep_extension_blob_path, keep_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(
original_profile_dir_, keep_extension_id.c_str());
const auto [move_extension_blob_path, move_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(original_profile_dir_,
kMoveExtensionId);
EXPECT_TRUE(
base::PathExists(keep_extension_blob_path.Append(kDataFilePath)));
EXPECT_TRUE(
base::PathExists(keep_extension_leveldb_path.Append(kDataFilePath)));
EXPECT_FALSE(base::PathExists(move_extension_blob_path));
EXPECT_FALSE(base::PathExists(move_extension_leveldb_path));
}

// Lacros contains only IndexedDB folders of extensions not in keeplist.
{
const auto [keep_extension_blob_path, keep_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(
new_profile_dir, keep_extension_id.c_str());
const auto [move_extension_blob_path, move_extension_leveldb_path] =
browser_data_migrator_util::GetIndexedDBPaths(new_profile_dir,
kMoveExtensionId);
EXPECT_FALSE(base::PathExists(keep_extension_blob_path));
EXPECT_FALSE(base::PathExists(keep_extension_leveldb_path));
EXPECT_TRUE(
base::PathExists(move_extension_blob_path.Append(kDataFilePath)));
EXPECT_TRUE(
base::PathExists(move_extension_leveldb_path.Append(kDataFilePath)));
}
}

void TearDown() override { EXPECT_TRUE(scoped_temp_dir_.Delete()); }
Expand Down Expand Up @@ -555,6 +632,7 @@ TEST_F(MoveMigratorMigrateTest, MigrateResumeFromMoveLacrosItems) {
// |- move_migrator/Default/
// |- Bookmarks
// |- Extensions
// |- IndexedDB
// |- Local Storage
// |- Policy
// |- move_migrator_split/
Expand Down Expand Up @@ -587,6 +665,12 @@ TEST_F(MoveMigratorMigrateTest, MigrateResumeFromMoveLacrosItems) {
browser_data_migrator_util::kExtensionsFilePath),
tmp_profile_dir.Append(browser_data_migrator_util::kExtensionsFilePath)));

// IndexedDB has been moved to Lacros's tmp dir.
ASSERT_TRUE(base::Move(
original_profile_dir_.Append(
browser_data_migrator_util::kIndexedDBFilePath),
tmp_profile_dir.Append(browser_data_migrator_util::kIndexedDBFilePath)));

// Local Storage has been split.
ASSERT_TRUE(
base::Move(original_profile_dir_.Append(
Expand Down Expand Up @@ -618,6 +702,7 @@ TEST_F(MoveMigratorMigrateTest, MigrateResumeFromMoveSplitItems) {
// |- Bookmarks
// |- Cookies
// |- Extensions
// |- IndexedDB
// |- Local Storage
// |- Policy
// |- move_migrator_split/
Expand Down Expand Up @@ -652,6 +737,11 @@ TEST_F(MoveMigratorMigrateTest, MigrateResumeFromMoveSplitItems) {
original_profile_dir_.Append(
browser_data_migrator_util::kExtensionsFilePath),
tmp_profile_dir.Append(browser_data_migrator_util::kExtensionsFilePath)));
// Same for IndexedDB.
ASSERT_TRUE(base::Move(
original_profile_dir_.Append(
browser_data_migrator_util::kIndexedDBFilePath),
tmp_profile_dir.Append(browser_data_migrator_util::kIndexedDBFilePath)));

// Local Storage has been split, but not yet moved to Ash profile dir.
ASSERT_TRUE(
Expand Down Expand Up @@ -715,6 +805,12 @@ TEST_F(MoveMigratorMigrateTest, MigrateResumeFromMoveTmpDir) {
SetUpExtensions(tmp_profile_dir, /*ash=*/false, /*lacros=*/true);
SetUpExtensions(original_profile_dir_, /*ash=*/true, /*lacros=*/false);

// IndexedDB has been split, and Ash's version is in its final place.
ASSERT_TRUE(base::DeletePathRecursively(original_profile_dir_.Append(
browser_data_migrator_util::kIndexedDBFilePath)));
SetUpIndexedDB(tmp_profile_dir, /*ash=*/false, /*lacros=*/true);
SetUpIndexedDB(original_profile_dir_, /*ash=*/true, /*lacros=*/false);

// Local Storage has been split, and Ash's version is in its final place.
ASSERT_TRUE(
base::Move(original_profile_dir_.Append(
Expand Down

0 comments on commit cacf6d3

Please sign in to comment.