#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;
};
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;
};
struct PathsToShare {
PathsToShare();
PathsToShare(const 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;
void Shutdown() override;
void AddObserver(Observer* obs);
void RemoveObserver(Observer* obs);
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);
void SharePath(const std::string& vm_name,
uint32_t seneschal_server_handle,
const base::FilePath& path,
SharePathCallback callback);
void SharePaths(const std::string& vm_name,
uint32_t seneschal_server_handle,
std::vector<base::FilePath> paths,
SuccessCallback callback);
void UnsharePath(const std::string& vm_name,
const base::FilePath& path,
bool unpersist,
SuccessCallback callback);
bool GetAndSetFirstForSession(const std::string& vm_name);
std::vector<base::FilePath> GetPersistedSharedPaths(
const std::string& vm_name);
void SharePersistedPaths(const std::string& vm_name,
uint32_t seneschal_server_handle,
SuccessCallback callback);
void RegisterPersistedPaths(const std::string& vm_name,
const std::vector<base::FilePath>& path);
bool IsPathShared(const std::string& vm_name, base::FilePath path) const;
void OnVmStarted(const vm_tools::concierge::VmStartedSignal& signal) override;
void OnVmStopped(const vm_tools::concierge::VmStoppedSignal& signal) override;
void OnVolumeMounted(ash::MountError error_code,
const file_manager::Volume& volume) override;
void OnVolumeUnmounted(ash::MountError error_code,
const file_manager::Volume& volume) override;
void OnFilesChanged(
const std::vector<drivefs::mojom::FileChange>& changes) override;
void RegisterSharedPath(const std::string& vm_name,
const base::FilePath& path);
void PathDeleted(const base::FilePath& path);
void RegisterGuest(const GuestId& guest);
void UnregisterGuest(const GuestId& guest);
const base::flat_set<GuestId>& ListGuests();
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);
SharedPathInfo* FindSharedPathInfo(const base::FilePath& path);
bool RemoveSharedPathInfo(SharedPathInfo& info, const std::string& vm_name);
raw_ptr<Profile> profile_;
scoped_refptr<base::SequencedTaskRunner> file_watcher_task_runner_;
std::set<std::string> first_for_session_;
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};
};
}
#endif