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
ash / components / arc / volume_mounter / arc_volume_mounter_bridge.h [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_COMPONENTS_ARC_VOLUME_MOUNTER_ARC_VOLUME_MOUNTER_BRIDGE_H_
#define ASH_COMPONENTS_ARC_VOLUME_MOUNTER_ARC_VOLUME_MOUNTER_BRIDGE_H_
#include <string>
#include "ash/components/arc/mojom/volume_mounter.mojom.h"
#include "ash/components/arc/session/connection_observer.h"
#include "base/cancelable_callback.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/ash/components/disks/disk_mount_manager.h"
#include "chromeos/dbus/power/power_manager_client.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"
namespace content {
class BrowserContext;
} // namespace content
namespace arc {
constexpr char kArcppMediaSharingServicesJobName[] =
"arcpp_2dmedia_2dsharing_2dservices";
class ArcBridgeService;
// This class handles Volume mount/unmount requests from cros-disks and
// send them to Android.
class ArcVolumeMounterBridge
: public KeyedService,
public ash::disks::DiskMountManager::Observer,
public ash::disks::DiskMountManager::ArcDelegate,
public chromeos::PowerManagerClient::Observer,
public ConnectionObserver<mojom::VolumeMounterInstance>,
public mojom::VolumeMounterHost {
public:
class Delegate {
public:
// Returns true if file system changes are watched by file system watchers.
// Mounting events should be sent to Android only when this returns true so
// that every file in MyFiles and removable media is indexed in Android's
// MediaStore.
virtual bool IsWatchingFileSystemChanges() = 0;
// To be called by ArcVolumeMounter when a removable media is mounted. This
// creates a watcher for the removable media if it's not created yet.
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 removes the watcher for the removable media..
virtual void StopWatchingRemovableMedia(const std::string& mount_path) = 0;
protected:
~Delegate() = default;
};
// Returns singleton instance for the given BrowserContext,
// or nullptr if the browser |context| is not allowed to use ARC.
static ArcVolumeMounterBridge* GetForBrowserContext(
content::BrowserContext* context);
// Returns Factory instance for ArcVolumeMounterBridge.
static KeyedServiceBaseFactory* GetFactory();
ArcVolumeMounterBridge(content::BrowserContext* context,
ArcBridgeService* bridge_service);
ArcVolumeMounterBridge(const ArcVolumeMounterBridge&) = delete;
ArcVolumeMounterBridge& operator=(const ArcVolumeMounterBridge&) = delete;
~ArcVolumeMounterBridge() override;
// ash::disks::DiskMountManager::Observer overrides:
void OnMountEvent(
ash::disks::DiskMountManager::MountEvent event,
ash::MountError error_code,
const ash::disks::DiskMountManager::MountPoint& mount_info) override;
// ash::disks::DiskMountManager::ArcDelegate overrides:
void DropArcCaches(
const base::FilePath& mount_path,
ash::disks::DiskMountManager::ArcDelegate::Callback callback) override;
// chromeos::PowerManagerClient::Observer overrides:
void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
void SuspendDone(base::TimeDelta sleep_duration) override;
// ConnectionObserver<mojom::VolumeMounterInstance> overrides:
void OnConnectionReady() override;
void OnConnectionClosed() override;
// mojom::VolumeMounterHost overrides:
void RequestAllMountPoints() override;
void SetUpExternalStorageMountPoints(
uint32_t media_provider_uid,
SetUpExternalStorageMountPointsCallback callback) override;
void OnReadyToSuspend(bool success) override;
// Initialize ArcVolumeMounterBridge with delegate.
void Initialize(Delegate* delegate);
// Send all existing mount events. Usually is called around service startup.
void SendAllMountEvents();
// Utility methods for testing.
void SetUnmountTimeoutForTesting(const base::TimeDelta& timeout) {
unmount_timeout_ = timeout;
}
base::OneShotTimer* GetUnmountTimerForTesting() { return &unmount_timer_; }
static void EnsureFactoryBuilt();
private:
void SendMountEventForMyFiles();
void SendMountEventForRemovableMedia(
ash::disks::DiskMountManager::MountEvent event,
const std::string& source_path,
const std::string& mount_path,
const std::string& fs_uuid,
const std::string& device_label,
ash::DeviceType device_type,
bool visible);
bool IsVisibleToAndroidApps(const std::string& uuid) const;
void OnVisibleStoragesChanged();
bool IsReadyToSendMountingEvents();
void OnSetUpExternalStorageMountPoints(
const std::string& job_name,
SetUpExternalStorageMountPointsCallback callback,
bool result,
std::optional<std::string> error_name,
std::optional<std::string> error_message);
// Processes the oldest PrepareForRemovableMediaUnmount request queued in
// `unmount_requests_` by calling the PrepareForRemovableMediaUnmount mojo
// method and starting `unmount_timer_`.
void ProcessPendingRemovableMediaUnmountRequest();
// The callback for PrepareForRemovableMediaUnmount mojo call and
// `unmount_timer_`. This method should be called only by one of them for
// every unmount request.
void OnArcPreparedForRemovableMediaUnmount(const base::FilePath& mount_path,
bool is_timeout,
bool success);
using UnmountRequest =
std::tuple<base::FilePath,
ash::disks::DiskMountManager::ArcDelegate::Callback>;
// Pending requests for PrepareForRemovableMediaUnmount().
base::queue<UnmountRequest> unmount_requests_
GUARDED_BY_CONTEXT(sequence_checker_);
// Manages the timeout of PrepareForRemovableMediaUnmount mojo call.
base::OneShotTimer unmount_timer_ GUARDED_BY_CONTEXT(sequence_checker_);
// Callback for the current PrepareForRemovableMediaUnmount mojo call.
// This will be cancelled if not run by the timeout.
base::CancelableOnceCallback<void(bool)> unmount_mojo_callback_
GUARDED_BY_CONTEXT(sequence_checker_);
// Stores the callback passed from DropArcCaches() call that triggered the
// current in-flight mojo call.
ash::disks::DiskMountManager::ArcDelegate::Callback unmount_callback_
GUARDED_BY_CONTEXT(sequence_checker_);
// When the callback for PrepareForRemovableMediaUnmount mojo does not run
// within this timeout, the callback will be called with false.
base::TimeDelta unmount_timeout_ = base::Seconds(30);
// Holds the last time when PrepareForRemovableMediaUnmount mojo was called.
base::TimeTicks unmount_mojo_start_time_;
// Represents the state of cleaning up ARC-side removable media caches before
// device suspension. State transition should be as follows:
// NO_SUSPEND -> NOT_READY_TO_SUSPEND:
// When `SuspendImminent` is called.
// NOT_READY_TO_SUSPEND -> READY_TO_SUSPEND:
// When `OnReadyToSuspend` is called.
// NOT_READY_TO_SUSPEND or READY_TO_SUSPEND -> NO_SUSPEND:
// When `SuspendDone` is called.
enum class SuspendState {
// The device is not going to suspend.
NO_SUSPEND,
// The device is going to suspend, but there still might be removable drives
// mounted on the ARC side.
NOT_READY_TO_SUSPEND,
// The device is going to suspend, and all removable drives should have been
// unmounted on the ARC side.
READY_TO_SUSPEND,
};
SuspendState suspend_state_ = SuspendState::NO_SUSPEND;
raw_ptr<Delegate, DanglingUntriaged> delegate_ = nullptr;
const raw_ptr<ArcBridgeService>
arc_bridge_service_; // Owned by ArcServiceManager.
const raw_ptr<PrefService> pref_service_;
PrefChangeRegistrar change_registerar_;
bool external_storage_mount_points_are_ready_ = false;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<ArcVolumeMounterBridge> weak_ptr_factory_{this};
};
} // namespace arc
#endif // ASH_COMPONENTS_ARC_VOLUME_MOUNTER_ARC_VOLUME_MOUNTER_BRIDGE_H_