blob: 98276a2257b8dadc31bf85bb6a987322d3c6d98d [file] [log] [blame]
Sergei Datsenko44ee41332019-02-12 05:33:281// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/components/drivefs/drivefs_session.h"
6
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"
12#include "chromeos/components/drivefs/drivefs_bootstrap.h"
Anand K. Mistry7cdbe2d2020-01-21 03:43:2213#include "chromeos/disks/mount_point.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://";
23constexpr base::TimeDelta kMountTimeout = base::TimeDelta::FromSeconds(20);
24
Anand K. Mistry7cdbe2d2020-01-21 03:43:2225class DiskMounterImpl : public DiskMounter {
Sergei Datsenko44ee41332019-02-12 05:33:2826 public:
27 explicit DiskMounterImpl(
28 chromeos::disks::DiskMountManager* disk_mount_manager)
29 : disk_mount_manager_(disk_mount_manager) {}
30
Anand K. Mistry7cdbe2d2020-01-21 03:43:2231 ~DiskMounterImpl() override = default;
Sergei Datsenko44ee41332019-02-12 05:33:2832
33 void Mount(const base::UnguessableToken& token,
34 const base::FilePath& data_path,
Sam McNallya0c0018f2019-05-22 08:03:5435 const base::FilePath& my_files_path,
Sergei Datsenko44ee41332019-02-12 05:33:2836 const std::string& desired_mount_dir_name,
37 base::OnceCallback<void(base::FilePath)> callback) override {
Anand K. Mistry7cdbe2d2020-01-21 03:43:2238 DCHECK(!mount_point_);
Sergei Datsenko44ee41332019-02-12 05:33:2839 DCHECK(callback_.is_null());
40 callback_ = std::move(callback);
41
Sergei Datsenko44ee41332019-02-12 05:33:2842 source_path_ = base::StrCat({kMountScheme, token.ToString()});
43 std::string datadir_option =
44 base::StrCat({kDataDirOption, data_path.value()});
Anand K. Mistry7cdbe2d2020-01-21 03:43:2245
46 chromeos::disks::MountPoint::Mount(
47 disk_mount_manager_, source_path_, "", desired_mount_dir_name,
Sam McNally6783de02019-06-13 23:35:5748 {datadir_option, base::StrCat({kMyFilesOption, my_files_path.value()})},
49 chromeos::MOUNT_TYPE_NETWORK_STORAGE,
Anand K. Mistry7cdbe2d2020-01-21 03:43:2250 chromeos::MOUNT_ACCESS_MODE_READ_WRITE,
51 base::BindOnce(&DiskMounterImpl::OnMountDone,
52 weak_factory_.GetWeakPtr()));
Sergei Datsenko44ee41332019-02-12 05:33:2853 }
54
55 private:
Anand K. Mistry7cdbe2d2020-01-21 03:43:2256 // MountPoint::Mount() done callback.
57 void OnMountDone(chromeos::MountError error_code,
58 std::unique_ptr<chromeos::disks::MountPoint> mount_point) {
59 DCHECK(callback_);
Sergei Datsenko44ee41332019-02-12 05:33:2860
Anand K. Mistry7cdbe2d2020-01-21 03:43:2261 if (error_code != chromeos::MOUNT_ERROR_NONE) {
62 LOG(WARNING) << "DriveFs mount failed with error: " << error_code;
63 std::move(callback_).Run({});
Sergei Datsenko44ee41332019-02-12 05:33:2864 return;
65 }
Anand K. Mistry7cdbe2d2020-01-21 03:43:2266
67 DCHECK(mount_point);
68 mount_point_ = std::move(mount_point);
69 std::move(callback_).Run(mount_point_->mount_path());
Sergei Datsenko44ee41332019-02-12 05:33:2870 }
71
72 chromeos::disks::DiskMountManager* const disk_mount_manager_;
73 base::OnceCallback<void(base::FilePath)> callback_;
74 // The path passed to cros-disks to mount.
75 std::string source_path_;
Anand K. Mistry7cdbe2d2020-01-21 03:43:2276 std::unique_ptr<chromeos::disks::MountPoint> mount_point_;
77
78 base::WeakPtrFactory<DiskMounterImpl> weak_factory_{this};
Sergei Datsenko44ee41332019-02-12 05:33:2879
80 DISALLOW_COPY_AND_ASSIGN(DiskMounterImpl);
81};
82
83} // namespace
84
85std::unique_ptr<DiskMounter> DiskMounter::Create(
86 chromeos::disks::DiskMountManager* disk_mount_manager) {
87 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,
Anton Bikineeva55469fa2021-05-15 18:01:45166 absl::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(
Anton Bikineeva55469fa2021-05-15 18:01:45175 absl::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(
Anton Bikineeva55469fa2021-05-15 18:01:45194 absl::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
207void DriveFsSession::OnUnmounted(
Anton Bikineeva55469fa2021-05-15 18:01:45208 absl::optional<base::TimeDelta> remount_delay) {
Sergei Datsenko44ee41332019-02-12 05:33:28209 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
210 DCHECK(drivefs_has_started_);
211 DCHECK(!drivefs_has_terminated_);
212 DCHECK(is_mounted_);
213 bool was_mounted = is_mounted_;
214 drivefs_has_terminated_ = true;
215 is_mounted_ = false;
216 if (was_mounted) {
217 NotifyUnmounted(std::move(remount_delay));
218 }
219}
220
221void DriveFsSession::OnHeartbeat() {
222 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
223 if (timer_->IsRunning()) {
224 timer_->Reset();
225 }
226}
227
228} // namespace drivefs