File: guest_os_share_path.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (235 lines) | stat: -rw-r--r-- 9,565 bytes parent folder | download | duplicates (5)
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
// Copyright 2018 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_GUEST_OS_GUEST_OS_SHARE_PATH_H_
#define CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_SHARE_PATH_H_

#include <map>
#include <memory>
#include <set>
#include <variant>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/task/sequenced_task_runner.h"
#include "chrome/browser/ash/crostini/crostini_util.h"
#include "chrome/browser/ash/file_manager/volume_manager_observer.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "chrome/browser/ash/guest_os/guest_os_registry_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/ash/components/drivefs/drivefs_host.h"
#include "components/keyed_service/core/keyed_service.h"

namespace guest_os {

using SuccessCallback =
    base::OnceCallback<void(bool success, const std::string& failure_reason)>;

struct SharedPathInfo {
  explicit SharedPathInfo(std::unique_ptr<base::FilePathWatcher> watcher,
                          const std::string& vm_name);
  SharedPathInfo(SharedPathInfo&&);
  ~SharedPathInfo();

  std::unique_ptr<base::FilePathWatcher> watcher;
  std::set<std::string> vm_names;
};

// Handles sharing and unsharing paths from the Chrome OS host to guest VMs via
// seneschal.
class GuestOsSharePath : public KeyedService,
                         ash::ConciergeClient::VmObserver,
                         file_manager::VolumeManagerObserver,
                         drivefs::DriveFsHost::Observer {
 public:
  using SharePathCallback =
      base::OnceCallback<void(const base::FilePath&, bool, const std::string&)>;
  using SeneschalCallback =
      base::RepeatingCallback<void(const std::string& operation,
                                   const base::FilePath& cros_path,
                                   const base::FilePath& container_path,
                                   bool result,
                                   const std::string& failure_reason)>;
  class Observer {
   public:
    virtual void OnPersistedPathRegistered(const std::string& vm_name,
                                           const base::FilePath& path) = 0;
    virtual void OnUnshare(const std::string& vm_name,
                           const base::FilePath& path) = 0;
    virtual void OnGuestRegistered(const guest_os::GuestId& guest) = 0;
    virtual void OnGuestUnregistered(const guest_os::GuestId& guest) = 0;
  };

  // ConvertArgsToPathsToShare returns this.
  struct PathsToShare {
    PathsToShare();
    PathsToShare(PathsToShare&);
    ~PathsToShare();

    std::vector<base::FilePath> paths_to_share;
    std::vector<std::string> launch_args;
  };

  explicit GuestOsSharePath(Profile* profile);

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

  ~GuestOsSharePath() override;

  // KeyedService:
  // FilePathWatchers are removed in Shutdown to ensure they are all destroyed
  // before the service.
  void Shutdown() override;

  // Observer receives unshare events.
  void AddObserver(Observer* obs);
  void RemoveObserver(Observer* obs);

  // Convert launch args and return paths to share with the VM, and string args
  // to pass to the app being launched. On failure, returns an error string
  // instead.
  std::variant<PathsToShare, std::string> ConvertArgsToPathsToShare(
      const guest_os::GuestOsRegistryService::Registration& registration,
      const std::vector<guest_os::LaunchArg>& args,
      const base::FilePath& vm_mount,
      bool map_crostini_home);

  // Share specified absolute |path| with vm. If |persist| is set, the path will
  // be automatically shared at container startup. Callback receives path mapped
  // in container, success bool and failure reason string.
  void SharePath(const std::string& vm_name,
                 uint32_t seneschal_server_handle,
                 const base::FilePath& path,
                 SharePathCallback callback);

  // Share specified absolute |paths| with vm. If |persist| is set, the paths
  // will be automatically shared at container startup. Callback receives
  // success bool and failure reason string of the first error.
  void SharePaths(const std::string& vm_name,
                  uint32_t seneschal_server_handle,
                  std::vector<base::FilePath> paths,
                  SuccessCallback callback);

  // Unshare specified |path| with |vm_name|.  If |unpersist| is set, the path
  // is removed from prefs, and will not be shared at container startup.
  // Callback receives success bool and failure reason string.
  void UnsharePath(const std::string& vm_name,
                   const base::FilePath& path,
                   bool unpersist,
                   SuccessCallback callback);

  // Returns true the first time it is called on this service.
  bool GetAndSetFirstForSession(const std::string& vm_name);

  // Get list of all shared paths for the specified VM.
  std::vector<base::FilePath> GetPersistedSharedPaths(
      const std::string& vm_name);

  // Share all paths configured in prefs for the specified VM.
  // Called at container startup.  Callback is invoked once complete.
  void SharePersistedPaths(const std::string& vm_name,
                           uint32_t seneschal_server_handle,
                           SuccessCallback callback);

  // Save |paths| into prefs for |vm_name|.
  void RegisterPersistedPaths(const std::string& vm_name,
                              const std::vector<base::FilePath>& path);

  // Returns true if |path| or a parent is shared with |vm_name|.
  bool IsPathShared(const std::string& vm_name, base::FilePath path) const;

  // ash::ConciergeClient::VmObserver
  void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
  void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override;

  // file_manager::VolumeManagerObserver
  void OnVolumeMounted(ash::MountError error_code,
                       const file_manager::Volume& volume) override;
  void OnVolumeUnmounted(ash::MountError error_code,
                         const file_manager::Volume& volume) override;

  // DriveFsHost::Observer implementation.
  void OnFilesChanged(
      const std::vector<drivefs::mojom::FileChange>& changes) override;

  // Registers |path| as shared with |vm_name|.  Adds a FilePathWatcher to
  // detect when the path has been deleted.  If the path is deleted, we unshare
  // the path, and remove it from prefs if it was persisted.
  // Visible for testing.
  void RegisterSharedPath(const std::string& vm_name,
                          const base::FilePath& path);

  // Runs on UI Thread to handle when a path is deleted.
  // Visible for testing.
  void PathDeleted(const base::FilePath& path);

  // Registers `guest` with this service, so methods which take a VmType will
  // operate on it.
  void RegisterGuest(const GuestId& guest);

  // Unregisters `guest` so it no longer is included by methods taking a
  // `VmType`.
  void UnregisterGuest(const GuestId& guest);

  // Returns the list of guests which are currently registered with this
  // service.
  const base::flat_set<GuestId>& ListGuests();

  // Allow seneschal callback to be overridden for testing.
  void set_seneschal_callback_for_testing(SeneschalCallback callback) {
    seneschal_callback_ = std::move(callback);
  }

 private:
  void CallSeneschalSharePath(const std::string& vm_name,
                              uint32_t seneschal_server_handle,
                              const base::FilePath& path,
                              SharePathCallback callback);

  void CallSeneschalUnsharePath(const std::string& vm_name,
                                const base::FilePath& path,
                                SuccessCallback callback);

  void OnFileWatcherDeleted(const base::FilePath& path);

  void OnVolumeMountCheck(const base::FilePath& path, bool mount_exists);

  // Returns info for specified path or nullptr if not found.
  SharedPathInfo* FindSharedPathInfo(const base::FilePath& path);
  // Removes |vm_name| from |info.vm_names| if it exists, and deletes the
  // |info.watcher| if |info.path| is not shared with any other VMs.  Returns
  // true if path is no longer shared with any VMs.
  bool RemoveSharedPathInfo(SharedPathInfo& info, const std::string& vm_name);

  raw_ptr<Profile> profile_;
  // Task runner for FilePathWatchers to be created, run, and be destroyed on.
  scoped_refptr<base::SequencedTaskRunner> file_watcher_task_runner_;

  // List of VMs GetAndSetFirstForSession has been called on.
  std::set<std::string> first_for_session_;

  // Allow seneschal callback to be overridden for testing.
  SeneschalCallback seneschal_callback_;
  base::ObserverList<Observer>::Unchecked observers_;
  std::map<base::FilePath, SharedPathInfo> shared_paths_;
  base::flat_set<GuestId> guests_;

  base::ScopedObservation<file_manager::VolumeManager,
                          file_manager::VolumeManagerObserver>
      volume_manager_observer_{this};

  base::WeakPtrFactory<GuestOsSharePath> weak_ptr_factory_{this};
};  // class

}  // namespace guest_os

#endif  // CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_SHARE_PATH_H_