Commit 643971b5 authored by Risan's avatar Risan Committed by Commit Bot

Split Removable Media Watchers to be one per media

Currently, Removable Media is watched at the top-level directory under
/media/removable. Unfortunately, this only works if the removable media
was attached before the inotify is attached (since inotify does not
detect mount event).

This changes listen to the mount events from cros-disks through
ArcVolumeManager (to synchronize with Android volume mounting) and
create a FilePathWatcher per removable media.

BUG=b:150883493
TEST=Mount invisible removable media, the media changes are indexed.
TEST=Reboot DUT with non-visible removable media attached, still indexed.
TEST=Change the removable media to be visible, still indexed.
TEST=Reboot DUT with visible media attached, still indexed
TEST=Change the removable media to be invisible, still indexed.

Change-Id: Ia02012676681e025431d74f2c3f9b951a77ca783
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2362376
Auto-Submit: Risan <risan@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Commit-Queue: Risan <risan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806716}
parent 57c82338
...@@ -7,12 +7,10 @@ ...@@ -7,12 +7,10 @@
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <map>
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_enumerator.h" #include "base/files/file_enumerator.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_path_watcher.h" #include "base/files/file_path_watcher.h"
...@@ -122,8 +120,25 @@ TimestampMap BuildTimestampMap(base::FilePath cros_dir, ...@@ -122,8 +120,25 @@ TimestampMap BuildTimestampMap(base::FilePath cros_dir,
// Skip non-media files for efficiency. // Skip non-media files for efficiency.
if (!HasAndroidSupportedMediaExtension(cros_path)) if (!HasAndroidSupportedMediaExtension(cros_path))
continue; continue;
base::FilePath android_path =
GetAndroidPath(cros_path, cros_dir, android_dir); // TODO(b/163951541): Temporary hack, this will be changed when we change
// the path to UUID. The cros_dir for removable media is now changed to
// /media/removable/volume_name instead of just /media/removable.
// Meanwhile, the GetAndroidPath function accept the second parameter
// cros_dir as a way to identify if it is a removable media directory.
// Since the second parameter is only used for identification,
// and the identification happens through equality check with
// kCrosRemovableMediaDir string, it is safe to just pass
// kCrosRemovableMediaDir string directly when we know it is a removable
// media. In other word, the cros_removable_media_dir below is used as
// the ChromeOS analogue for the Android /storage directory.
base::FilePath cros_removable_media_dir =
base::FilePath(kCrosRemovableMediaDir);
base::FilePath android_path = GetAndroidPath(
cros_path,
cros_removable_media_dir.IsParent(cros_dir) ? cros_removable_media_dir
: cros_dir,
android_dir);
const base::FileEnumerator::FileInfo& info = enumerator.GetInfo(); const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
timestamp_map[android_path] = info.GetLastModifiedTime(); timestamp_map[android_path] = info.GetLastModifiedTime();
} }
...@@ -151,13 +166,19 @@ class ArcFileSystemWatcherServiceFactory ...@@ -151,13 +166,19 @@ class ArcFileSystemWatcherServiceFactory
// Factory name used by ArcBrowserContextKeyedServiceFactoryBase. // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
static constexpr const char* kName = "ArcFileSystemWatcherServiceFactory"; static constexpr const char* kName = "ArcFileSystemWatcherServiceFactory";
ArcFileSystemWatcherServiceFactory()
: ArcBrowserContextKeyedServiceFactoryBase<
ArcFileSystemWatcherService,
ArcFileSystemWatcherServiceFactory>() {
DependsOn(ArcVolumeMounterBridge::GetFactory());
}
static ArcFileSystemWatcherServiceFactory* GetInstance() { static ArcFileSystemWatcherServiceFactory* GetInstance() {
return base::Singleton<ArcFileSystemWatcherServiceFactory>::get(); return base::Singleton<ArcFileSystemWatcherServiceFactory>::get();
} }
private: private:
friend base::DefaultSingletonTraits<ArcFileSystemWatcherServiceFactory>; friend base::DefaultSingletonTraits<ArcFileSystemWatcherServiceFactory>;
ArcFileSystemWatcherServiceFactory() = default;
~ArcFileSystemWatcherServiceFactory() override = default; ~ArcFileSystemWatcherServiceFactory() override = default;
}; };
...@@ -169,8 +190,7 @@ class ArcFileSystemWatcherService::FileSystemWatcher { ...@@ -169,8 +190,7 @@ class ArcFileSystemWatcherService::FileSystemWatcher {
public: public:
using Callback = base::Callback<void(const std::vector<std::string>& paths)>; using Callback = base::Callback<void(const std::vector<std::string>& paths)>;
FileSystemWatcher(content::BrowserContext* context, FileSystemWatcher(const Callback& callback,
const Callback& callback,
const base::FilePath& cros_dir, const base::FilePath& cros_dir,
const base::FilePath& android_dir); const base::FilePath& android_dir);
~FileSystemWatcher(); ~FileSystemWatcher();
...@@ -213,7 +233,6 @@ class ArcFileSystemWatcherService::FileSystemWatcher { ...@@ -213,7 +233,6 @@ class ArcFileSystemWatcherService::FileSystemWatcher {
}; };
ArcFileSystemWatcherService::FileSystemWatcher::FileSystemWatcher( ArcFileSystemWatcherService::FileSystemWatcher::FileSystemWatcher(
content::BrowserContext* context,
const Callback& callback, const Callback& callback,
const base::FilePath& cros_dir, const base::FilePath& cros_dir,
const base::FilePath& android_dir) const base::FilePath& android_dir)
...@@ -312,15 +331,16 @@ ArcFileSystemWatcherService::ArcFileSystemWatcherService( ...@@ -312,15 +331,16 @@ ArcFileSystemWatcherService::ArcFileSystemWatcherService(
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) { base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
arc_bridge_service_->file_system()->AddObserver(this); arc_bridge_service_->file_system()->AddObserver(this);
ArcVolumeMounterBridge::GetForBrowserContext(context_)->Initialize(this);
} }
ArcFileSystemWatcherService::~ArcFileSystemWatcherService() { ArcFileSystemWatcherService::~ArcFileSystemWatcherService() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
StopWatchingFileSystem(); StopWatchingFileSystem(base::DoNothing());
DCHECK(removable_media_watchers_.empty());
DCHECK(!downloads_watcher_); DCHECK(!downloads_watcher_);
DCHECK(!myfiles_watcher_); DCHECK(!myfiles_watcher_);
DCHECK(!removable_media_watcher_);
arc_bridge_service_->file_system()->RemoveObserver(this); arc_bridge_service_->file_system()->RemoveObserver(this);
} }
...@@ -332,12 +352,25 @@ void ArcFileSystemWatcherService::OnConnectionReady() { ...@@ -332,12 +352,25 @@ void ArcFileSystemWatcherService::OnConnectionReady() {
void ArcFileSystemWatcherService::OnConnectionClosed() { void ArcFileSystemWatcherService::OnConnectionClosed() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
StopWatchingFileSystem(); StopWatchingFileSystem(base::DoNothing());
} }
void ArcFileSystemWatcherService::StartWatchingFileSystem() { void ArcFileSystemWatcherService::StartWatchingFileSystem() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
StopWatchingFileSystem();
// Triggered SendAllMountEvents as reply to make sure that callback is
// triggered after StopWatchingFileSystem() is triggered in the
// file_task_runner. Without this synchronization, the
// StopWatchingFileSystem() might race with
// ArcVolumeMounter::RequestAllMountPoints. If RequestAllMountPoints is
// triggered before StopWatchingFileSystem, then the watcher for existing
// removable media will be accidentally removed, even though the removable
// media is still attached. This can happen if there is an attached removable
// media during startup.
StopWatchingFileSystem(
base::BindOnce(&ArcFileSystemWatcherService::TriggerSendAllMountEvents,
weak_ptr_factory_.GetWeakPtr()));
Profile* profile = Profile::FromBrowserContext(context_); Profile* profile = Profile::FromBrowserContext(context_);
DCHECK(!downloads_watcher_); DCHECK(!downloads_watcher_);
...@@ -345,42 +378,47 @@ void ArcFileSystemWatcherService::StartWatchingFileSystem() { ...@@ -345,42 +378,47 @@ void ArcFileSystemWatcherService::StartWatchingFileSystem() {
DownloadPrefs(profile) DownloadPrefs(profile)
.GetDefaultDownloadDirectoryForProfile() .GetDefaultDownloadDirectoryForProfile()
.StripTrailingSeparators(), .StripTrailingSeparators(),
base::FilePath(kAndroidDownloadDir)); base::FilePath(kAndroidDownloadDir), base::DoNothing());
DCHECK(!myfiles_watcher_); DCHECK(!myfiles_watcher_);
myfiles_watcher_ = CreateAndStartFileSystemWatcher( myfiles_watcher_ = CreateAndStartFileSystemWatcher(
file_manager::util::GetMyFilesFolderForProfile(profile), file_manager::util::GetMyFilesFolderForProfile(profile),
base::FilePath(kAndroidMyFilesDir)); base::FilePath(kAndroidMyFilesDir), base::DoNothing());
DCHECK(!removable_media_watcher_);
removable_media_watcher_ = CreateAndStartFileSystemWatcher(
base::FilePath(kCrosRemovableMediaDir),
base::FilePath(kAndroidRemovableMediaDir));
} }
void ArcFileSystemWatcherService::StopWatchingFileSystem() { void ArcFileSystemWatcherService::StopWatchingFileSystem(
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (auto& watcher : removable_media_watchers_) {
file_task_runner_->DeleteSoon(FROM_HERE, watcher.second.release());
}
removable_media_watchers_.clear();
if (downloads_watcher_) if (downloads_watcher_)
file_task_runner_->DeleteSoon(FROM_HERE, downloads_watcher_.release()); file_task_runner_->DeleteSoon(FROM_HERE, downloads_watcher_.release());
if (myfiles_watcher_) // Trigger the callback at the end of the StopWatchingFileSystem. This is
file_task_runner_->DeleteSoon(FROM_HERE, myfiles_watcher_.release()); // equivalent with DeleteSoon with a callback.
if (removable_media_watcher_) file_task_runner_->PostTaskAndReply(
file_task_runner_->DeleteSoon(FROM_HERE, FROM_HERE,
removable_media_watcher_.release()); base::BindOnce([](std::unique_ptr<FileSystemWatcher> watcher) {},
base::Passed(&myfiles_watcher_)),
std::move(callback));
} }
std::unique_ptr<ArcFileSystemWatcherService::FileSystemWatcher> std::unique_ptr<ArcFileSystemWatcherService::FileSystemWatcher>
ArcFileSystemWatcherService::CreateAndStartFileSystemWatcher( ArcFileSystemWatcherService::CreateAndStartFileSystemWatcher(
const base::FilePath& cros_path, const base::FilePath& cros_path,
const base::FilePath& android_path) { const base::FilePath& android_path,
base::OnceClosure callback) {
auto watcher = std::make_unique<FileSystemWatcher>( auto watcher = std::make_unique<FileSystemWatcher>(
context_,
base::BindRepeating(&ArcFileSystemWatcherService::OnFileSystemChanged, base::BindRepeating(&ArcFileSystemWatcherService::OnFileSystemChanged,
weak_ptr_factory_.GetWeakPtr()), weak_ptr_factory_.GetWeakPtr()),
cros_path, android_path); cros_path, android_path);
file_task_runner_->PostTask(FROM_HERE,
base::BindOnce(&FileSystemWatcher::Start, file_task_runner_->PostTaskAndReply(
base::Unretained(watcher.get()))); FROM_HERE,
base::BindOnce(&FileSystemWatcher::Start,
base::Unretained(watcher.get())),
std::move(callback));
return watcher; return watcher;
} }
...@@ -397,7 +435,7 @@ void ArcFileSystemWatcherService::OnFileSystemChanged( ...@@ -397,7 +435,7 @@ void ArcFileSystemWatcherService::OnFileSystemChanged(
for (const std::string& path : paths) { for (const std::string& path : paths) {
if (base::StartsWith(path, kAndroidMyFilesDownloadsDir, if (base::StartsWith(path, kAndroidMyFilesDownloadsDir,
base::CompareCase::SENSITIVE)) { base::CompareCase::SENSITIVE)) {
// Exclude files under /storage/MyFiles/Downloads/ because they are also // Exclude files under .../MyFiles/Downloads/ because they are also
// indexed as files under /storage/emulated/0/Download/ // indexed as files under /storage/emulated/0/Download/
continue; continue;
} }
...@@ -407,4 +445,38 @@ void ArcFileSystemWatcherService::OnFileSystemChanged( ...@@ -407,4 +445,38 @@ void ArcFileSystemWatcherService::OnFileSystemChanged(
instance->RequestMediaScan(filtered_paths); instance->RequestMediaScan(filtered_paths);
} }
void ArcFileSystemWatcherService::StartWatchingRemovableMedia(
const std::string& fs_uuid,
const std::string& mount_path,
base::OnceClosure callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Make sure the callback is triggered after the file system is attached in
// file_task_runner.
// TODO(b/163951541): Temporary hack, this will be changed when we change the
// path to UUID. The kAndroidRemovableMediaDir is hardcoded here because
// CreateAndStartFileSystemWatcher accepts the removable media's volume's
// directory's parent in Android as second argument (i.e., /storage).
removable_media_watchers_[fs_uuid] = CreateAndStartFileSystemWatcher(
base::FilePath(mount_path), base::FilePath(kAndroidRemovableMediaDir),
std::move(callback));
}
void ArcFileSystemWatcherService::StopWatchingRemovableMedia(
const std::string& fs_uuid) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!removable_media_watchers_.count(fs_uuid)) {
LOG(ERROR) << "Unmounting non-existing volume with UUID: " << fs_uuid;
return;
}
file_task_runner_->DeleteSoon(FROM_HERE,
removable_media_watchers_[fs_uuid].release());
removable_media_watchers_.erase(fs_uuid);
}
void ArcFileSystemWatcherService::TriggerSendAllMountEvents() const {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ArcVolumeMounterBridge::GetForBrowserContext(context_)->SendAllMountEvents();
}
} // namespace arc } // namespace arc
...@@ -5,15 +5,18 @@ ...@@ -5,15 +5,18 @@
#ifndef CHROME_BROWSER_CHROMEOS_ARC_FILE_SYSTEM_WATCHER_ARC_FILE_SYSTEM_WATCHER_SERVICE_H_ #ifndef CHROME_BROWSER_CHROMEOS_ARC_FILE_SYSTEM_WATCHER_ARC_FILE_SYSTEM_WATCHER_SERVICE_H_
#define CHROME_BROWSER_CHROMEOS_ARC_FILE_SYSTEM_WATCHER_ARC_FILE_SYSTEM_WATCHER_SERVICE_H_ #define CHROME_BROWSER_CHROMEOS_ARC_FILE_SYSTEM_WATCHER_ARC_FILE_SYSTEM_WATCHER_SERVICE_H_
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "components/arc/mojom/file_system.mojom-forward.h" #include "components/arc/mojom/file_system.mojom-forward.h"
#include "components/arc/session/connection_observer.h" #include "components/arc/session/connection_observer.h"
#include "components/arc/volume_mounter/arc_volume_mounter_bridge.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
namespace base { namespace base {
...@@ -33,7 +36,8 @@ class ArcBridgeService; ...@@ -33,7 +36,8 @@ class ArcBridgeService;
// Android MediaProvider. // Android MediaProvider.
class ArcFileSystemWatcherService class ArcFileSystemWatcherService
: public KeyedService, : public KeyedService,
public ConnectionObserver<mojom::FileSystemInstance> { public ConnectionObserver<mojom::FileSystemInstance>,
public ArcVolumeMounterBridge::Delegate {
public: public:
// Returns singleton instance for the given BrowserContext, // Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC. // or nullptr if the browser |context| is not allowed to use ARC.
...@@ -49,15 +53,25 @@ class ArcFileSystemWatcherService ...@@ -49,15 +53,25 @@ class ArcFileSystemWatcherService
void OnConnectionReady() override; void OnConnectionReady() override;
void OnConnectionClosed() override; void OnConnectionClosed() override;
// ArcVolumeMounterBridge::Delegate overrides.
void StartWatchingRemovableMedia(const std::string& fs_uuid,
const std::string& mount_path,
base::OnceClosure callback) override;
void StopWatchingRemovableMedia(const std::string& fs_uuid) override;
private: private:
class FileSystemWatcher; class FileSystemWatcher;
void StartWatchingFileSystem(); void StartWatchingFileSystem();
void StopWatchingFileSystem(); void StopWatchingFileSystem(base::OnceClosure);
void TriggerSendAllMountEvents() const;
std::unique_ptr<FileSystemWatcher> CreateAndStartFileSystemWatcher( std::unique_ptr<FileSystemWatcher> CreateAndStartFileSystemWatcher(
const base::FilePath& cros_path, const base::FilePath& cros_path,
const base::FilePath& android_path); const base::FilePath& android_path,
base::OnceClosure callback);
void OnFileSystemChanged(const std::vector<std::string>& paths); void OnFileSystemChanged(const std::vector<std::string>& paths);
content::BrowserContext* const context_; content::BrowserContext* const context_;
...@@ -65,7 +79,9 @@ class ArcFileSystemWatcherService ...@@ -65,7 +79,9 @@ class ArcFileSystemWatcherService
std::unique_ptr<FileSystemWatcher> downloads_watcher_; std::unique_ptr<FileSystemWatcher> downloads_watcher_;
std::unique_ptr<FileSystemWatcher> myfiles_watcher_; std::unique_ptr<FileSystemWatcher> myfiles_watcher_;
std::unique_ptr<FileSystemWatcher> removable_media_watcher_; // A map from UUID to watcher.
std::map<std::string, std::unique_ptr<FileSystemWatcher>>
removable_media_watchers_;
scoped_refptr<base::SequencedTaskRunner> file_task_runner_; scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
......
...@@ -118,6 +118,7 @@ static_library("arc") { ...@@ -118,6 +118,7 @@ static_library("arc") {
"//components/exo", "//components/exo",
"//components/google/core/common", "//components/google/core/common",
"//components/guest_os", "//components/guest_os",
"//components/keyed_service/core",
"//components/onc", "//components/onc",
"//components/prefs", "//components/prefs",
......
...@@ -70,9 +70,15 @@ ArcVolumeMounterBridge* ArcVolumeMounterBridge::GetForBrowserContextForTesting( ...@@ -70,9 +70,15 @@ ArcVolumeMounterBridge* ArcVolumeMounterBridge::GetForBrowserContextForTesting(
return ArcVolumeMounterBridgeFactory::GetForBrowserContextForTesting(context); return ArcVolumeMounterBridgeFactory::GetForBrowserContextForTesting(context);
} }
// static
KeyedServiceBaseFactory* ArcVolumeMounterBridge::GetFactory() {
return ArcVolumeMounterBridgeFactory::GetInstance();
}
ArcVolumeMounterBridge::ArcVolumeMounterBridge(content::BrowserContext* context, ArcVolumeMounterBridge::ArcVolumeMounterBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service) ArcBridgeService* bridge_service)
: arc_bridge_service_(bridge_service), : delegate_(nullptr),
arc_bridge_service_(bridge_service),
pref_service_(user_prefs::UserPrefs::Get(context)) { pref_service_(user_prefs::UserPrefs::Get(context)) {
DCHECK(pref_service_); DCHECK(pref_service_);
arc_bridge_service_->volume_mounter()->AddObserver(this); arc_bridge_service_->volume_mounter()->AddObserver(this);
...@@ -95,6 +101,11 @@ ArcVolumeMounterBridge::~ArcVolumeMounterBridge() { ...@@ -95,6 +101,11 @@ ArcVolumeMounterBridge::~ArcVolumeMounterBridge() {
arc_bridge_service_->volume_mounter()->RemoveObserver(this); arc_bridge_service_->volume_mounter()->RemoveObserver(this);
} }
void ArcVolumeMounterBridge::Initialize(Delegate* delegate) {
delegate_ = delegate;
DCHECK(delegate_);
}
// Sends MountEvents of all existing MountPoints in cros-disks. // Sends MountEvents of all existing MountPoints in cros-disks.
void ArcVolumeMounterBridge::SendAllMountEvents() { void ArcVolumeMounterBridge::SendAllMountEvents() {
SendMountEventForMyFiles(); SendMountEventForMyFiles();
...@@ -150,19 +161,12 @@ void ArcVolumeMounterBridge::OnVisibleStoragesChanged() { ...@@ -150,19 +161,12 @@ void ArcVolumeMounterBridge::OnVisibleStoragesChanged() {
} }
} }
void ArcVolumeMounterBridge::OnConnectionReady() {
// Deferring the SendAllMountEvents as a task to current thread to not
// block the mojo request since SendAllMountEvents might take non trivial
// amount of time.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&ArcVolumeMounterBridge::SendAllMountEvents,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcVolumeMounterBridge::OnMountEvent( void ArcVolumeMounterBridge::OnMountEvent(
DiskMountManager::MountEvent event, DiskMountManager::MountEvent event,
chromeos::MountError error_code, chromeos::MountError error_code,
const DiskMountManager::MountPointInfo& mount_info) { const DiskMountManager::MountPointInfo& mount_info) {
DCHECK(delegate_);
// ArcVolumeMounter is limited for local storage, as Android's StorageManager // ArcVolumeMounter is limited for local storage, as Android's StorageManager
// volume concept relies on assumption that it is local filesystem. Hence, // volume concept relies on assumption that it is local filesystem. Hence,
// special volumes like DriveFS should not come through this path. // special volumes like DriveFS should not come through this path.
...@@ -199,17 +203,35 @@ void ArcVolumeMounterBridge::OnMountEvent( ...@@ -199,17 +203,35 @@ void ArcVolumeMounterBridge::OnMountEvent(
<< " is null during MountEvent " << event; << " is null during MountEvent " << event;
} }
mojom::VolumeMounterInstance* volume_mounter_instance =
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->volume_mounter(),
OnMountEvent);
if (!volume_mounter_instance)
return;
const bool visible = IsVisibleToAndroidApps(fs_uuid); const bool visible = IsVisibleToAndroidApps(fs_uuid);
volume_mounter_instance->OnMountEvent(mojom::MountPointInfo::New( switch (event) {
event, mount_info.source_path, mount_info.mount_path, fs_uuid, case DiskMountManager::MountEvent::MOUNTING:
device_label, device_type, visible)); // Attach watcher to the directories. This is the best place to add the
// watcher, because if the watcher is attached after Android mounts (and
// performs full scan) the removable media, there might be a small time
// interval that has undetectable changes.
delegate_->StartWatchingRemovableMedia(
fs_uuid, mount_info.mount_path,
base::BindOnce(
&ArcVolumeMounterBridge::SendMountEventForRemovableMedia,
weak_ptr_factory_.GetWeakPtr(), event, mount_info.source_path,
mount_info.mount_path, fs_uuid, device_label, device_type,
visible));
break;
case DiskMountManager::MountEvent::UNMOUNTING:
// The actual ordering for the unmount event is not very important because
// during unmount, we don't care about accidentally ignoring changes.
// Hence, no synchronization is needed as we only care about cleaning up
// memory usage for watchers which is ok to be done at any time as long as
// it is done.
SendMountEventForRemovableMedia(event, mount_info.source_path,
mount_info.mount_path, fs_uuid,
device_label, device_type, visible);
delegate_->StopWatchingRemovableMedia(fs_uuid);
break;
}
if (event == DiskMountManager::MountEvent::MOUNTING && if (event == DiskMountManager::MountEvent::MOUNTING &&
(device_type == chromeos::DeviceType::DEVICE_TYPE_USB || (device_type == chromeos::DeviceType::DEVICE_TYPE_USB ||
device_type == chromeos::DeviceType::DEVICE_TYPE_SD)) { device_type == chromeos::DeviceType::DEVICE_TYPE_SD)) {
...@@ -220,6 +242,25 @@ void ArcVolumeMounterBridge::OnMountEvent( ...@@ -220,6 +242,25 @@ void ArcVolumeMounterBridge::OnMountEvent(
} }
} }
void ArcVolumeMounterBridge::SendMountEventForRemovableMedia(
DiskMountManager::MountEvent event,
const std::string& source_path,
const std::string& mount_path,
const std::string& fs_uuid,
const std::string& device_label,
chromeos::DeviceType device_type,
bool visible) {
mojom::VolumeMounterInstance* volume_mounter_instance =
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->volume_mounter(),
OnMountEvent);
if (!volume_mounter_instance)
return;
volume_mounter_instance->OnMountEvent(
mojom::MountPointInfo::New(event, source_path, mount_path, fs_uuid,
device_label, device_type, visible));
}
void ArcVolumeMounterBridge::RequestAllMountPoints() { void ArcVolumeMounterBridge::RequestAllMountPoints() {
// Deferring the SendAllMountEvents as a task to current thread to not // Deferring the SendAllMountEvents as a task to current thread to not
// block the mojo request since SendAllMountEvents might take non trivial // block the mojo request since SendAllMountEvents might take non trivial
......
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
#include <string> #include <string>
#include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chromeos/disks/disk_mount_manager.h" #include "chromeos/disks/disk_mount_manager.h"
#include "components/arc/mojom/volume_mounter.mojom.h" #include "components/arc/mojom/volume_mounter.mojom.h"
#include "components/arc/session/connection_observer.h" #include "components/arc/session/connection_observer.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/keyed_service/core/keyed_service_base_factory.h"
#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_change_registrar.h"
namespace content { namespace content {
...@@ -31,6 +33,21 @@ class ArcVolumeMounterBridge ...@@ -31,6 +33,21 @@ class ArcVolumeMounterBridge
public ConnectionObserver<mojom::VolumeMounterInstance>, public ConnectionObserver<mojom::VolumeMounterInstance>,
public mojom::VolumeMounterHost { public mojom::VolumeMounterHost {
public: public:
class Delegate {
public:
// To be called by ArcVolumeMounter when a removable media is mounted. This
// create a watcher for the removable media.
virtual void StartWatchingRemovableMedia(const std::string& fs_uuid,
const std::string& mount_path,
base::OnceClosure callback) = 0;
// To be called by ArcVolumeMounter when a removable media is unmounted.
// This removees the watcher for the removable media..
virtual void StopWatchingRemovableMedia(const std::string& fs_uuid) = 0;
protected:
~Delegate() = default;
};
// Returns singleton instance for the given BrowserContext, // Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC. // or nullptr if the browser |context| is not allowed to use ARC.
static ArcVolumeMounterBridge* GetForBrowserContext( static ArcVolumeMounterBridge* GetForBrowserContext(
...@@ -38,13 +55,13 @@ class ArcVolumeMounterBridge ...@@ -38,13 +55,13 @@ class ArcVolumeMounterBridge
static ArcVolumeMounterBridge* GetForBrowserContextForTesting( static ArcVolumeMounterBridge* GetForBrowserContextForTesting(
content::BrowserContext* context); content::BrowserContext* context);
// Returns Factory instance for ArcVolumeMounterBridge.
static KeyedServiceBaseFactory* GetFactory();
ArcVolumeMounterBridge(content::BrowserContext* context, ArcVolumeMounterBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service); ArcBridgeService* bridge_service);
~ArcVolumeMounterBridge() override; ~ArcVolumeMounterBridge() override;
// ConnectionObserver<mojom::VolumeMounterInstance> overrides:
void OnConnectionReady() override;
// chromeos::disks::DiskMountManager::Observer overrides: // chromeos::disks::DiskMountManager::Observer overrides:
void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event, void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
chromeos::MountError error_code, chromeos::MountError error_code,
...@@ -54,14 +71,28 @@ class ArcVolumeMounterBridge ...@@ -54,14 +71,28 @@ class ArcVolumeMounterBridge
// mojom::VolumeMounterHost overrides: // mojom::VolumeMounterHost overrides:
void RequestAllMountPoints() override; void RequestAllMountPoints() override;
private: // Initialize ArcVolumeMounterBridge with delegate.
void Initialize(Delegate* delegate);
// Send all existing mount events. Usually is called around service startup.
void SendAllMountEvents(); void SendAllMountEvents();
private:
void SendMountEventForMyFiles(); void SendMountEventForMyFiles();
void SendMountEventForRemovableMedia(
chromeos::disks::DiskMountManager::MountEvent event,
const std::string& source_path,
const std::string& mount_path,
const std::string& fs_uuid,
const std::string& device_label,
chromeos::DeviceType device_type,
bool visible);
bool IsVisibleToAndroidApps(const std::string& uuid) const; bool IsVisibleToAndroidApps(const std::string& uuid) const;
void OnVisibleStoragesChanged(); void OnVisibleStoragesChanged();
Delegate* delegate_;
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
PrefService* const pref_service_; PrefService* const pref_service_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment