1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// 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/ref_counted.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.
// TODO(b/353475473): Extract code shared with DriveUploadObserver, if possible.
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_
|