blob: 45fea60788f440bf0ac092b96e975f4d5d5cbc11 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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/callback.h"
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequenced_task_runner.h"
#include "chrome/browser/chromeos/crostini/crostini_manager.h"
#include "chrome/browser/chromeos/file_manager/volume_manager_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/components/drivefs/drivefs_host_observer.h"
#include "chromeos/dbus/seneschal/seneschal_service.pb.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 chromeos::VmShutdownObserver,
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 OnUnshare(const std::string& vm_name,
const base::FilePath& path) = 0;
};
static GuestOsSharePath* GetForProfile(Profile* profile);
explicit GuestOsSharePath(Profile* profile);
~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,
const base::FilePath& path,
bool persist,
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,
std::vector<base::FilePath> paths,
bool persist,
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();
// 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,
SuccessCallback callback);
// Save |path| into prefs for |vm_name|.
void RegisterPersistedPath(const std::string& vm_name,
const 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;
// chromeos::VmShutdownObserver
void OnVmShutdown(const std::string& vm_name) override;
// file_manager::VolumeManagerObserver
void OnVolumeMounted(chromeos::MountError error_code,
const file_manager::Volume& volume) override;
void OnVolumeUnmounted(chromeos::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);
// 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,
const base::FilePath& path,
bool persist,
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);
Profile* profile_;
// Task runner for FilePathWatchers to be created, run, and be destroyed on.
scoped_refptr<base::SequencedTaskRunner> file_watcher_task_runner_;
bool first_for_session_ = true;
// Allow seneschal callback to be overridden for testing.
SeneschalCallback seneschal_callback_;
base::ObserverList<Observer>::Unchecked observers_;
std::map<base::FilePath, SharedPathInfo> shared_paths_;
base::WeakPtrFactory<GuestOsSharePath> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(GuestOsSharePath);
}; // class
} // namespace guest_os
#endif // CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_SHARE_PATH_H_