File: crostini_export_import.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (315 lines) | stat: -rw-r--r-- 13,189 bytes parent folder | download | duplicates (6)
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// Copyright 2019 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_CROSTINI_CROSTINI_EXPORT_IMPORT_H_
#define CHROME_BROWSER_ASH_CROSTINI_CROSTINI_EXPORT_IMPORT_H_

#include <map>
#include <memory>
#include <string>
#include <unordered_map>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ash/crostini/crostini_export_import_notification_controller.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_simple_types.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "chrome/browser/ash/guest_os/guest_os_share_path.h"
#include "components/keyed_service/core/keyed_service.h"
#include "ui/shell_dialogs/select_file_dialog.h"

class Profile;

namespace content {
class WebContents;
}

namespace crostini {

enum class ExportContainerResult;
enum class ImportContainerResult;

enum class ExportImportType {
  EXPORT,
  IMPORT,
  EXPORT_DISK_IMAGE,
  IMPORT_DISK_IMAGE
};

// ExportContainerResult is used for UMA, if you update this make sure to update
// CrostiniExportContainerResult in enums.xml
enum class ExportContainerResult {
  kSuccess = 0,
  kFailed = 1,
  kFailedVmStopped = 2,
  kFailedVmStarted = 3,
  kMaxValue = kFailedVmStarted,
};

// ImportContainerResult is used for UMA, if you update this make sure to update
// CrostiniImportContainerResult in enums.xml
enum class ImportContainerResult {
  kSuccess = 0,
  kFailed = 1,
  kFailedVmStopped = 2,
  kFailedVmStarted = 3,
  kFailedArchitecture = 4,
  kFailedSpace = 5,
  kMaxValue = kFailedSpace,
};

// CrostiniExportImport is a keyed profile service to manage exporting and
// importing containers with crostini.  It manages a file dialog for selecting
// files and a notification to show the progress of export/import.
//
// TODO(crbug.com/41441501): Ensure we have enough free space before doing
// backup or restore.
class CrostiniExportImport : public KeyedService,
                             public ui::SelectFileDialog::Listener,
                             public crostini::ExportContainerProgressObserver,
                             public crostini::ImportContainerProgressObserver,
                             public crostini::DiskImageProgressObserver {
 public:
  class Observer : public base::CheckedObserver {
   public:
    // Called immediately before operation begins with |in_progress|=true, and
    // again immediately after the operation completes with |in_progress|=false.
    virtual void OnCrostiniExportImportOperationStatusChanged(
        bool in_progress) = 0;
  };

  using OnceTrackerFactory = base::OnceCallback<std::unique_ptr<
      CrostiniExportImportStatusTracker>(ExportImportType, base::FilePath)>;

  struct OperationData {
    OperationData(ExportImportType type,
                  guest_os::GuestId id,
                  OnceTrackerFactory factory);
    ~OperationData();

    ExportImportType type;
    guest_os::GuestId container_id;
    OnceTrackerFactory tracker_factory;
  };

  explicit CrostiniExportImport(Profile* profile);

  CrostiniExportImport(const CrostiniExportImport&) = delete;
  CrostiniExportImport& operator=(const CrostiniExportImport&) = delete;

  ~CrostiniExportImport() override;

  void AddObserver(Observer* observer) { observers_.AddObserver(observer); }

  void RemoveObserver(Observer* observer) {
    observers_.RemoveObserver(observer);
  }

  // KeyedService:
  void Shutdown() override;

  // Export the |container_id| showing FileDialog.
  void ExportContainer(guest_os::GuestId container_id,
                       content::WebContents* web_contents);
  // Import the |container_id| showing FileDialog.
  void ImportContainer(guest_os::GuestId container_id,
                       content::WebContents* web_contents);

  // Export |container_id| to |path| and invoke |callback| when complete.
  void ExportContainer(guest_os::GuestId container_id,
                       base::FilePath path,
                       CrostiniManager::CrostiniResultCallback callback);

  // Import |container_id| from |path| and invoke |callback| when complete.
  void ImportContainer(guest_os::GuestId container_id,
                       base::FilePath path,
                       CrostiniManager::CrostiniResultCallback callback);

  // Create a new container with |container_id| from |path| and invoke
  // |callback| when complete.
  void CreateContainerFromImport(
      guest_os::GuestId container_id,
      base::FilePath path,
      CrostiniManager::CrostiniResultCallback callback);

  // Export |container_id| showing FileDialog, and using |tracker_factory| for
  // status tracking.
  void ExportContainer(guest_os::GuestId container_id,
                       content::WebContents* web_contents,
                       OnceTrackerFactory tracker_factory);
  // Import |container_id| showing FileDialog, and using |tracker_factory| for
  // status tracking.
  void ImportContainer(guest_os::GuestId container_id,
                       content::WebContents* web_contents,
                       OnceTrackerFactory tracker_factory);

  // Export |container| to |path| and invoke |tracker_factory| to create a
  // tracker for this operation.
  void ExportContainer(guest_os::GuestId container_id,
                       base::FilePath path,
                       OnceTrackerFactory tracker_factory);
  // Import |container| from |path| and invoke |tracker_factory| to create a
  // tracker for this operation.
  void ImportContainer(guest_os::GuestId container_id,
                       base::FilePath path,
                       OnceTrackerFactory tracker_factory);

  // Cancel currently running export/import.
  void CancelOperation(ExportImportType type, guest_os::GuestId id);

  // Whether an export or import is currently in progress.
  bool GetExportImportOperationStatus() const;

  // Returns the default location to export the container to.
  base::FilePath GetDefaultBackupPath() const;

  base::WeakPtr<CrostiniExportImportNotificationController>
  GetNotificationControllerForTesting(guest_os::GuestId container_id);

 private:
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestDeprecatedExportSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestExportCustomVmContainerSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportFail);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportCancelled);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestExportDoneBeforeCancelled);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestImportCustomVmContainerSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFail);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportCancelled);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestImportDoneBeforeCancelled);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestImportFailArchitecture);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportFailSpace);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestExportDiskImageSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestExportDiskImageFail);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestExportDiskImageCancelled);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestImportDiskImageSuccess);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest, TestImportDiskImageFail);
  FRIEND_TEST_ALL_PREFIXES(CrostiniExportImportTest,
                           TestImportDiskImageCancelled);

  void FillOperationData(ExportImportType type,
                         guest_os::GuestId id,
                         OnceTrackerFactory cb);
  void FillOperationData(ExportImportType type, guest_os::GuestId id);
  void FillOperationData(ExportImportType type);

  // ui::SelectFileDialog::Listener implementation.
  void FileSelected(const ui::SelectedFileInfo& file, int index) override;
  void FileSelectionCanceled() override;

  void Start(base::FilePath path,
             bool create_new_container,
             CrostiniManager::CrostiniResultCallback callback);

  // Restart VM with LXD if required and share the file path with VM.
  void EnsureLxdStartedThenSharePath(
      const guest_os::GuestId& container_id,
      const base::FilePath& path,
      bool persist,
      bool create_new_container,
      guest_os::GuestOsSharePath::SharePathCallback callback);

  // Share the file path with VM after VM has been restarted.
  void SharePath(const std::string& vm_name,
                 const base::FilePath& path,
                 guest_os::GuestOsSharePath::SharePathCallback callback,
                 crostini::CrostiniResult result);

  // crostini::ExportContainerProgressObserver implementation.
  void OnExportContainerProgress(const guest_os::GuestId& container_id,
                                 const StreamingExportStatus& status) override;

  // crostini::DiskImageProgressObserver implementation.
  void OnDiskImageProgress(const guest_os::GuestId& container_id,
                           DiskImageProgressStatus status,
                           int progress) override;

  // crostini::ImportContainerProgressObserver implementation.
  void OnImportContainerProgress(const guest_os::GuestId& container_id,
                                 crostini::ImportContainerProgressStatus status,
                                 int progress_percent,
                                 uint64_t progress_speed,
                                 const std::string& architecture_device,
                                 const std::string& architecture_container,
                                 uint64_t available_space,
                                 uint64_t minimum_required_space) override;

  void ExportDiskImage(const guest_os::GuestId& container_id,
                       const base::FilePath& path,
                       CrostiniManager::CrostiniResultCallback callback,
                       CrostiniResult result);

  void ImportDiskImage(const guest_os::GuestId& container_id,
                       const base::FilePath& path,
                       CrostiniManager::CrostiniResultCallback callback,
                       CrostiniResult result);

  void AfterDiskImageOperation(const guest_os::GuestId& container_id,
                               CrostiniManager::CrostiniResultCallback callback,
                               CrostiniResult result);

  void ExportAfterSharing(const guest_os::GuestId& container_id,
                          const base::FilePath& path,
                          CrostiniManager::CrostiniResultCallback callback,
                          const base::FilePath& container_path,
                          bool result,
                          const std::string& failure_reason);
  void OnExportComplete(const base::Time& start,
                        const guest_os::GuestId& container_id,
                        CrostiniManager::CrostiniResultCallback callback,
                        CrostiniResult result,
                        uint64_t container_size,
                        uint64_t compressed_size);

  void ImportAfterSharing(const guest_os::GuestId& container_id,
                          const base::FilePath& path,
                          CrostiniManager::CrostiniResultCallback callback,
                          const base::FilePath& container_path,
                          bool result,
                          const std::string& failure_reason);
  void OnImportComplete(const base::Time& start,
                        const guest_os::GuestId& container_id,
                        CrostiniManager::CrostiniResultCallback callback,
                        CrostiniResult result);

  void OpenFileDialog(content::WebContents* web_contents);

  std::string GetUniqueNotificationId();

  using TrackerMap =
      std::map<guest_os::GuestId,
               std::unique_ptr<CrostiniExportImportStatusTracker>>;

  std::unique_ptr<CrostiniExportImportStatusTracker> RemoveTracker(
      TrackerMap::iterator it);

  raw_ptr<Profile> profile_;
  scoped_refptr<ui::SelectFileDialog> select_folder_dialog_;
  TrackerMap status_trackers_;
  std::unique_ptr<OperationData> operation_data_;
  // Trackers must have unique-per-profile identifiers.
  // A non-static member on a profile-keyed-service will suffice.
  int next_status_tracker_id_ = 0;
  base::ObserverList<Observer> observers_;
  // weak_ptr_factory_ should always be last member.
  base::WeakPtrFactory<CrostiniExportImport> weak_ptr_factory_{this};
};

}  // namespace crostini

#endif  // CHROME_BROWSER_ASH_CROSTINI_CROSTINI_EXPORT_IMPORT_H_