Commit 63e4b8ce authored by Sam McNally's avatar Sam McNally Committed by Commit Bot

Migrate pinned files to DriveFS on first run with DriveFS enabled.

Bug: 877043
Change-Id: Iab18132a8c4750de0f7f96601f6232c41e3aaf54
Reviewed-on: https://chromium-review.googlesource.com/1194544Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Reviewed-by: default avatarStuart Langley <slangley@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Commit-Queue: Sam McNally <sammc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#588771}
parent e482f1c2
......@@ -18,6 +18,7 @@
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "chrome/browser/browser_process.h"
......@@ -178,6 +179,11 @@ FileError InitializeMetadata(
return FILE_ERROR_FAILED;
}
// When running with DriveFS and migrating pinned files, only
// |metadata_storage| is non-null and needs to be initialized.
if (!cache)
return FILE_ERROR_OK;
if (!cache->Initialize()) {
LOG(WARNING) << "Failed to initialize the cache.";
return FILE_ERROR_FAILED;
......@@ -220,6 +226,56 @@ void ResetCacheDone(base::OnceCallback<void(bool)> callback, FileError error) {
std::move(callback).Run(error == FILE_ERROR_OK);
}
base::FilePath GetFullPath(internal::ResourceMetadataStorage* metadata_storage,
const ResourceEntry& entry) {
std::vector<std::string> path_components;
ResourceEntry current_entry = entry;
constexpr int kPathComponentSanityLimit = 100;
for (int i = 0; i < kPathComponentSanityLimit; ++i) {
path_components.push_back(current_entry.base_name());
if (!current_entry.has_parent_local_id()) {
// Ignore anything not contained within the drive grand root.
return {};
}
if (current_entry.parent_local_id() == util::kDriveGrandRootLocalId) {
// Omit the DriveGrantRoot directory from the path; DriveFS paths are
// relative to the mount point.
break;
}
if (metadata_storage->GetEntry(current_entry.parent_local_id(),
&current_entry) != FILE_ERROR_OK) {
return {};
}
}
if (path_components.empty()) {
return {};
}
base::FilePath path("/");
for (auto it = path_components.crbegin(); it != path_components.crend();
++it) {
path = path.Append(*it);
}
return path;
}
std::vector<base::FilePath> GetPinnedFiles(
internal::ResourceMetadataStorage* metadata_storage) {
std::vector<base::FilePath> pinned_files;
for (auto it = metadata_storage->GetIterator(); !it->IsAtEnd();
it->Advance()) {
const auto& value = it->GetValue();
if (!value.has_file_specific_info() ||
!value.file_specific_info().cache_state().is_pinned()) {
continue;
}
auto path = GetFullPath(metadata_storage, value);
if (!path.empty()) {
pinned_files.push_back(std::move(path));
}
}
return pinned_files;
}
} // namespace
// Observes drive disable Preference's change.
......@@ -443,10 +499,19 @@ DriveIntegrationService::DriveIntegrationService(
if (preference_watcher_)
preference_watcher->set_integration_service(this);
bool migrated_to_drivefs =
profile_->GetPrefs()->GetBoolean(prefs::kDriveFsPinnedMigrated);
if (!drivefs_holder_ || !migrated_to_drivefs) {
metadata_storage_.reset(new internal::ResourceMetadataStorage(
cache_root_directory_.Append(kMetadataDirectory),
blocking_task_runner_.get()));
}
if (drivefs_holder_) {
delete test_drive_service;
delete test_file_system;
if (migrated_to_drivefs) {
state_ = INITIALIZED;
}
SetEnabled(drive::util::IsDriveEnabledForProfile(profile));
return;
}
......@@ -481,9 +546,6 @@ DriveIntegrationService::DriveIntegrationService(
scheduler_ = std::make_unique<JobScheduler>(
profile_->GetPrefs(), logger_.get(), drive_service_.get(),
blocking_task_runner_.get(), std::move(wake_lock_provider));
metadata_storage_.reset(new internal::ResourceMetadataStorage(
cache_root_directory_.Append(kMetadataDirectory),
blocking_task_runner_.get()));
cache_.reset(new internal::FileCache(
metadata_storage_.get(),
cache_root_directory_.Append(kCacheFileDirectory),
......@@ -748,6 +810,10 @@ void DriveIntegrationService::AddDriveMountPointAfterMounted() {
if (drivefs_holder_ && preference_watcher_) {
preference_watcher_->UpdateSyncPauseState();
}
if (drivefs_holder_ &&
!profile_->GetPrefs()->GetBoolean(prefs::kDriveFsPinnedMigrated)) {
MigratePinnedFiles();
}
}
void DriveIntegrationService::RemoveDriveMountPoint() {
......@@ -830,6 +896,17 @@ void DriveIntegrationService::InitializeAfterMetadataInitialized(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK_EQ(INITIALIZING, state_);
if (drivefs_holder_) {
if (error != FILE_ERROR_OK) {
profile_->GetPrefs()->SetBoolean(prefs::kDriveFsPinnedMigrated, true);
metadata_storage_.reset();
}
state_ = INITIALIZED;
if (enabled_)
AddDriveMountPoint();
return;
}
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile_);
drive_service_->Initialize(signin_manager->GetAuthenticatedAccountId());
......@@ -916,6 +993,29 @@ void DriveIntegrationService::Observe(
}
}
void DriveIntegrationService::MigratePinnedFiles() {
if (!metadata_storage_)
return;
base::PostTaskAndReplyWithResult(
blocking_task_runner_.get(), FROM_HERE,
base::BindOnce(&GetPinnedFiles, metadata_storage_.get()),
base::BindOnce(&DriveIntegrationService::PinFiles,
weak_ptr_factory_.GetWeakPtr()));
}
void DriveIntegrationService::PinFiles(
const std::vector<base::FilePath>& files_to_pin) {
if (!drivefs_holder_->drivefs_host()->IsMounted())
return;
for (const auto& path : files_to_pin) {
GetDriveFsInterface()->SetPinned(path, true, base::DoNothing());
}
profile_->GetPrefs()->SetBoolean(prefs::kDriveFsPinnedMigrated, true);
metadata_storage_.reset();
}
//===================== DriveIntegrationServiceFactory =======================
DriveIntegrationServiceFactory::FactoryCallback*
......
......@@ -213,6 +213,12 @@ class DriveIntegrationService : public KeyedService,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Migrate pinned files from the old Drive integration to DriveFS.
void MigratePinnedFiles();
// Pin all the files in |files_to_pin| with DriveFS.
void PinFiles(const std::vector<base::FilePath>& files_to_pin);
friend class DriveIntegrationServiceFactory;
Profile* profile_;
......
......@@ -735,4 +735,46 @@ IN_PROC_BROWSER_TEST_F(MultiProfileFilesAppBrowserTest, BasicDrive) {
StartTest();
}
// Test fixture class for testing migration to DriveFS.
class DriveFsFilesAppBrowserTest : public FileManagerBrowserTestBase {
public:
DriveFsFilesAppBrowserTest() = default;
protected:
GuestMode GetGuestMode() const override { return NOT_IN_GUEST_MODE; }
const char* GetTestCaseName() const override {
return test_case_name_.c_str();
}
std::string GetFullTestCaseName() const override { return test_case_name_; }
const char* GetTestExtensionManifestName() const override {
return "file_manager_test_manifest.json";
}
void set_test_case_name(const std::string& name) { test_case_name_ = name; }
bool GetEnableDriveFs() const override {
return !base::StringPiece(
::testing::UnitTest::GetInstance()->current_test_info()->name())
.starts_with("PRE");
}
private:
std::string test_case_name_;
DISALLOW_COPY_AND_ASSIGN(DriveFsFilesAppBrowserTest);
};
IN_PROC_BROWSER_TEST_F(DriveFsFilesAppBrowserTest, PRE_MigratePinnedFiles) {
set_test_case_name("PRE_driveMigratePinnedFile");
StartTest();
}
IN_PROC_BROWSER_TEST_F(DriveFsFilesAppBrowserTest, MigratePinnedFiles) {
set_test_case_name("driveMigratePinnedFile");
StartTest();
}
} // namespace file_manager
......@@ -353,12 +353,13 @@ class TestVolume {
bool CreateRootDirectory(const Profile* profile) {
if (root_initialized_)
return true;
root_initialized_ = root_.Set(profile->GetPath().Append(name_));
root_ = profile->GetPath().Append(name_);
root_initialized_ = base::CreateDirectory(root_);
return root_initialized_;
}
const std::string& name() const { return name_; }
const base::FilePath& root_path() const { return root_.GetPath(); }
const base::FilePath& root_path() const { return root_; }
static base::FilePath GetTestDataFilePath(const std::string& file_name) {
// Get the path to file manager's test data directory.
......@@ -374,7 +375,7 @@ class TestVolume {
}
private:
base::ScopedTempDir root_;
base::FilePath root_;
bool root_initialized_ = false;
std::string name_;
......
......@@ -318,6 +318,7 @@ void Preferences::RegisterProfilePrefs(
drive::prefs::kDisableDriveHostedFiles, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterStringPref(drive::prefs::kDriveFsProfileSalt, "");
registry->RegisterBooleanPref(drive::prefs::kDriveFsPinnedMigrated, false);
// We don't sync prefs::kLanguageCurrentInputMethod and PreviousInputMethod
// because they're just used to track the logout state of the device.
registry->RegisterStringPref(prefs::kLanguageCurrentInputMethod, "");
......
......@@ -126,7 +126,9 @@ void FakeDriveFs::SetMetadata(const base::FilePath& path,
stored_metadata.mime_type = mime_type;
stored_metadata.original_name = original_name;
stored_metadata.hosted = (original_name != path.BaseName().value());
stored_metadata.pinned = pinned;
if (pinned) {
stored_metadata.pinned = true;
}
}
void FakeDriveFs::Init(drivefs::mojom::DriveFsConfigurationPtr config,
......
......@@ -23,5 +23,8 @@ const char kDisableDriveHostedFiles[] = "gdata.hosted_files.disabled";
// when passed to drivefs.
const char kDriveFsProfileSalt[] = "drivefs.profile_salt";
// A boolean pref containing whether pinned files have been migrated to DriveFS.
const char kDriveFsPinnedMigrated[] = "drivefs.pinned_migrated";
} // namespace prefs
} // namespace drive
......@@ -14,6 +14,7 @@ extern const char kDisableDrive[];
extern const char kDisableDriveOverCellular[];
extern const char kDisableDriveHostedFiles[];
extern const char kDriveFsProfileSalt[];
extern const char kDriveFsPinnedMigrated[];
} // namespace prefs
} // namespace drive
......
......@@ -344,3 +344,75 @@ testcase.drivePressCtrlAFromSearch = function() {
];
StepsRunner.run(steps);
};
testcase.PRE_driveMigratePinnedFile = function() {
// Pin a file.
testPromise(
setupAndWaitUntilReady(null, RootPath.DRIVE).then(function(results) {
var windowId = results.windowId;
return remoteCall
.callRemoteTestUtil('selectFile', windowId, ['hello.txt'])
.then(function() {
return remoteCall.waitForElement(
windowId, ['.table-row[selected]']);
})
.then(function() {
return remoteCall.callRemoteTestUtil(
'fakeMouseRightClick', windowId, ['.table-row[selected]']);
})
.then(function(result) {
chrome.test.assertTrue(result);
return remoteCall.waitForElement(
windowId, '#file-context-menu:not([hidden])');
})
.then(function() {
return remoteCall.waitForElement(
windowId, ['[command="#toggle-pinned"]']);
})
.then(function() {
return remoteCall.callRemoteTestUtil(
'fakeMouseClick', windowId, ['[command="#toggle-pinned"]']);
})
.then(function(result) {
return remoteCall.waitForElement(
windowId, '#file-context-menu[hidden]');
})
.then(function() {
return remoteCall.callRemoteTestUtil(
'fakeEvent', windowId, ['#file-list', 'contextmenu']);
})
.then(function(result) {
chrome.test.assertTrue(result);
return remoteCall.waitForElement(
windowId, '[command="#toggle-pinned"][checked]');
});
}));
};
testcase.driveMigratePinnedFile = function() {
// After enabling DriveFS, ensure the file is still pinned.
testPromise(
setupAndWaitUntilReady(null, RootPath.DRIVE).then(function(results) {
var windowId = results.windowId;
return remoteCall
.callRemoteTestUtil('selectFile', windowId, ['hello.txt'])
.then(function() {
return remoteCall.waitForElement(
windowId, ['.table-row[selected]']);
})
.then(function() {
return remoteCall.callRemoteTestUtil(
'fakeMouseRightClick', windowId, ['.table-row[selected]']);
})
.then(function(result) {
chrome.test.assertTrue(result);
return remoteCall.waitForElement(
windowId, '#file-context-menu:not([hidden])');
})
.then(function() {
return remoteCall.waitForElement(
windowId, '[command="#toggle-pinned"][checked]');
});
}));
};
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