blob: 1815ec691f866e3a3f979ac47cd18368cf1d2fae [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ASH_POLICY_SKYVAULT_DRIVE_SKYVAULT_UPLOADER_H_
#define CHROME_BROWSER_ASH_POLICY_SKYVAULT_DRIVE_SKYVAULT_UPLOADER_H_
#include <optional>
#include <string>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/ash/drive/drive_integration_service.h"
#include "chrome/browser/ash/drive/file_system_util.h"
#include "chrome/browser/ash/file_manager/io_task_controller.h"
#include "chrome/browser/ash/policy/skyvault/policy_utils.h"
#include "chromeos/ash/components/drivefs/drivefs_host.h"
#include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
#include "storage/browser/file_system/file_system_context.h"
#include "storage/browser/file_system/file_system_url.h"
class Profile;
namespace policy::local_user_files {
// Manages the "upload to Drive" workflow as part of the SkyVault files
// migration. Starts with moving the file to the cloud. Gets upload status by
// observing move and Drive events. Calls the UploadCallback with once the
// upload is completed, passing the error if any occurred.
class DriveSkyvaultUploader
: public file_manager::io_task::IOTaskController::Observer,
drivefs::DriveFsHost::Observer,
drive::DriveIntegrationService::Observer {
public:
// Called when the upload finishes. Parameters:
// error: The upload error, if any.
// upload_root_path: Path to the upload root, or empty on early failure.
using UploadCallback =
base::OnceCallback<void(std::optional<MigrationUploadError>,
base::FilePath)>;
DriveSkyvaultUploader(Profile* profile,
const base::FilePath& file_path,
const base::FilePath& relative_source_path,
const std::string& upload_root,
UploadCallback callback);
~DriveSkyvaultUploader() override;
// Starts the upload workflow:
// - Copy the file via an IO task.
// - Sync to Drive.
// - Remove the source file in case of a move operation. Move mode of the
// `CopyOrMoveIOTask` is not used because the source file should only be
// deleted at the end of the sync operation.
void Run();
// Cancels the upload, if possible.
void Cancel();
DriveSkyvaultUploader(const DriveSkyvaultUploader&) = delete;
DriveSkyvaultUploader& operator=(const DriveSkyvaultUploader&) = delete;
void SetFailDeleteForTesting(bool fail);
private:
// Starts the IOTask to upload the file to Google Drive to
// `destination_folder_path`, if it was created successfully and fails the
// operation otherwise.
void CreateCopyIOTask(const base::FilePath& destination_folder_path,
bool created);
// Called when copy to Drive completes. Cleans up files if needed, or
// completes the operation immediately. Saves `error` so it's not overridden
// if delete fails.
void OnEndCopy(std::optional<MigrationUploadError> error = std::nullopt);
// Called after unrecoverable error or when all tasks complete successfully.
// Invokes the upload callback, passing the error if any occurred.
void OnEndUpload();
// Callback for when ImmediatelyUpload() is called on DriveFS.
void ImmediatelyUploadDone(drive::FileError error);
// Directs IO task status updates to |OnCopyStatus| or |OnDeleteStatus| based
// on task id.
void OnIOTaskStatus(
const file_manager::io_task::ProgressStatus& status) override;
// Observes copy to Drive IO task status updates. Calls `OnEndCopy` upon any
// error.
void OnCopyStatus(const file_manager::io_task::ProgressStatus& status);
// Observes delete IO task status updates from the delete task for cleaning up
// the source file. Calls `OnEndUpload` once the delete is finished.
void OnDeleteStatus(const file_manager::io_task::ProgressStatus& status);
// Translates the status error into a MigrationUploadError.
void ProcessCopyError(const file_manager::io_task::ProgressStatus& status);
// DriveFsHost::Observer implementation.
void OnUnmounted() override;
void OnSyncingStatusUpdate(
const drivefs::mojom::SyncingStatus& status) override;
void OnError(const drivefs::mojom::DriveError& error) override;
// DriveIntegrationService::Observer implementation.
void OnDriveConnectionStatusChanged(
drive::util::ConnectionStatus status) override;
// Called when waiting for connection times out.
void OnReconnectionTimeout();
// Test-only: Simulates a delete failure if true. Actual result of the
// DeleteIO task is ignored.
bool fail_delete_for_testing_ = false;
const raw_ptr<Profile> profile_;
scoped_refptr<storage::FileSystemContext> file_system_context_;
const raw_ptr<drive::DriveIntegrationService> drive_integration_service_;
// Upload details:
// Source file URL
const storage::FileSystemURL source_url_;
// Part of the source path relative to MyFiles
const base::FilePath relative_source_path_;
// The name of the device-unique upload root folder on Drive
const std::string upload_root_;
// Absolute path to the device's upload root folder on Drive. This is
// populated when the upload is about to start.
base::FilePath upload_root_path_;
// Invoked on completion
UploadCallback callback_;
// Tracks upload progress:
std::optional<file_manager::io_task::IOTaskId> observed_copy_task_id_ =
std::nullopt;
std::optional<file_manager::io_task::IOTaskId> observed_delete_task_id_ =
std::nullopt;
base::FilePath observed_absolute_dest_path_;
base::FilePath observed_relative_drive_path_;
// Whether `EndCopy()` was called.
bool copy_ended_ = false;
// Set to `true` if upload is explicitly cancelled by owner. Forces every step
// to exit early.
bool cancelled_ = false;
// Indicates whether there was no connection on starting the task.
bool waiting_for_connection_ = false;
// Time at which we started waiting for connection. Used for UMA.
std::optional<base::Time> connection_wait_start_time_;
// Ensures that we don't wait for connection indefinitely
base::OneShotTimer reconnection_timer_;
// Stores the first encountered error, if any.
std::optional<MigrationUploadError> error_;
raw_ptr<file_manager::io_task::IOTaskController> io_task_controller_ =
nullptr;
base::ScopedObservation<file_manager::io_task::IOTaskController,
file_manager::io_task::IOTaskController::Observer>
io_task_controller_observer_{this};
base::WeakPtrFactory<DriveSkyvaultUploader> weak_ptr_factory_{this};
};
} // namespace policy::local_user_files
#endif // CHROME_BROWSER_ASH_POLICY_SKYVAULT_DRIVE_SKYVAULT_UPLOADER_H_