blob: 368952dcd671104bc4115560517b0b7e60e988c1 [file] [log] [blame]
Avi Drissmane4714ce92022-09-12 21:41:581// Copyright 2019 The Chromium Authors
Sergei Datsenko44ee41332019-02-12 05:33:282// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Henrique Ferreiro197812962022-08-22 23:51:105#include "chromeos/ash/components/drivefs/drivefs_session.h"
Sergei Datsenko44ee41332019-02-12 05:33:286
7#include <utility>
8
Avi Drissman710fdab2023-01-11 04:37:369#include "base/functional/bind.h"
Arthur Sonzognid8468bb2023-04-21 19:36:4910#include "base/memory/raw_ptr.h"
Anand K. Mistry7cdbe2d2020-01-21 03:43:2211#include "base/memory/weak_ptr.h"
Sergei Datsenko44ee41332019-02-12 05:33:2812#include "base/strings/strcat.h"
Henrique Ferreiro8e7c4d32022-08-19 15:48:0313#include "chromeos/ash/components/disks/mount_point.h"
Henrique Ferreiro197812962022-08-22 23:51:1014#include "chromeos/ash/components/drivefs/drivefs_bootstrap.h"
Sergei Datsenko44ee41332019-02-12 05:33:2815
16namespace drivefs {
17
18namespace {
19
20using MountFailure = DriveFsSession::MountObserver::MountFailure;
21constexpr char kDataDirOption[] = "datadir=";
Sam McNally6783de02019-06-13 23:35:5722constexpr char kMyFilesOption[] = "myfiles=";
Sergei Datsenko44ee41332019-02-12 05:33:2823constexpr char kMountScheme[] = "drivefs://";
Peter Kastinge5a38ed2021-10-02 03:06:3524constexpr base::TimeDelta kMountTimeout = base::Seconds(20);
Sergei Datsenko44ee41332019-02-12 05:33:2825
Anand K. Mistry7cdbe2d2020-01-21 03:43:2226class DiskMounterImpl : public DiskMounter {
Sergei Datsenko44ee41332019-02-12 05:33:2827 public:
Yeunjoo Choif12038632021-12-01 02:45:4828 explicit DiskMounterImpl(ash::disks::DiskMountManager* disk_mount_manager)
Sergei Datsenko44ee41332019-02-12 05:33:2829 : disk_mount_manager_(disk_mount_manager) {}
30
Peter Boströmec31a042021-09-16 23:37:3431 DiskMounterImpl(const DiskMounterImpl&) = delete;
32 DiskMounterImpl& operator=(const DiskMounterImpl&) = delete;
33
Anand K. Mistry7cdbe2d2020-01-21 03:43:2234 ~DiskMounterImpl() override = default;
Sergei Datsenko44ee41332019-02-12 05:33:2835
36 void Mount(const base::UnguessableToken& token,
37 const base::FilePath& data_path,
Sam McNallya0c0018f2019-05-22 08:03:5438 const base::FilePath& my_files_path,
Sergei Datsenko44ee41332019-02-12 05:33:2839 const std::string& desired_mount_dir_name,
40 base::OnceCallback<void(base::FilePath)> callback) override {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2241 DCHECK(!mount_point_);
Sergei Datsenko44ee41332019-02-12 05:33:2842 DCHECK(callback_.is_null());
43 callback_ = std::move(callback);
44
Sergei Datsenko44ee41332019-02-12 05:33:2845 source_path_ = base::StrCat({kMountScheme, token.ToString()});
46 std::string datadir_option =
47 base::StrCat({kDataDirOption, data_path.value()});
Anand K. Mistry7cdbe2d2020-01-21 03:43:2248
Yeunjoo Choif12038632021-12-01 02:45:4849 ash::disks::MountPoint::Mount(
Anand K. Mistry7cdbe2d2020-01-21 03:43:2250 disk_mount_manager_, source_path_, "", desired_mount_dir_name,
Sam McNally6783de02019-06-13 23:35:5751 {datadir_option, base::StrCat({kMyFilesOption, my_files_path.value()})},
Yeunjoo Choi191d43c2022-08-16 03:03:5452 ash::MountType::kNetworkStorage, ash::MountAccessMode::kReadWrite,
Anand K. Mistry7cdbe2d2020-01-21 03:43:2253 base::BindOnce(&DiskMounterImpl::OnMountDone,
54 weak_factory_.GetWeakPtr()));
Sergei Datsenko44ee41332019-02-12 05:33:2855 }
56
57 private:
Anand K. Mistry7cdbe2d2020-01-21 03:43:2258 // MountPoint::Mount() done callback.
Yeunjoo Choi1b99e7092022-08-03 01:15:1559 void OnMountDone(ash::MountError error_code,
Yeunjoo Choif12038632021-12-01 02:45:4860 std::unique_ptr<ash::disks::MountPoint> mount_point) {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2261 DCHECK(callback_);
Sergei Datsenko44ee41332019-02-12 05:33:2862
François Degrosc7a6d1a2022-10-26 00:06:0463 if (error_code != ash::MountError::kSuccess) {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2264 LOG(WARNING) << "DriveFs mount failed with error: " << error_code;
65 std::move(callback_).Run({});
Sergei Datsenko44ee41332019-02-12 05:33:2866 return;
67 }
Anand K. Mistry7cdbe2d2020-01-21 03:43:2268
69 DCHECK(mount_point);
70 mount_point_ = std::move(mount_point);
71 std::move(callback_).Run(mount_point_->mount_path());
Sergei Datsenko44ee41332019-02-12 05:33:2872 }
73
Bartek Nowierski6b2b6f5a2024-01-08 06:42:5774 const raw_ptr<ash::disks::DiskMountManager> disk_mount_manager_;
Sergei Datsenko44ee41332019-02-12 05:33:2875 base::OnceCallback<void(base::FilePath)> callback_;
76 // The path passed to cros-disks to mount.
77 std::string source_path_;
Yeunjoo Choif12038632021-12-01 02:45:4878 std::unique_ptr<ash::disks::MountPoint> mount_point_;
Anand K. Mistry7cdbe2d2020-01-21 03:43:2279
80 base::WeakPtrFactory<DiskMounterImpl> weak_factory_{this};
Sergei Datsenko44ee41332019-02-12 05:33:2881};
82
83} // namespace
84
85std::unique_ptr<DiskMounter> DiskMounter::Create(
Yeunjoo Choif12038632021-12-01 02:45:4886 ash::disks::DiskMountManager* disk_mount_manager) {
Sergei Datsenko44ee41332019-02-12 05:33:2887 return std::make_unique<DiskMounterImpl>(disk_mount_manager);
88}
89
90DriveFsSession::DriveFsSession(base::OneShotTimer* timer,
91 std::unique_ptr<DiskMounter> disk_mounter,
92 std::unique_ptr<DriveFsConnection> connection,
93 const base::FilePath& data_path,
Sam McNallya0c0018f2019-05-22 08:03:5494 const base::FilePath& my_files_path,
Sergei Datsenko44ee41332019-02-12 05:33:2895 const std::string& desired_mount_dir_name,
96 MountObserver* observer)
97 : timer_(timer),
98 disk_mounter_(std::move(disk_mounter)),
99 connection_(std::move(connection)),
100 observer_(observer) {
101 auto token = connection_->Connect(
102 this, base::BindOnce(&DriveFsSession::OnMojoConnectionError,
103 base::Unretained(this)));
104 CHECK(token);
105 drivefs_ = &connection_->GetDriveFs();
Sam McNallya0c0018f2019-05-22 08:03:54106 disk_mounter_->Mount(token, data_path, my_files_path, desired_mount_dir_name,
Sergei Datsenko44ee41332019-02-12 05:33:28107 base::BindOnce(&DriveFsSession::OnDiskMountCompleted,
108 base::Unretained(this)));
109 timer_->Start(
110 FROM_HERE, kMountTimeout,
111 base::BindOnce(&DriveFsSession::OnMountTimedOut, base::Unretained(this)));
112}
113
114DriveFsSession::~DriveFsSession() {
115 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116 timer_->Stop();
117 is_mounted_ = false;
118 drivefs_has_terminated_ = true;
119 disk_mounter_.reset();
120}
121
122void DriveFsSession::OnDiskMountCompleted(base::FilePath mount_path) {
123 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
124 if (!mount_path.empty()) {
125 mount_path_ = mount_path;
126 MaybeNotifyOnMounted();
127 } else {
128 NotifyFailed(MountFailure::kInvocation, {});
129 }
130}
131
132void DriveFsSession::OnMojoConnectionError() {
133 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
134 if (!drivefs_has_terminated_) {
135 bool was_mounted = is_mounted_;
136 is_mounted_ = false;
137 drivefs_has_terminated_ = true;
138 if (was_mounted) {
139 NotifyUnmounted({});
140 } else {
141 NotifyFailed(MountFailure::kIpcDisconnect, {});
142 }
143 }
144}
145
146void DriveFsSession::OnMountTimedOut() {
147 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
148 DCHECK(!is_mounted_);
149 DCHECK(!drivefs_has_terminated_);
150 timer_->Stop();
151 drivefs_has_terminated_ = true;
152 NotifyFailed(MountFailure::kTimeout, {});
153}
154
155void DriveFsSession::MaybeNotifyOnMounted() {
156 is_mounted_ =
157 drivefs_has_started_ && !drivefs_has_terminated_ && !mount_path_.empty();
158 if (is_mounted_) {
159 timer_->Stop();
160 observer_->OnMounted(mount_path());
161 }
162}
163
164void DriveFsSession::NotifyFailed(
165 MountFailure failure,
Arthur Sonzogni74f09f8a2023-12-06 19:35:29166 std::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28167 // May delete |this|.
168 auto connection = std::move(connection_);
169 if (connection) {
170 observer_->OnMountFailed(failure, remount_delay);
171 }
172}
173
174void DriveFsSession::NotifyUnmounted(
Arthur Sonzogni74f09f8a2023-12-06 19:35:29175 std::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28176 // May delete |this|.
177 auto connection = std::move(connection_);
178 if (connection) {
179 observer_->OnUnmounted(remount_delay);
180 }
181}
182
183void DriveFsSession::OnMounted() {
184 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
185 DCHECK(!drivefs_has_started_);
186 DCHECK(!is_mounted_);
187 if (!drivefs_has_terminated_) {
188 drivefs_has_started_ = true;
189 MaybeNotifyOnMounted();
190 }
191}
192
193void DriveFsSession::OnMountFailed(
Arthur Sonzogni74f09f8a2023-12-06 19:35:29194 std::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28195 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
196 DCHECK(!drivefs_has_started_);
197 DCHECK(!is_mounted_);
198 if (!drivefs_has_terminated_) {
199 drivefs_has_terminated_ = true;
200 bool needs_restart = remount_delay.has_value();
201 NotifyFailed(
202 needs_restart ? MountFailure::kNeedsRestart : MountFailure::kUnknown,
203 std::move(remount_delay));
204 }
205}
206
Arthur Sonzogni74f09f8a2023-12-06 19:35:29207void DriveFsSession::OnUnmounted(std::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28208 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
209 DCHECK(drivefs_has_started_);
210 DCHECK(!drivefs_has_terminated_);
211 DCHECK(is_mounted_);
212 bool was_mounted = is_mounted_;
213 drivefs_has_terminated_ = true;
214 is_mounted_ = false;
215 if (was_mounted) {
216 NotifyUnmounted(std::move(remount_delay));
217 }
218}
219
220void DriveFsSession::OnHeartbeat() {
221 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
222 if (timer_->IsRunning()) {
223 timer_->Reset();
224 }
225}
226
227} // namespace drivefs