1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "IdleMaint.h"
18 #include "FileDeviceUtils.h"
19 #include "Utils.h"
20 #include "VoldUtil.h"
21 #include "VolumeManager.h"
22 #include "model/PrivateVolume.h"
23
24 #include <thread>
25 #include <utility>
26
27 #include <aidl/android/hardware/health/storage/BnGarbageCollectCallback.h>
28 #include <aidl/android/hardware/health/storage/IStorage.h>
29 #include <android-base/chrono_utils.h>
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/strings.h>
34 #include <android/binder_manager.h>
35 #include <android/hardware/health/storage/1.0/IStorage.h>
36 #include <fs_mgr.h>
37 #include <private/android_filesystem_config.h>
38 #include <wakelock/wakelock.h>
39
40 #include <dirent.h>
41 #include <fcntl.h>
42 #include <sys/mount.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46
47 using android::base::Basename;
48 using android::base::ReadFileToString;
49 using android::base::Realpath;
50 using android::base::StringPrintf;
51 using android::base::Timer;
52 using android::base::WriteStringToFile;
53 using android::hardware::Return;
54 using android::hardware::Void;
55 using AStorage = aidl::android::hardware::health::storage::IStorage;
56 using ABnGarbageCollectCallback =
57 aidl::android::hardware::health::storage::BnGarbageCollectCallback;
58 using AResult = aidl::android::hardware::health::storage::Result;
59 using HStorage = android::hardware::health::storage::V1_0::IStorage;
60 using HGarbageCollectCallback = android::hardware::health::storage::V1_0::IGarbageCollectCallback;
61 using HResult = android::hardware::health::storage::V1_0::Result;
62 using std::string_literals::operator""s;
63
64 namespace android {
65 namespace vold {
66
67 enum class PathTypes {
68 kMountPoint = 1,
69 kBlkDevice,
70 };
71
72 enum class IdleMaintStats {
73 kStopped = 1,
74 kRunning,
75 kAbort,
76 };
77
78 static const char* kWakeLock = "IdleMaint";
79 static const int DIRTY_SEGMENTS_THRESHOLD = 100;
80 /*
81 * Timing policy:
82 * 1. F2FS_GC = 7 mins
83 * 2. Trim = 1 min
84 * 3. Dev GC = 2 mins
85 */
86 static const int GC_TIMEOUT_SEC = 420;
87 static const int DEVGC_TIMEOUT_SEC = 120;
88
89 static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
90 static std::condition_variable cv_abort, cv_stop;
91 static std::mutex cv_m;
92
addFromVolumeManager(std::list<std::string> * paths,PathTypes path_type)93 static void addFromVolumeManager(std::list<std::string>* paths, PathTypes path_type) {
94 VolumeManager* vm = VolumeManager::Instance();
95 std::list<std::string> privateIds;
96 vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
97 for (const auto& id : privateIds) {
98 PrivateVolume* vol = static_cast<PrivateVolume*>(vm->findVolume(id).get());
99 if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
100 if (path_type == PathTypes::kMountPoint) {
101 paths->push_back(vol->getPath());
102 } else if (path_type == PathTypes::kBlkDevice) {
103 std::string gc_path;
104 const std::string& fs_type = vol->getFsType();
105 if (fs_type == "f2fs" && (Realpath(vol->getRawDmDevPath(), &gc_path) ||
106 Realpath(vol->getRawDevPath(), &gc_path))) {
107 paths->push_back(std::string("/sys/fs/") + fs_type + "/" + Basename(gc_path));
108 }
109 }
110 }
111 }
112 }
113
addFromFstab(std::list<std::string> * paths,PathTypes path_type)114 static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
115 std::string previous_mount_point;
116 for (const auto& entry : fstab_default) {
117 // Skip raw partitions and swap space.
118 if (entry.fs_type == "emmc" || entry.fs_type == "mtd" || entry.fs_type == "swap") {
119 continue;
120 }
121 // Skip read-only filesystems and bind mounts.
122 if (entry.flags & (MS_RDONLY | MS_BIND)) {
123 continue;
124 }
125 // Skip anything without an underlying block device, e.g. virtiofs.
126 if (entry.blk_device[0] != '/') {
127 continue;
128 }
129 if (entry.fs_mgr_flags.vold_managed) {
130 continue; // Should we trim fat32 filesystems?
131 }
132 if (entry.fs_mgr_flags.no_trim) {
133 continue;
134 }
135
136 // Skip the multi-type partitions, which are required to be following each other.
137 // See fs_mgr.c's mount_with_alternatives().
138 if (entry.mount_point == previous_mount_point) {
139 continue;
140 }
141
142 if (path_type == PathTypes::kMountPoint) {
143 paths->push_back(entry.mount_point);
144 } else if (path_type == PathTypes::kBlkDevice) {
145 std::string gc_path;
146 if (entry.fs_type == "f2fs" &&
147 Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &gc_path)) {
148 paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(gc_path));
149 }
150 }
151
152 previous_mount_point = entry.mount_point;
153 }
154 }
155
Trim(const android::sp<android::os::IVoldTaskListener> & listener)156 void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
157 auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
158 if (!wl.has_value()) {
159 return;
160 }
161
162 // Collect both fstab and vold volumes
163 std::list<std::string> paths;
164 addFromFstab(&paths, PathTypes::kMountPoint);
165 addFromVolumeManager(&paths, PathTypes::kMountPoint);
166
167 for (const auto& path : paths) {
168 LOG(DEBUG) << "Starting trim of " << path;
169
170 android::os::PersistableBundle extras;
171 extras.putString(String16("path"), String16(path.c_str()));
172
173 int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
174 if (fd < 0) {
175 PLOG(WARNING) << "Failed to open " << path;
176 if (listener) {
177 listener->onStatus(-1, extras);
178 }
179 continue;
180 }
181
182 struct fstrim_range range;
183 memset(&range, 0, sizeof(range));
184 range.len = ULLONG_MAX;
185
186 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
187 if (ioctl(fd, FITRIM, &range)) {
188 PLOG(WARNING) << "Trim failed on " << path;
189 if (listener) {
190 listener->onStatus(-1, extras);
191 }
192 } else {
193 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
194 LOG(INFO) << "Trimmed " << range.len << " bytes on " << path << " in "
195 << nanoseconds_to_milliseconds(time) << "ms";
196 extras.putLong(String16("bytes"), range.len);
197 extras.putLong(String16("time"), time);
198 if (listener) {
199 listener->onStatus(0, extras);
200 }
201 }
202 close(fd);
203 }
204
205 if (listener) {
206 android::os::PersistableBundle extras;
207 listener->onFinished(0, extras);
208 }
209
210 }
211
waitForGc(const std::list<std::string> & paths)212 static bool waitForGc(const std::list<std::string>& paths) {
213 std::unique_lock<std::mutex> lk(cv_m, std::defer_lock);
214 bool stop = false, aborted = false;
215 Timer timer;
216
217 while (!stop && !aborted) {
218 stop = true;
219 for (const auto& path : paths) {
220 std::string dirty_segments;
221 if (!ReadFileToString(path + "/dirty_segments", &dirty_segments)) {
222 PLOG(WARNING) << "Reading dirty_segments failed in " << path;
223 continue;
224 }
225 if (std::stoi(dirty_segments) > DIRTY_SEGMENTS_THRESHOLD) {
226 stop = false;
227 break;
228 }
229 }
230
231 if (stop) break;
232
233 if (timer.duration() >= std::chrono::seconds(GC_TIMEOUT_SEC)) {
234 LOG(WARNING) << "GC timeout";
235 break;
236 }
237
238 lk.lock();
239 aborted =
240 cv_abort.wait_for(lk, 10s, [] { return idle_maint_stat == IdleMaintStats::kAbort; });
241 lk.unlock();
242 }
243
244 return aborted;
245 }
246
startGc(const std::list<std::string> & paths)247 static int startGc(const std::list<std::string>& paths) {
248 for (const auto& path : paths) {
249 LOG(DEBUG) << "Start GC on " << path;
250 if (!WriteStringToFile("1", path + "/gc_urgent")) {
251 PLOG(WARNING) << "Start GC failed on " << path;
252 }
253 }
254 return android::OK;
255 }
256
stopGc(const std::list<std::string> & paths)257 static int stopGc(const std::list<std::string>& paths) {
258 for (const auto& path : paths) {
259 LOG(DEBUG) << "Stop GC on " << path;
260 if (!WriteStringToFile("0", path + "/gc_urgent")) {
261 PLOG(WARNING) << "Stop GC failed on " << path;
262 }
263 }
264 return android::OK;
265 }
266
runDevGcFstab(void)267 static void runDevGcFstab(void) {
268 std::string path;
269 for (const auto& entry : fstab_default) {
270 if (!entry.sysfs_path.empty()) {
271 path = entry.sysfs_path;
272 break;
273 }
274 }
275
276 if (path.empty()) {
277 return;
278 }
279
280 path = path + "/manual_gc";
281 Timer timer;
282
283 LOG(DEBUG) << "Start Dev GC on " << path;
284 while (1) {
285 std::string require;
286 if (!ReadFileToString(path, &require)) {
287 PLOG(WARNING) << "Reading manual_gc failed in " << path;
288 break;
289 }
290 require = android::base::Trim(require);
291 if (require == "" || require == "off" || require == "disabled") {
292 LOG(DEBUG) << "No more to do Dev GC";
293 break;
294 }
295
296 LOG(DEBUG) << "Trigger Dev GC on " << path;
297 if (!WriteStringToFile("1", path)) {
298 PLOG(WARNING) << "Start Dev GC failed on " << path;
299 break;
300 }
301
302 if (timer.duration() >= std::chrono::seconds(DEVGC_TIMEOUT_SEC)) {
303 LOG(WARNING) << "Dev GC timeout";
304 break;
305 }
306 sleep(2);
307 }
308 LOG(DEBUG) << "Stop Dev GC on " << path;
309 if (!WriteStringToFile("0", path)) {
310 PLOG(WARNING) << "Stop Dev GC failed on " << path;
311 }
312 return;
313 }
314
315 enum class IDL { HIDL, AIDL };
operator <<(std::ostream & os,IDL idl)316 std::ostream& operator<<(std::ostream& os, IDL idl) {
317 return os << (idl == IDL::HIDL ? "HIDL" : "AIDL");
318 }
319
320 template <IDL idl, typename Result>
321 class GcCallbackImpl {
322 protected:
onFinishInternal(Result result)323 void onFinishInternal(Result result) {
324 std::unique_lock<std::mutex> lock(mMutex);
325 mFinished = true;
326 mResult = result;
327 lock.unlock();
328 mCv.notify_all();
329 }
330
331 public:
wait(uint64_t seconds)332 void wait(uint64_t seconds) {
333 std::unique_lock<std::mutex> lock(mMutex);
334 mCv.wait_for(lock, std::chrono::seconds(seconds), [this] { return mFinished; });
335
336 if (!mFinished) {
337 LOG(WARNING) << "Dev GC on " << idl << " HAL timeout";
338 } else if (mResult != Result::SUCCESS) {
339 LOG(WARNING) << "Dev GC on " << idl << " HAL failed with " << toString(mResult);
340 } else {
341 LOG(INFO) << "Dev GC on " << idl << " HAL successful";
342 }
343 }
344
345 private:
346 std::mutex mMutex;
347 std::condition_variable mCv;
348 bool mFinished{false};
349 Result mResult{Result::UNKNOWN_ERROR};
350 };
351
352 class AGcCallbackImpl : public ABnGarbageCollectCallback,
353 public GcCallbackImpl<IDL::AIDL, AResult> {
onFinish(AResult result)354 ndk::ScopedAStatus onFinish(AResult result) override {
355 onFinishInternal(result);
356 return ndk::ScopedAStatus::ok();
357 }
358 };
359
360 class HGcCallbackImpl : public HGarbageCollectCallback, public GcCallbackImpl<IDL::HIDL, HResult> {
onFinish(HResult result)361 Return<void> onFinish(HResult result) override {
362 onFinishInternal(result);
363 return Void();
364 }
365 };
366
367 template <IDL idl, typename Service, typename GcCallbackImpl, typename GetDescription>
runDevGcOnHal(Service service,GcCallbackImpl cb,GetDescription get_description)368 static void runDevGcOnHal(Service service, GcCallbackImpl cb, GetDescription get_description) {
369 LOG(DEBUG) << "Start Dev GC on " << idl << " HAL";
370 auto ret = service->garbageCollect(DEVGC_TIMEOUT_SEC, cb);
371 if (!ret.isOk()) {
372 LOG(WARNING) << "Cannot start Dev GC on " << idl
373 << " HAL: " << std::invoke(get_description, ret);
374 return;
375 }
376 cb->wait(DEVGC_TIMEOUT_SEC);
377 }
378
runDevGc(void)379 static void runDevGc(void) {
380 auto aidl_service_name = AStorage::descriptor + "/default"s;
381 if (AServiceManager_isDeclared(aidl_service_name.c_str())) {
382 ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_service_name.c_str()));
383 if (binder.get() != nullptr) {
384 std::shared_ptr<AStorage> aidl_service = AStorage::fromBinder(binder);
385 if (aidl_service != nullptr) {
386 runDevGcOnHal<IDL::AIDL>(aidl_service, ndk::SharedRefBase::make<AGcCallbackImpl>(),
387 &ndk::ScopedAStatus::getDescription);
388 return;
389 }
390 }
391 LOG(WARNING) << "Device declares " << aidl_service_name
392 << " but it is not running, skip dev GC on AIDL HAL";
393 return;
394 }
395 auto hidl_service = HStorage::getService();
396 if (hidl_service != nullptr) {
397 runDevGcOnHal<IDL::HIDL>(hidl_service, sp<HGcCallbackImpl>(new HGcCallbackImpl()),
398 &Return<void>::description);
399 return;
400 }
401 // fallback to legacy code path
402 runDevGcFstab();
403 }
404
RunIdleMaint(const android::sp<android::os::IVoldTaskListener> & listener)405 int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
406 std::unique_lock<std::mutex> lk(cv_m);
407 if (idle_maint_stat != IdleMaintStats::kStopped) {
408 LOG(DEBUG) << "idle maintenance is already running";
409 if (listener) {
410 android::os::PersistableBundle extras;
411 listener->onFinished(0, extras);
412 }
413 return android::OK;
414 }
415 idle_maint_stat = IdleMaintStats::kRunning;
416 lk.unlock();
417
418 LOG(DEBUG) << "idle maintenance started";
419
420 auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
421 if (!wl.has_value()) {
422 return android::UNEXPECTED_NULL;
423 }
424
425 std::list<std::string> paths;
426 addFromFstab(&paths, PathTypes::kBlkDevice);
427 addFromVolumeManager(&paths, PathTypes::kBlkDevice);
428
429 startGc(paths);
430
431 bool gc_aborted = waitForGc(paths);
432
433 stopGc(paths);
434
435 lk.lock();
436 idle_maint_stat = IdleMaintStats::kStopped;
437 lk.unlock();
438
439 cv_stop.notify_one();
440
441 if (!gc_aborted) {
442 Trim(nullptr);
443 runDevGc();
444 }
445
446 if (listener) {
447 android::os::PersistableBundle extras;
448 listener->onFinished(0, extras);
449 }
450
451 LOG(DEBUG) << "idle maintenance completed";
452
453 return android::OK;
454 }
455
AbortIdleMaint(const android::sp<android::os::IVoldTaskListener> & listener)456 int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
457 auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
458 if (!wl.has_value()) {
459 return android::UNEXPECTED_NULL;
460 }
461
462 std::unique_lock<std::mutex> lk(cv_m);
463 if (idle_maint_stat != IdleMaintStats::kStopped) {
464 idle_maint_stat = IdleMaintStats::kAbort;
465 lk.unlock();
466 cv_abort.notify_one();
467 lk.lock();
468 LOG(DEBUG) << "aborting idle maintenance";
469 cv_stop.wait(lk, [] { return idle_maint_stat == IdleMaintStats::kStopped; });
470 }
471 lk.unlock();
472
473 if (listener) {
474 android::os::PersistableBundle extras;
475 listener->onFinished(0, extras);
476 }
477
478 LOG(DEBUG) << "idle maintenance stopped";
479
480 return android::OK;
481 }
482
483 } // namespace vold
484 } // namespace android
485