blob: ded5a319ebcf4aac3e8fc10d8478bbb69825a9df [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
Anand K. Mistry7cdbe2d2020-01-21 03:43:229#include "base/bind.h"
10#include "base/memory/weak_ptr.h"
Sergei Datsenko44ee41332019-02-12 05:33:2811#include "base/strings/strcat.h"
Henrique Ferreiro8e7c4d32022-08-19 15:48:0312#include "chromeos/ash/components/disks/mount_point.h"
Henrique Ferreiro197812962022-08-22 23:51:1013#include "chromeos/ash/components/drivefs/drivefs_bootstrap.h"
Sergei Datsenko44ee41332019-02-12 05:33:2814
15namespace drivefs {
16
17namespace {
18
19using MountFailure = DriveFsSession::MountObserver::MountFailure;
20constexpr char kDataDirOption[] = "datadir=";
Sam McNally6783de02019-06-13 23:35:5721constexpr char kMyFilesOption[] = "myfiles=";
Sergei Datsenko44ee41332019-02-12 05:33:2822constexpr char kMountScheme[] = "drivefs://";
Peter Kastinge5a38ed2021-10-02 03:06:3523constexpr base::TimeDelta kMountTimeout = base::Seconds(20);
Sergei Datsenko44ee41332019-02-12 05:33:2824
Anand K. Mistry7cdbe2d2020-01-21 03:43:2225class DiskMounterImpl : public DiskMounter {
Sergei Datsenko44ee41332019-02-12 05:33:2826 public:
Yeunjoo Choif12038632021-12-01 02:45:4827 explicit DiskMounterImpl(ash::disks::DiskMountManager* disk_mount_manager)
Sergei Datsenko44ee41332019-02-12 05:33:2828 : disk_mount_manager_(disk_mount_manager) {}
29
Peter Boströmec31a042021-09-16 23:37:3430 DiskMounterImpl(const DiskMounterImpl&) = delete;
31 DiskMounterImpl& operator=(const DiskMounterImpl&) = delete;
32
Anand K. Mistry7cdbe2d2020-01-21 03:43:2233 ~DiskMounterImpl() override = default;
Sergei Datsenko44ee41332019-02-12 05:33:2834
35 void Mount(const base::UnguessableToken& token,
36 const base::FilePath& data_path,
Sam McNallya0c0018f2019-05-22 08:03:5437 const base::FilePath& my_files_path,
Sergei Datsenko44ee41332019-02-12 05:33:2838 const std::string& desired_mount_dir_name,
39 base::OnceCallback<void(base::FilePath)> callback) override {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2240 DCHECK(!mount_point_);
Sergei Datsenko44ee41332019-02-12 05:33:2841 DCHECK(callback_.is_null());
42 callback_ = std::move(callback);
43
Sergei Datsenko44ee41332019-02-12 05:33:2844 source_path_ = base::StrCat({kMountScheme, token.ToString()});
45 std::string datadir_option =
46 base::StrCat({kDataDirOption, data_path.value()});
Anand K. Mistry7cdbe2d2020-01-21 03:43:2247
Yeunjoo Choif12038632021-12-01 02:45:4848 ash::disks::MountPoint::Mount(
Anand K. Mistry7cdbe2d2020-01-21 03:43:2249 disk_mount_manager_, source_path_, "", desired_mount_dir_name,
Sam McNally6783de02019-06-13 23:35:5750 {datadir_option, base::StrCat({kMyFilesOption, my_files_path.value()})},
Yeunjoo Choi191d43c2022-08-16 03:03:5451 ash::MountType::kNetworkStorage, ash::MountAccessMode::kReadWrite,
Anand K. Mistry7cdbe2d2020-01-21 03:43:2252 base::BindOnce(&DiskMounterImpl::OnMountDone,
53 weak_factory_.GetWeakPtr()));
Sergei Datsenko44ee41332019-02-12 05:33:2854 }
55
56 private:
Anand K. Mistry7cdbe2d2020-01-21 03:43:2257 // MountPoint::Mount() done callback.
Yeunjoo Choi1b99e7092022-08-03 01:15:1558 void OnMountDone(ash::MountError error_code,
Yeunjoo Choif12038632021-12-01 02:45:4859 std::unique_ptr<ash::disks::MountPoint> mount_point) {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2260 DCHECK(callback_);
Sergei Datsenko44ee41332019-02-12 05:33:2861
Yeunjoo Choi1b99e7092022-08-03 01:15:1562 if (error_code != ash::MountError::kNone) {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2263 LOG(WARNING) << "DriveFs mount failed with error: " << error_code;
64 std::move(callback_).Run({});
Sergei Datsenko44ee41332019-02-12 05:33:2865 return;
66 }
Anand K. Mistry7cdbe2d2020-01-21 03:43:2267
68 DCHECK(mount_point);
69 mount_point_ = std::move(mount_point);
70 std::move(callback_).Run(mount_point_->mount_path());
Sergei Datsenko44ee41332019-02-12 05:33:2871 }
72
Yeunjoo Choif12038632021-12-01 02:45:4873 ash::disks::DiskMountManager* const disk_mount_manager_;
Sergei Datsenko44ee41332019-02-12 05:33:2874 base::OnceCallback<void(base::FilePath)> callback_;
75 // The path passed to cros-disks to mount.
76 std::string source_path_;
Yeunjoo Choif12038632021-12-01 02:45:4877 std::unique_ptr<ash::disks::MountPoint> mount_point_;
Anand K. Mistry7cdbe2d2020-01-21 03:43:2278
79 base::WeakPtrFactory<DiskMounterImpl> weak_factory_{this};
Sergei Datsenko44ee41332019-02-12 05:33:2880};
81
82} // namespace
83
84std::unique_ptr<DiskMounter> DiskMounter::Create(
Yeunjoo Choif12038632021-12-01 02:45:4885 ash::disks::DiskMountManager* disk_mount_manager) {
Sergei Datsenko44ee41332019-02-12 05:33:2886 return std::make_unique<DiskMounterImpl>(disk_mount_manager);
87}
88
89DriveFsSession::DriveFsSession(base::OneShotTimer* timer,
90 std::unique_ptr<DiskMounter> disk_mounter,
91 std::unique_ptr<DriveFsConnection> connection,
92 const base::FilePath& data_path,
Sam McNallya0c0018f2019-05-22 08:03:5493 const base::FilePath& my_files_path,
Sergei Datsenko44ee41332019-02-12 05:33:2894 const std::string& desired_mount_dir_name,
95 MountObserver* observer)
96 : timer_(timer),
97 disk_mounter_(std::move(disk_mounter)),
98 connection_(std::move(connection)),
99 observer_(observer) {
100 auto token = connection_->Connect(
101 this, base::BindOnce(&DriveFsSession::OnMojoConnectionError,
102 base::Unretained(this)));
103 CHECK(token);
104 drivefs_ = &connection_->GetDriveFs();
Sam McNallya0c0018f2019-05-22 08:03:54105 disk_mounter_->Mount(token, data_path, my_files_path, desired_mount_dir_name,
Sergei Datsenko44ee41332019-02-12 05:33:28106 base::BindOnce(&DriveFsSession::OnDiskMountCompleted,
107 base::Unretained(this)));
108 timer_->Start(
109 FROM_HERE, kMountTimeout,
110 base::BindOnce(&DriveFsSession::OnMountTimedOut, base::Unretained(this)));
111}
112
113DriveFsSession::~DriveFsSession() {
114 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
115 timer_->Stop();
116 is_mounted_ = false;
117 drivefs_has_terminated_ = true;
118 disk_mounter_.reset();
119}
120
121void DriveFsSession::OnDiskMountCompleted(base::FilePath mount_path) {
122 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123 if (!mount_path.empty()) {
124 mount_path_ = mount_path;
125 MaybeNotifyOnMounted();
126 } else {
127 NotifyFailed(MountFailure::kInvocation, {});
128 }
129}
130
131void DriveFsSession::OnMojoConnectionError() {
132 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
133 if (!drivefs_has_terminated_) {
134 bool was_mounted = is_mounted_;
135 is_mounted_ = false;
136 drivefs_has_terminated_ = true;
137 if (was_mounted) {
138 NotifyUnmounted({});
139 } else {
140 NotifyFailed(MountFailure::kIpcDisconnect, {});
141 }
142 }
143}
144
145void DriveFsSession::OnMountTimedOut() {
146 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
147 DCHECK(!is_mounted_);
148 DCHECK(!drivefs_has_terminated_);
149 timer_->Stop();
150 drivefs_has_terminated_ = true;
151 NotifyFailed(MountFailure::kTimeout, {});
152}
153
154void DriveFsSession::MaybeNotifyOnMounted() {
155 is_mounted_ =
156 drivefs_has_started_ && !drivefs_has_terminated_ && !mount_path_.empty();
157 if (is_mounted_) {
158 timer_->Stop();
159 observer_->OnMounted(mount_path());
160 }
161}
162
163void DriveFsSession::NotifyFailed(
164 MountFailure failure,
Anton Bikineeva55469fa2021-05-15 18:01:45165 absl::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28166 // May delete |this|.
167 auto connection = std::move(connection_);
168 if (connection) {
169 observer_->OnMountFailed(failure, remount_delay);
170 }
171}
172
173void DriveFsSession::NotifyUnmounted(
Anton Bikineeva55469fa2021-05-15 18:01:45174 absl::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28175 // May delete |this|.
176 auto connection = std::move(connection_);
177 if (connection) {
178 observer_->OnUnmounted(remount_delay);
179 }
180}
181
182void DriveFsSession::OnMounted() {
183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
184 DCHECK(!drivefs_has_started_);
185 DCHECK(!is_mounted_);
186 if (!drivefs_has_terminated_) {
187 drivefs_has_started_ = true;
188 MaybeNotifyOnMounted();
189 }
190}
191
192void DriveFsSession::OnMountFailed(
Anton Bikineeva55469fa2021-05-15 18:01:45193 absl::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28194 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
195 DCHECK(!drivefs_has_started_);
196 DCHECK(!is_mounted_);
197 if (!drivefs_has_terminated_) {
198 drivefs_has_terminated_ = true;
199 bool needs_restart = remount_delay.has_value();
200 NotifyFailed(
201 needs_restart ? MountFailure::kNeedsRestart : MountFailure::kUnknown,
202 std::move(remount_delay));
203 }
204}
205
206void DriveFsSession::OnUnmounted(
Anton Bikineeva55469fa2021-05-15 18:01:45207 absl::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