| // 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 <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/task/sequenced_task_runner.h" |
| #include "chrome/browser/ash/file_manager/volume_manager_observer.h" |
| #include "chrome/browser/ash/guest_os/guest_id.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chromeos/ash/components/dbus/concierge/concierge_client.h" |
| #include "chromeos/ash/components/dbus/seneschal/seneschal_service.pb.h" |
| #include "chromeos/ash/components/drivefs/drivefs_host_observer.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, |
| public ash::ConciergeClient::VmObserver, |
| public file_manager::VolumeManagerObserver, |
| public drivefs::DriveFsHostObserver { |
| 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; |
| }; |
| |
| static GuestOsSharePath* GetForProfile(Profile* profile); |
| 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); |
| |
| // 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; |
| |
| // drivefs::DriveFsHostObserver |
| 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, ExperimentalAsh> 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::WeakPtrFactory<GuestOsSharePath> weak_ptr_factory_{this}; |
| }; // class |
| |
| } // namespace guest_os |
| |
| #endif // CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_SHARE_PATH_H_ |