xref: /aosp_15_r20/system/vold/IdleMaint.cpp (revision f40fafd4c6c2594924d919feffc1a1fd6e3b30f3)
1*f40fafd4SAndroid Build Coastguard Worker /*
2*f40fafd4SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*f40fafd4SAndroid Build Coastguard Worker  *
4*f40fafd4SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*f40fafd4SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*f40fafd4SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*f40fafd4SAndroid Build Coastguard Worker  *
8*f40fafd4SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*f40fafd4SAndroid Build Coastguard Worker  *
10*f40fafd4SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*f40fafd4SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*f40fafd4SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f40fafd4SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*f40fafd4SAndroid Build Coastguard Worker  * limitations under the License.
15*f40fafd4SAndroid Build Coastguard Worker  */
16*f40fafd4SAndroid Build Coastguard Worker 
17*f40fafd4SAndroid Build Coastguard Worker #include "IdleMaint.h"
18*f40fafd4SAndroid Build Coastguard Worker #include "FileDeviceUtils.h"
19*f40fafd4SAndroid Build Coastguard Worker #include "Utils.h"
20*f40fafd4SAndroid Build Coastguard Worker #include "VoldUtil.h"
21*f40fafd4SAndroid Build Coastguard Worker #include "VolumeManager.h"
22*f40fafd4SAndroid Build Coastguard Worker #include "model/PrivateVolume.h"
23*f40fafd4SAndroid Build Coastguard Worker 
24*f40fafd4SAndroid Build Coastguard Worker #include <thread>
25*f40fafd4SAndroid Build Coastguard Worker #include <utility>
26*f40fafd4SAndroid Build Coastguard Worker 
27*f40fafd4SAndroid Build Coastguard Worker #include <aidl/android/hardware/health/storage/BnGarbageCollectCallback.h>
28*f40fafd4SAndroid Build Coastguard Worker #include <aidl/android/hardware/health/storage/IStorage.h>
29*f40fafd4SAndroid Build Coastguard Worker #include <android-base/chrono_utils.h>
30*f40fafd4SAndroid Build Coastguard Worker #include <android-base/file.h>
31*f40fafd4SAndroid Build Coastguard Worker #include <android-base/logging.h>
32*f40fafd4SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
33*f40fafd4SAndroid Build Coastguard Worker #include <android-base/strings.h>
34*f40fafd4SAndroid Build Coastguard Worker #include <android/binder_manager.h>
35*f40fafd4SAndroid Build Coastguard Worker #include <android/hardware/health/storage/1.0/IStorage.h>
36*f40fafd4SAndroid Build Coastguard Worker #include <fs_mgr.h>
37*f40fafd4SAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
38*f40fafd4SAndroid Build Coastguard Worker #include <wakelock/wakelock.h>
39*f40fafd4SAndroid Build Coastguard Worker 
40*f40fafd4SAndroid Build Coastguard Worker #include <dirent.h>
41*f40fafd4SAndroid Build Coastguard Worker #include <fcntl.h>
42*f40fafd4SAndroid Build Coastguard Worker #include <sys/mount.h>
43*f40fafd4SAndroid Build Coastguard Worker #include <sys/stat.h>
44*f40fafd4SAndroid Build Coastguard Worker #include <sys/types.h>
45*f40fafd4SAndroid Build Coastguard Worker #include <sys/wait.h>
46*f40fafd4SAndroid Build Coastguard Worker 
47*f40fafd4SAndroid Build Coastguard Worker using android::base::Basename;
48*f40fafd4SAndroid Build Coastguard Worker using android::base::ReadFileToString;
49*f40fafd4SAndroid Build Coastguard Worker using android::base::Realpath;
50*f40fafd4SAndroid Build Coastguard Worker using android::base::StringPrintf;
51*f40fafd4SAndroid Build Coastguard Worker using android::base::Timer;
52*f40fafd4SAndroid Build Coastguard Worker using android::base::WriteStringToFile;
53*f40fafd4SAndroid Build Coastguard Worker using android::hardware::Return;
54*f40fafd4SAndroid Build Coastguard Worker using android::hardware::Void;
55*f40fafd4SAndroid Build Coastguard Worker using AStorage = aidl::android::hardware::health::storage::IStorage;
56*f40fafd4SAndroid Build Coastguard Worker using ABnGarbageCollectCallback =
57*f40fafd4SAndroid Build Coastguard Worker         aidl::android::hardware::health::storage::BnGarbageCollectCallback;
58*f40fafd4SAndroid Build Coastguard Worker using AResult = aidl::android::hardware::health::storage::Result;
59*f40fafd4SAndroid Build Coastguard Worker using HStorage = android::hardware::health::storage::V1_0::IStorage;
60*f40fafd4SAndroid Build Coastguard Worker using HGarbageCollectCallback = android::hardware::health::storage::V1_0::IGarbageCollectCallback;
61*f40fafd4SAndroid Build Coastguard Worker using HResult = android::hardware::health::storage::V1_0::Result;
62*f40fafd4SAndroid Build Coastguard Worker using std::string_literals::operator""s;
63*f40fafd4SAndroid Build Coastguard Worker 
64*f40fafd4SAndroid Build Coastguard Worker namespace android {
65*f40fafd4SAndroid Build Coastguard Worker namespace vold {
66*f40fafd4SAndroid Build Coastguard Worker 
67*f40fafd4SAndroid Build Coastguard Worker enum class PathTypes {
68*f40fafd4SAndroid Build Coastguard Worker     kMountPoint = 1,
69*f40fafd4SAndroid Build Coastguard Worker     kBlkDevice,
70*f40fafd4SAndroid Build Coastguard Worker };
71*f40fafd4SAndroid Build Coastguard Worker 
72*f40fafd4SAndroid Build Coastguard Worker enum class IdleMaintStats {
73*f40fafd4SAndroid Build Coastguard Worker     kStopped = 1,
74*f40fafd4SAndroid Build Coastguard Worker     kRunning,
75*f40fafd4SAndroid Build Coastguard Worker     kAbort,
76*f40fafd4SAndroid Build Coastguard Worker };
77*f40fafd4SAndroid Build Coastguard Worker 
78*f40fafd4SAndroid Build Coastguard Worker static const char* kWakeLock = "IdleMaint";
79*f40fafd4SAndroid Build Coastguard Worker static const int DIRTY_SEGMENTS_THRESHOLD = 100;
80*f40fafd4SAndroid Build Coastguard Worker /*
81*f40fafd4SAndroid Build Coastguard Worker  * Timing policy:
82*f40fafd4SAndroid Build Coastguard Worker  *  1. F2FS_GC = 7 mins
83*f40fafd4SAndroid Build Coastguard Worker  *  2. Trim = 1 min
84*f40fafd4SAndroid Build Coastguard Worker  *  3. Dev GC = 2 mins
85*f40fafd4SAndroid Build Coastguard Worker  */
86*f40fafd4SAndroid Build Coastguard Worker static const int GC_TIMEOUT_SEC = 420;
87*f40fafd4SAndroid Build Coastguard Worker static const int DEVGC_TIMEOUT_SEC = 120;
88*f40fafd4SAndroid Build Coastguard Worker static const int KBYTES_IN_SEGMENT = 2048;
89*f40fafd4SAndroid Build Coastguard Worker static const int ONE_MINUTE_IN_MS = 60000;
90*f40fafd4SAndroid Build Coastguard Worker static const int GC_NORMAL_MODE = 0;
91*f40fafd4SAndroid Build Coastguard Worker static const int GC_URGENT_MID_MODE = 3;
92*f40fafd4SAndroid Build Coastguard Worker 
93*f40fafd4SAndroid Build Coastguard Worker static int32_t previousSegmentWrite = 0;
94*f40fafd4SAndroid Build Coastguard Worker 
95*f40fafd4SAndroid Build Coastguard Worker static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
96*f40fafd4SAndroid Build Coastguard Worker static std::condition_variable cv_abort, cv_stop;
97*f40fafd4SAndroid Build Coastguard Worker static std::mutex cv_m;
98*f40fafd4SAndroid Build Coastguard Worker 
addFromVolumeManager(std::list<std::string> * paths,PathTypes path_type)99*f40fafd4SAndroid Build Coastguard Worker static void addFromVolumeManager(std::list<std::string>* paths, PathTypes path_type) {
100*f40fafd4SAndroid Build Coastguard Worker     VolumeManager* vm = VolumeManager::Instance();
101*f40fafd4SAndroid Build Coastguard Worker     std::list<std::string> privateIds;
102*f40fafd4SAndroid Build Coastguard Worker     vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
103*f40fafd4SAndroid Build Coastguard Worker     for (const auto& id : privateIds) {
104*f40fafd4SAndroid Build Coastguard Worker         PrivateVolume* vol = static_cast<PrivateVolume*>(vm->findVolume(id).get());
105*f40fafd4SAndroid Build Coastguard Worker         if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
106*f40fafd4SAndroid Build Coastguard Worker             if (path_type == PathTypes::kMountPoint) {
107*f40fafd4SAndroid Build Coastguard Worker                 paths->push_back(vol->getPath());
108*f40fafd4SAndroid Build Coastguard Worker             } else if (path_type == PathTypes::kBlkDevice) {
109*f40fafd4SAndroid Build Coastguard Worker                 std::string gc_path;
110*f40fafd4SAndroid Build Coastguard Worker                 const std::string& fs_type = vol->getFsType();
111*f40fafd4SAndroid Build Coastguard Worker                 if (fs_type == "f2fs" && (Realpath(vol->getRawDmDevPath(), &gc_path) ||
112*f40fafd4SAndroid Build Coastguard Worker                                           Realpath(vol->getRawDevPath(), &gc_path))) {
113*f40fafd4SAndroid Build Coastguard Worker                     paths->push_back(std::string("/sys/fs/") + fs_type + "/" + Basename(gc_path));
114*f40fafd4SAndroid Build Coastguard Worker                 }
115*f40fafd4SAndroid Build Coastguard Worker             }
116*f40fafd4SAndroid Build Coastguard Worker         }
117*f40fafd4SAndroid Build Coastguard Worker     }
118*f40fafd4SAndroid Build Coastguard Worker }
119*f40fafd4SAndroid Build Coastguard Worker 
addFromFstab(std::list<std::string> * paths,PathTypes path_type,bool only_data_part)120*f40fafd4SAndroid Build Coastguard Worker static void addFromFstab(std::list<std::string>* paths, PathTypes path_type, bool only_data_part) {
121*f40fafd4SAndroid Build Coastguard Worker     std::string previous_mount_point;
122*f40fafd4SAndroid Build Coastguard Worker     for (const auto& entry : fstab_default) {
123*f40fafd4SAndroid Build Coastguard Worker         // Skip raw partitions and swap space.
124*f40fafd4SAndroid Build Coastguard Worker         if (entry.fs_type == "emmc" || entry.fs_type == "mtd" || entry.fs_type == "swap") {
125*f40fafd4SAndroid Build Coastguard Worker             continue;
126*f40fafd4SAndroid Build Coastguard Worker         }
127*f40fafd4SAndroid Build Coastguard Worker         // Skip read-only filesystems and bind mounts.
128*f40fafd4SAndroid Build Coastguard Worker         if (entry.flags & (MS_RDONLY | MS_BIND)) {
129*f40fafd4SAndroid Build Coastguard Worker             continue;
130*f40fafd4SAndroid Build Coastguard Worker         }
131*f40fafd4SAndroid Build Coastguard Worker         // Skip anything without an underlying block device, e.g. virtiofs.
132*f40fafd4SAndroid Build Coastguard Worker         if (entry.blk_device[0] != '/') {
133*f40fafd4SAndroid Build Coastguard Worker             continue;
134*f40fafd4SAndroid Build Coastguard Worker         }
135*f40fafd4SAndroid Build Coastguard Worker         if (entry.fs_mgr_flags.vold_managed) {
136*f40fafd4SAndroid Build Coastguard Worker             continue;  // Should we trim fat32 filesystems?
137*f40fafd4SAndroid Build Coastguard Worker         }
138*f40fafd4SAndroid Build Coastguard Worker         if (entry.fs_mgr_flags.no_trim) {
139*f40fafd4SAndroid Build Coastguard Worker             continue;
140*f40fafd4SAndroid Build Coastguard Worker         }
141*f40fafd4SAndroid Build Coastguard Worker 
142*f40fafd4SAndroid Build Coastguard Worker         if (only_data_part && entry.mount_point != "/data") {
143*f40fafd4SAndroid Build Coastguard Worker             continue;
144*f40fafd4SAndroid Build Coastguard Worker         }
145*f40fafd4SAndroid Build Coastguard Worker 
146*f40fafd4SAndroid Build Coastguard Worker         // Skip the multi-type partitions, which are required to be following each other.
147*f40fafd4SAndroid Build Coastguard Worker         // See fs_mgr.c's mount_with_alternatives().
148*f40fafd4SAndroid Build Coastguard Worker         if (entry.mount_point == previous_mount_point) {
149*f40fafd4SAndroid Build Coastguard Worker             continue;
150*f40fafd4SAndroid Build Coastguard Worker         }
151*f40fafd4SAndroid Build Coastguard Worker 
152*f40fafd4SAndroid Build Coastguard Worker         if (path_type == PathTypes::kMountPoint) {
153*f40fafd4SAndroid Build Coastguard Worker             paths->push_back(entry.mount_point);
154*f40fafd4SAndroid Build Coastguard Worker         } else if (path_type == PathTypes::kBlkDevice) {
155*f40fafd4SAndroid Build Coastguard Worker             std::string path;
156*f40fafd4SAndroid Build Coastguard Worker             if (entry.fs_type == "f2fs" &&
157*f40fafd4SAndroid Build Coastguard Worker                 Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &path)) {
158*f40fafd4SAndroid Build Coastguard Worker                 paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(path));
159*f40fafd4SAndroid Build Coastguard Worker             }
160*f40fafd4SAndroid Build Coastguard Worker         }
161*f40fafd4SAndroid Build Coastguard Worker 
162*f40fafd4SAndroid Build Coastguard Worker         previous_mount_point = entry.mount_point;
163*f40fafd4SAndroid Build Coastguard Worker     }
164*f40fafd4SAndroid Build Coastguard Worker }
165*f40fafd4SAndroid Build Coastguard Worker 
Trim(const android::sp<android::os::IVoldTaskListener> & listener)166*f40fafd4SAndroid Build Coastguard Worker void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
167*f40fafd4SAndroid Build Coastguard Worker     auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
168*f40fafd4SAndroid Build Coastguard Worker     if (!wl.has_value()) {
169*f40fafd4SAndroid Build Coastguard Worker         return;
170*f40fafd4SAndroid Build Coastguard Worker     }
171*f40fafd4SAndroid Build Coastguard Worker 
172*f40fafd4SAndroid Build Coastguard Worker     // Collect both fstab and vold volumes
173*f40fafd4SAndroid Build Coastguard Worker     std::list<std::string> paths;
174*f40fafd4SAndroid Build Coastguard Worker     addFromFstab(&paths, PathTypes::kMountPoint, false);
175*f40fafd4SAndroid Build Coastguard Worker     addFromVolumeManager(&paths, PathTypes::kMountPoint);
176*f40fafd4SAndroid Build Coastguard Worker 
177*f40fafd4SAndroid Build Coastguard Worker     for (const auto& path : paths) {
178*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "Starting trim of " << path;
179*f40fafd4SAndroid Build Coastguard Worker 
180*f40fafd4SAndroid Build Coastguard Worker         android::os::PersistableBundle extras;
181*f40fafd4SAndroid Build Coastguard Worker         extras.putString(String16("path"), String16(path.c_str()));
182*f40fafd4SAndroid Build Coastguard Worker 
183*f40fafd4SAndroid Build Coastguard Worker         int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
184*f40fafd4SAndroid Build Coastguard Worker         if (fd < 0) {
185*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Failed to open " << path;
186*f40fafd4SAndroid Build Coastguard Worker             if (listener) {
187*f40fafd4SAndroid Build Coastguard Worker                 listener->onStatus(-1, extras);
188*f40fafd4SAndroid Build Coastguard Worker             }
189*f40fafd4SAndroid Build Coastguard Worker             continue;
190*f40fafd4SAndroid Build Coastguard Worker         }
191*f40fafd4SAndroid Build Coastguard Worker 
192*f40fafd4SAndroid Build Coastguard Worker         struct fstrim_range range;
193*f40fafd4SAndroid Build Coastguard Worker         memset(&range, 0, sizeof(range));
194*f40fafd4SAndroid Build Coastguard Worker         range.len = ULLONG_MAX;
195*f40fafd4SAndroid Build Coastguard Worker 
196*f40fafd4SAndroid Build Coastguard Worker         nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
197*f40fafd4SAndroid Build Coastguard Worker         if (ioctl(fd, FITRIM, &range)) {
198*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Trim failed on " << path;
199*f40fafd4SAndroid Build Coastguard Worker             if (listener) {
200*f40fafd4SAndroid Build Coastguard Worker                 listener->onStatus(-1, extras);
201*f40fafd4SAndroid Build Coastguard Worker             }
202*f40fafd4SAndroid Build Coastguard Worker         } else {
203*f40fafd4SAndroid Build Coastguard Worker             nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
204*f40fafd4SAndroid Build Coastguard Worker             LOG(INFO) << "Trimmed " << range.len << " bytes on " << path << " in "
205*f40fafd4SAndroid Build Coastguard Worker                       << nanoseconds_to_milliseconds(time) << "ms";
206*f40fafd4SAndroid Build Coastguard Worker             extras.putLong(String16("bytes"), range.len);
207*f40fafd4SAndroid Build Coastguard Worker             extras.putLong(String16("time"), time);
208*f40fafd4SAndroid Build Coastguard Worker             if (listener) {
209*f40fafd4SAndroid Build Coastguard Worker                 listener->onStatus(0, extras);
210*f40fafd4SAndroid Build Coastguard Worker             }
211*f40fafd4SAndroid Build Coastguard Worker         }
212*f40fafd4SAndroid Build Coastguard Worker         close(fd);
213*f40fafd4SAndroid Build Coastguard Worker     }
214*f40fafd4SAndroid Build Coastguard Worker 
215*f40fafd4SAndroid Build Coastguard Worker     if (listener) {
216*f40fafd4SAndroid Build Coastguard Worker         android::os::PersistableBundle extras;
217*f40fafd4SAndroid Build Coastguard Worker         listener->onFinished(0, extras);
218*f40fafd4SAndroid Build Coastguard Worker     }
219*f40fafd4SAndroid Build Coastguard Worker 
220*f40fafd4SAndroid Build Coastguard Worker }
221*f40fafd4SAndroid Build Coastguard Worker 
waitForGc(const std::list<std::string> & paths)222*f40fafd4SAndroid Build Coastguard Worker static bool waitForGc(const std::list<std::string>& paths) {
223*f40fafd4SAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lk(cv_m, std::defer_lock);
224*f40fafd4SAndroid Build Coastguard Worker     bool stop = false, aborted = false;
225*f40fafd4SAndroid Build Coastguard Worker     Timer timer;
226*f40fafd4SAndroid Build Coastguard Worker 
227*f40fafd4SAndroid Build Coastguard Worker     while (!stop && !aborted) {
228*f40fafd4SAndroid Build Coastguard Worker         stop = true;
229*f40fafd4SAndroid Build Coastguard Worker         for (const auto& path : paths) {
230*f40fafd4SAndroid Build Coastguard Worker             std::string dirty_segments;
231*f40fafd4SAndroid Build Coastguard Worker             if (!ReadFileToString(path + "/dirty_segments", &dirty_segments)) {
232*f40fafd4SAndroid Build Coastguard Worker                 PLOG(WARNING) << "Reading dirty_segments failed in " << path;
233*f40fafd4SAndroid Build Coastguard Worker                 continue;
234*f40fafd4SAndroid Build Coastguard Worker             }
235*f40fafd4SAndroid Build Coastguard Worker             if (std::stoi(dirty_segments) > DIRTY_SEGMENTS_THRESHOLD) {
236*f40fafd4SAndroid Build Coastguard Worker                 stop = false;
237*f40fafd4SAndroid Build Coastguard Worker                 break;
238*f40fafd4SAndroid Build Coastguard Worker             }
239*f40fafd4SAndroid Build Coastguard Worker         }
240*f40fafd4SAndroid Build Coastguard Worker 
241*f40fafd4SAndroid Build Coastguard Worker         if (stop) break;
242*f40fafd4SAndroid Build Coastguard Worker 
243*f40fafd4SAndroid Build Coastguard Worker         if (timer.duration() >= std::chrono::seconds(GC_TIMEOUT_SEC)) {
244*f40fafd4SAndroid Build Coastguard Worker             LOG(WARNING) << "GC timeout";
245*f40fafd4SAndroid Build Coastguard Worker             break;
246*f40fafd4SAndroid Build Coastguard Worker         }
247*f40fafd4SAndroid Build Coastguard Worker 
248*f40fafd4SAndroid Build Coastguard Worker         lk.lock();
249*f40fafd4SAndroid Build Coastguard Worker         aborted =
250*f40fafd4SAndroid Build Coastguard Worker             cv_abort.wait_for(lk, 10s, [] { return idle_maint_stat == IdleMaintStats::kAbort; });
251*f40fafd4SAndroid Build Coastguard Worker         lk.unlock();
252*f40fafd4SAndroid Build Coastguard Worker     }
253*f40fafd4SAndroid Build Coastguard Worker 
254*f40fafd4SAndroid Build Coastguard Worker     return aborted;
255*f40fafd4SAndroid Build Coastguard Worker }
256*f40fafd4SAndroid Build Coastguard Worker 
startGc(const std::list<std::string> & paths)257*f40fafd4SAndroid Build Coastguard Worker static int startGc(const std::list<std::string>& paths) {
258*f40fafd4SAndroid Build Coastguard Worker     for (const auto& path : paths) {
259*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "Start GC on " << path;
260*f40fafd4SAndroid Build Coastguard Worker         if (!WriteStringToFile("1", path + "/gc_urgent")) {
261*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Start GC failed on " << path;
262*f40fafd4SAndroid Build Coastguard Worker         }
263*f40fafd4SAndroid Build Coastguard Worker     }
264*f40fafd4SAndroid Build Coastguard Worker     return android::OK;
265*f40fafd4SAndroid Build Coastguard Worker }
266*f40fafd4SAndroid Build Coastguard Worker 
stopGc(const std::list<std::string> & paths)267*f40fafd4SAndroid Build Coastguard Worker static int stopGc(const std::list<std::string>& paths) {
268*f40fafd4SAndroid Build Coastguard Worker     for (const auto& path : paths) {
269*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "Stop GC on " << path;
270*f40fafd4SAndroid Build Coastguard Worker         if (!WriteStringToFile("0", path + "/gc_urgent")) {
271*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Stop GC failed on " << path;
272*f40fafd4SAndroid Build Coastguard Worker         }
273*f40fafd4SAndroid Build Coastguard Worker     }
274*f40fafd4SAndroid Build Coastguard Worker     return android::OK;
275*f40fafd4SAndroid Build Coastguard Worker }
276*f40fafd4SAndroid Build Coastguard Worker 
getDevSysfsPath()277*f40fafd4SAndroid Build Coastguard Worker static std::string getDevSysfsPath() {
278*f40fafd4SAndroid Build Coastguard Worker     for (const auto& entry : fstab_default) {
279*f40fafd4SAndroid Build Coastguard Worker         if (!entry.sysfs_path.empty()) {
280*f40fafd4SAndroid Build Coastguard Worker             return entry.sysfs_path;
281*f40fafd4SAndroid Build Coastguard Worker         }
282*f40fafd4SAndroid Build Coastguard Worker     }
283*f40fafd4SAndroid Build Coastguard Worker     LOG(WARNING) << "Cannot find dev sysfs path";
284*f40fafd4SAndroid Build Coastguard Worker     return "";
285*f40fafd4SAndroid Build Coastguard Worker }
286*f40fafd4SAndroid Build Coastguard Worker 
runDevGcFstab(void)287*f40fafd4SAndroid Build Coastguard Worker static void runDevGcFstab(void) {
288*f40fafd4SAndroid Build Coastguard Worker     std::string path = getDevSysfsPath();
289*f40fafd4SAndroid Build Coastguard Worker     if (path.empty()) {
290*f40fafd4SAndroid Build Coastguard Worker         return;
291*f40fafd4SAndroid Build Coastguard Worker     }
292*f40fafd4SAndroid Build Coastguard Worker 
293*f40fafd4SAndroid Build Coastguard Worker     path = path + "/manual_gc";
294*f40fafd4SAndroid Build Coastguard Worker     Timer timer;
295*f40fafd4SAndroid Build Coastguard Worker 
296*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "Start Dev GC on " << path;
297*f40fafd4SAndroid Build Coastguard Worker     while (1) {
298*f40fafd4SAndroid Build Coastguard Worker         std::string require;
299*f40fafd4SAndroid Build Coastguard Worker         if (!ReadFileToString(path, &require)) {
300*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Reading manual_gc failed in " << path;
301*f40fafd4SAndroid Build Coastguard Worker             break;
302*f40fafd4SAndroid Build Coastguard Worker         }
303*f40fafd4SAndroid Build Coastguard Worker         require = android::base::Trim(require);
304*f40fafd4SAndroid Build Coastguard Worker         if (require == "" || require == "off" || require == "disabled") {
305*f40fafd4SAndroid Build Coastguard Worker             LOG(DEBUG) << "No more to do Dev GC";
306*f40fafd4SAndroid Build Coastguard Worker             break;
307*f40fafd4SAndroid Build Coastguard Worker         }
308*f40fafd4SAndroid Build Coastguard Worker 
309*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "Trigger Dev GC on " << path;
310*f40fafd4SAndroid Build Coastguard Worker         if (!WriteStringToFile("1", path)) {
311*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Start Dev GC failed on " << path;
312*f40fafd4SAndroid Build Coastguard Worker             break;
313*f40fafd4SAndroid Build Coastguard Worker         }
314*f40fafd4SAndroid Build Coastguard Worker 
315*f40fafd4SAndroid Build Coastguard Worker         if (timer.duration() >= std::chrono::seconds(DEVGC_TIMEOUT_SEC)) {
316*f40fafd4SAndroid Build Coastguard Worker             LOG(WARNING) << "Dev GC timeout";
317*f40fafd4SAndroid Build Coastguard Worker             break;
318*f40fafd4SAndroid Build Coastguard Worker         }
319*f40fafd4SAndroid Build Coastguard Worker         sleep(2);
320*f40fafd4SAndroid Build Coastguard Worker     }
321*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "Stop Dev GC on " << path;
322*f40fafd4SAndroid Build Coastguard Worker     if (!WriteStringToFile("0", path)) {
323*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Stop Dev GC failed on " << path;
324*f40fafd4SAndroid Build Coastguard Worker     }
325*f40fafd4SAndroid Build Coastguard Worker     return;
326*f40fafd4SAndroid Build Coastguard Worker }
327*f40fafd4SAndroid Build Coastguard Worker 
328*f40fafd4SAndroid Build Coastguard Worker enum class IDL { HIDL, AIDL };
operator <<(std::ostream & os,IDL idl)329*f40fafd4SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, IDL idl) {
330*f40fafd4SAndroid Build Coastguard Worker     return os << (idl == IDL::HIDL ? "HIDL" : "AIDL");
331*f40fafd4SAndroid Build Coastguard Worker }
332*f40fafd4SAndroid Build Coastguard Worker 
333*f40fafd4SAndroid Build Coastguard Worker template <IDL idl, typename Result>
334*f40fafd4SAndroid Build Coastguard Worker class GcCallbackImpl {
335*f40fafd4SAndroid Build Coastguard Worker   protected:
onFinishInternal(Result result)336*f40fafd4SAndroid Build Coastguard Worker     void onFinishInternal(Result result) {
337*f40fafd4SAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mMutex);
338*f40fafd4SAndroid Build Coastguard Worker         mFinished = true;
339*f40fafd4SAndroid Build Coastguard Worker         mResult = result;
340*f40fafd4SAndroid Build Coastguard Worker         lock.unlock();
341*f40fafd4SAndroid Build Coastguard Worker         mCv.notify_all();
342*f40fafd4SAndroid Build Coastguard Worker     }
343*f40fafd4SAndroid Build Coastguard Worker 
344*f40fafd4SAndroid Build Coastguard Worker   public:
wait(uint64_t seconds)345*f40fafd4SAndroid Build Coastguard Worker     void wait(uint64_t seconds) {
346*f40fafd4SAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lock(mMutex);
347*f40fafd4SAndroid Build Coastguard Worker         mCv.wait_for(lock, std::chrono::seconds(seconds), [this] { return mFinished; });
348*f40fafd4SAndroid Build Coastguard Worker 
349*f40fafd4SAndroid Build Coastguard Worker         if (!mFinished) {
350*f40fafd4SAndroid Build Coastguard Worker             LOG(WARNING) << "Dev GC on " << idl << " HAL timeout";
351*f40fafd4SAndroid Build Coastguard Worker         } else if (mResult != Result::SUCCESS) {
352*f40fafd4SAndroid Build Coastguard Worker             LOG(WARNING) << "Dev GC on " << idl << " HAL failed with " << toString(mResult);
353*f40fafd4SAndroid Build Coastguard Worker         } else {
354*f40fafd4SAndroid Build Coastguard Worker             LOG(INFO) << "Dev GC on " << idl << " HAL successful";
355*f40fafd4SAndroid Build Coastguard Worker         }
356*f40fafd4SAndroid Build Coastguard Worker     }
357*f40fafd4SAndroid Build Coastguard Worker 
358*f40fafd4SAndroid Build Coastguard Worker   private:
359*f40fafd4SAndroid Build Coastguard Worker     std::mutex mMutex;
360*f40fafd4SAndroid Build Coastguard Worker     std::condition_variable mCv;
361*f40fafd4SAndroid Build Coastguard Worker     bool mFinished{false};
362*f40fafd4SAndroid Build Coastguard Worker     Result mResult{Result::UNKNOWN_ERROR};
363*f40fafd4SAndroid Build Coastguard Worker };
364*f40fafd4SAndroid Build Coastguard Worker 
365*f40fafd4SAndroid Build Coastguard Worker class AGcCallbackImpl : public ABnGarbageCollectCallback,
366*f40fafd4SAndroid Build Coastguard Worker                         public GcCallbackImpl<IDL::AIDL, AResult> {
onFinish(AResult result)367*f40fafd4SAndroid Build Coastguard Worker     ndk::ScopedAStatus onFinish(AResult result) override {
368*f40fafd4SAndroid Build Coastguard Worker         onFinishInternal(result);
369*f40fafd4SAndroid Build Coastguard Worker         return ndk::ScopedAStatus::ok();
370*f40fafd4SAndroid Build Coastguard Worker     }
371*f40fafd4SAndroid Build Coastguard Worker };
372*f40fafd4SAndroid Build Coastguard Worker 
373*f40fafd4SAndroid Build Coastguard Worker class HGcCallbackImpl : public HGarbageCollectCallback, public GcCallbackImpl<IDL::HIDL, HResult> {
onFinish(HResult result)374*f40fafd4SAndroid Build Coastguard Worker     Return<void> onFinish(HResult result) override {
375*f40fafd4SAndroid Build Coastguard Worker         onFinishInternal(result);
376*f40fafd4SAndroid Build Coastguard Worker         return Void();
377*f40fafd4SAndroid Build Coastguard Worker     }
378*f40fafd4SAndroid Build Coastguard Worker };
379*f40fafd4SAndroid Build Coastguard Worker 
380*f40fafd4SAndroid Build Coastguard Worker template <IDL idl, typename Service, typename GcCallbackImpl, typename GetDescription>
runDevGcOnHal(Service service,GcCallbackImpl cb,GetDescription get_description)381*f40fafd4SAndroid Build Coastguard Worker static void runDevGcOnHal(Service service, GcCallbackImpl cb, GetDescription get_description) {
382*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "Start Dev GC on " << idl << " HAL";
383*f40fafd4SAndroid Build Coastguard Worker     auto ret = service->garbageCollect(DEVGC_TIMEOUT_SEC, cb);
384*f40fafd4SAndroid Build Coastguard Worker     if (!ret.isOk()) {
385*f40fafd4SAndroid Build Coastguard Worker         LOG(WARNING) << "Cannot start Dev GC on " << idl
386*f40fafd4SAndroid Build Coastguard Worker                      << " HAL: " << std::invoke(get_description, ret);
387*f40fafd4SAndroid Build Coastguard Worker         return;
388*f40fafd4SAndroid Build Coastguard Worker     }
389*f40fafd4SAndroid Build Coastguard Worker     cb->wait(DEVGC_TIMEOUT_SEC);
390*f40fafd4SAndroid Build Coastguard Worker }
391*f40fafd4SAndroid Build Coastguard Worker 
runDevGc(void)392*f40fafd4SAndroid Build Coastguard Worker static void runDevGc(void) {
393*f40fafd4SAndroid Build Coastguard Worker     runDevGcFstab();
394*f40fafd4SAndroid Build Coastguard Worker }
395*f40fafd4SAndroid Build Coastguard Worker 
RunIdleMaint(bool needGC,const android::sp<android::os::IVoldTaskListener> & listener)396*f40fafd4SAndroid Build Coastguard Worker int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
397*f40fafd4SAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lk(cv_m);
398*f40fafd4SAndroid Build Coastguard Worker     bool gc_aborted = false;
399*f40fafd4SAndroid Build Coastguard Worker 
400*f40fafd4SAndroid Build Coastguard Worker     if (idle_maint_stat != IdleMaintStats::kStopped) {
401*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "idle maintenance is already running";
402*f40fafd4SAndroid Build Coastguard Worker         if (listener) {
403*f40fafd4SAndroid Build Coastguard Worker             android::os::PersistableBundle extras;
404*f40fafd4SAndroid Build Coastguard Worker             listener->onFinished(0, extras);
405*f40fafd4SAndroid Build Coastguard Worker         }
406*f40fafd4SAndroid Build Coastguard Worker         return android::OK;
407*f40fafd4SAndroid Build Coastguard Worker     }
408*f40fafd4SAndroid Build Coastguard Worker     idle_maint_stat = IdleMaintStats::kRunning;
409*f40fafd4SAndroid Build Coastguard Worker     lk.unlock();
410*f40fafd4SAndroid Build Coastguard Worker 
411*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "idle maintenance started";
412*f40fafd4SAndroid Build Coastguard Worker 
413*f40fafd4SAndroid Build Coastguard Worker     auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
414*f40fafd4SAndroid Build Coastguard Worker     if (!wl.has_value()) {
415*f40fafd4SAndroid Build Coastguard Worker         return android::UNEXPECTED_NULL;
416*f40fafd4SAndroid Build Coastguard Worker     }
417*f40fafd4SAndroid Build Coastguard Worker 
418*f40fafd4SAndroid Build Coastguard Worker     if (needGC) {
419*f40fafd4SAndroid Build Coastguard Worker         std::list<std::string> paths;
420*f40fafd4SAndroid Build Coastguard Worker         addFromFstab(&paths, PathTypes::kBlkDevice, false);
421*f40fafd4SAndroid Build Coastguard Worker         addFromVolumeManager(&paths, PathTypes::kBlkDevice);
422*f40fafd4SAndroid Build Coastguard Worker 
423*f40fafd4SAndroid Build Coastguard Worker         startGc(paths);
424*f40fafd4SAndroid Build Coastguard Worker 
425*f40fafd4SAndroid Build Coastguard Worker         gc_aborted = waitForGc(paths);
426*f40fafd4SAndroid Build Coastguard Worker 
427*f40fafd4SAndroid Build Coastguard Worker         stopGc(paths);
428*f40fafd4SAndroid Build Coastguard Worker     }
429*f40fafd4SAndroid Build Coastguard Worker 
430*f40fafd4SAndroid Build Coastguard Worker     if (!gc_aborted) {
431*f40fafd4SAndroid Build Coastguard Worker         Trim(nullptr);
432*f40fafd4SAndroid Build Coastguard Worker         runDevGc();
433*f40fafd4SAndroid Build Coastguard Worker     }
434*f40fafd4SAndroid Build Coastguard Worker 
435*f40fafd4SAndroid Build Coastguard Worker     lk.lock();
436*f40fafd4SAndroid Build Coastguard Worker     idle_maint_stat = IdleMaintStats::kStopped;
437*f40fafd4SAndroid Build Coastguard Worker     lk.unlock();
438*f40fafd4SAndroid Build Coastguard Worker 
439*f40fafd4SAndroid Build Coastguard Worker     cv_stop.notify_all();
440*f40fafd4SAndroid Build Coastguard Worker 
441*f40fafd4SAndroid Build Coastguard Worker     if (listener) {
442*f40fafd4SAndroid Build Coastguard Worker         android::os::PersistableBundle extras;
443*f40fafd4SAndroid Build Coastguard Worker         listener->onFinished(0, extras);
444*f40fafd4SAndroid Build Coastguard Worker     }
445*f40fafd4SAndroid Build Coastguard Worker 
446*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "idle maintenance completed";
447*f40fafd4SAndroid Build Coastguard Worker 
448*f40fafd4SAndroid Build Coastguard Worker     return android::OK;
449*f40fafd4SAndroid Build Coastguard Worker }
450*f40fafd4SAndroid Build Coastguard Worker 
AbortIdleMaint(const android::sp<android::os::IVoldTaskListener> & listener)451*f40fafd4SAndroid Build Coastguard Worker int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
452*f40fafd4SAndroid Build Coastguard Worker     auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
453*f40fafd4SAndroid Build Coastguard Worker     if (!wl.has_value()) {
454*f40fafd4SAndroid Build Coastguard Worker         return android::UNEXPECTED_NULL;
455*f40fafd4SAndroid Build Coastguard Worker     }
456*f40fafd4SAndroid Build Coastguard Worker 
457*f40fafd4SAndroid Build Coastguard Worker     std::unique_lock<std::mutex> lk(cv_m);
458*f40fafd4SAndroid Build Coastguard Worker     if (idle_maint_stat != IdleMaintStats::kStopped) {
459*f40fafd4SAndroid Build Coastguard Worker         idle_maint_stat = IdleMaintStats::kAbort;
460*f40fafd4SAndroid Build Coastguard Worker         lk.unlock();
461*f40fafd4SAndroid Build Coastguard Worker         cv_abort.notify_one();
462*f40fafd4SAndroid Build Coastguard Worker         lk.lock();
463*f40fafd4SAndroid Build Coastguard Worker         LOG(DEBUG) << "aborting idle maintenance";
464*f40fafd4SAndroid Build Coastguard Worker         cv_stop.wait(lk, [] { return idle_maint_stat == IdleMaintStats::kStopped; });
465*f40fafd4SAndroid Build Coastguard Worker     }
466*f40fafd4SAndroid Build Coastguard Worker     lk.unlock();
467*f40fafd4SAndroid Build Coastguard Worker 
468*f40fafd4SAndroid Build Coastguard Worker     if (listener) {
469*f40fafd4SAndroid Build Coastguard Worker         android::os::PersistableBundle extras;
470*f40fafd4SAndroid Build Coastguard Worker         listener->onFinished(0, extras);
471*f40fafd4SAndroid Build Coastguard Worker     }
472*f40fafd4SAndroid Build Coastguard Worker 
473*f40fafd4SAndroid Build Coastguard Worker     LOG(DEBUG) << "idle maintenance stopped";
474*f40fafd4SAndroid Build Coastguard Worker 
475*f40fafd4SAndroid Build Coastguard Worker     return android::OK;
476*f40fafd4SAndroid Build Coastguard Worker }
477*f40fafd4SAndroid Build Coastguard Worker 
getLifeTime(const std::string & path)478*f40fafd4SAndroid Build Coastguard Worker int getLifeTime(const std::string& path) {
479*f40fafd4SAndroid Build Coastguard Worker     std::string result;
480*f40fafd4SAndroid Build Coastguard Worker 
481*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(path, &result)) {
482*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Reading lifetime estimation failed for " << path;
483*f40fafd4SAndroid Build Coastguard Worker         return -1;
484*f40fafd4SAndroid Build Coastguard Worker     }
485*f40fafd4SAndroid Build Coastguard Worker     return std::stoi(result, 0, 16);
486*f40fafd4SAndroid Build Coastguard Worker }
487*f40fafd4SAndroid Build Coastguard Worker 
GetStorageLifeTime()488*f40fafd4SAndroid Build Coastguard Worker int32_t GetStorageLifeTime() {
489*f40fafd4SAndroid Build Coastguard Worker     std::string path = getDevSysfsPath();
490*f40fafd4SAndroid Build Coastguard Worker     if (path.empty()) {
491*f40fafd4SAndroid Build Coastguard Worker         return -1;
492*f40fafd4SAndroid Build Coastguard Worker     }
493*f40fafd4SAndroid Build Coastguard Worker 
494*f40fafd4SAndroid Build Coastguard Worker     std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
495*f40fafd4SAndroid Build Coastguard Worker 
496*f40fafd4SAndroid Build Coastguard Worker     int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
497*f40fafd4SAndroid Build Coastguard Worker     if (lifeTime != -1) {
498*f40fafd4SAndroid Build Coastguard Worker         return lifeTime;
499*f40fafd4SAndroid Build Coastguard Worker     }
500*f40fafd4SAndroid Build Coastguard Worker 
501*f40fafd4SAndroid Build Coastguard Worker     int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
502*f40fafd4SAndroid Build Coastguard Worker     int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
503*f40fafd4SAndroid Build Coastguard Worker     lifeTime = std::max(lifeTimeA, lifeTimeB);
504*f40fafd4SAndroid Build Coastguard Worker     if (lifeTime != -1) {
505*f40fafd4SAndroid Build Coastguard Worker         return lifeTime == 0 ? -1 : lifeTime * 10;
506*f40fafd4SAndroid Build Coastguard Worker     }
507*f40fafd4SAndroid Build Coastguard Worker     return -1;
508*f40fafd4SAndroid Build Coastguard Worker }
509*f40fafd4SAndroid Build Coastguard Worker 
GetStorageRemainingLifetime()510*f40fafd4SAndroid Build Coastguard Worker int32_t GetStorageRemainingLifetime() {
511*f40fafd4SAndroid Build Coastguard Worker     std::string path = getDevSysfsPath();
512*f40fafd4SAndroid Build Coastguard Worker     if (path.empty()) {
513*f40fafd4SAndroid Build Coastguard Worker         return -1;
514*f40fafd4SAndroid Build Coastguard Worker     }
515*f40fafd4SAndroid Build Coastguard Worker 
516*f40fafd4SAndroid Build Coastguard Worker     std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
517*f40fafd4SAndroid Build Coastguard Worker 
518*f40fafd4SAndroid Build Coastguard Worker     int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
519*f40fafd4SAndroid Build Coastguard Worker     if (lifeTime == -1) {
520*f40fafd4SAndroid Build Coastguard Worker         int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
521*f40fafd4SAndroid Build Coastguard Worker         int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
522*f40fafd4SAndroid Build Coastguard Worker         lifeTime = std::max(lifeTimeA, lifeTimeB);
523*f40fafd4SAndroid Build Coastguard Worker         if (lifeTime <= 0) {
524*f40fafd4SAndroid Build Coastguard Worker             return -1;
525*f40fafd4SAndroid Build Coastguard Worker         }
526*f40fafd4SAndroid Build Coastguard Worker 
527*f40fafd4SAndroid Build Coastguard Worker         // 1 = 0-10% used, 10 = 90-100% used. Subtract 1 so that a brand new
528*f40fafd4SAndroid Build Coastguard Worker         // device looks 0% used.
529*f40fafd4SAndroid Build Coastguard Worker         lifeTime = (lifeTime - 1) * 10;
530*f40fafd4SAndroid Build Coastguard Worker     }
531*f40fafd4SAndroid Build Coastguard Worker     return 100 - std::clamp(lifeTime, 0, 100);
532*f40fafd4SAndroid Build Coastguard Worker }
533*f40fafd4SAndroid Build Coastguard Worker 
SetGCUrgentPace(int32_t neededSegments,int32_t minSegmentThreshold,float dirtyReclaimRate,float reclaimWeight,int32_t gcPeriod,int32_t minGCSleepTime,int32_t targetDirtyRatio)534*f40fafd4SAndroid Build Coastguard Worker void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
535*f40fafd4SAndroid Build Coastguard Worker                      float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime,
536*f40fafd4SAndroid Build Coastguard Worker                      int32_t targetDirtyRatio) {
537*f40fafd4SAndroid Build Coastguard Worker     std::list<std::string> paths;
538*f40fafd4SAndroid Build Coastguard Worker     bool needGC = false;
539*f40fafd4SAndroid Build Coastguard Worker     int32_t sleepTime;
540*f40fafd4SAndroid Build Coastguard Worker 
541*f40fafd4SAndroid Build Coastguard Worker     addFromFstab(&paths, PathTypes::kBlkDevice, true);
542*f40fafd4SAndroid Build Coastguard Worker     if (paths.empty()) {
543*f40fafd4SAndroid Build Coastguard Worker         LOG(WARNING) << "There is no valid blk device path for data partition";
544*f40fafd4SAndroid Build Coastguard Worker         return;
545*f40fafd4SAndroid Build Coastguard Worker     }
546*f40fafd4SAndroid Build Coastguard Worker 
547*f40fafd4SAndroid Build Coastguard Worker     std::string f2fsSysfsPath = paths.front();
548*f40fafd4SAndroid Build Coastguard Worker     std::string freeSegmentsPath = f2fsSysfsPath + "/free_segments";
549*f40fafd4SAndroid Build Coastguard Worker     std::string dirtySegmentsPath = f2fsSysfsPath + "/dirty_segments";
550*f40fafd4SAndroid Build Coastguard Worker     std::string gcSleepTimePath = f2fsSysfsPath + "/gc_urgent_sleep_time";
551*f40fafd4SAndroid Build Coastguard Worker     std::string gcUrgentModePath = f2fsSysfsPath + "/gc_urgent";
552*f40fafd4SAndroid Build Coastguard Worker     std::string ovpSegmentsPath = f2fsSysfsPath + "/ovp_segments";
553*f40fafd4SAndroid Build Coastguard Worker     std::string reservedBlocksPath = f2fsSysfsPath + "/reserved_blocks";
554*f40fafd4SAndroid Build Coastguard Worker     std::string freeSegmentsStr, dirtySegmentsStr, ovpSegmentsStr, reservedBlocksStr;
555*f40fafd4SAndroid Build Coastguard Worker 
556*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(freeSegmentsPath, &freeSegmentsStr)) {
557*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Reading failed in " << freeSegmentsPath;
558*f40fafd4SAndroid Build Coastguard Worker         return;
559*f40fafd4SAndroid Build Coastguard Worker     }
560*f40fafd4SAndroid Build Coastguard Worker 
561*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(dirtySegmentsPath, &dirtySegmentsStr)) {
562*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Reading failed in " << dirtySegmentsPath;
563*f40fafd4SAndroid Build Coastguard Worker         return;
564*f40fafd4SAndroid Build Coastguard Worker     }
565*f40fafd4SAndroid Build Coastguard Worker 
566*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(ovpSegmentsPath, &ovpSegmentsStr)) {
567*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Reading failed in " << ovpSegmentsPath;
568*f40fafd4SAndroid Build Coastguard Worker             return;
569*f40fafd4SAndroid Build Coastguard Worker         }
570*f40fafd4SAndroid Build Coastguard Worker 
571*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(reservedBlocksPath, &reservedBlocksStr)) {
572*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Reading failed in " << reservedBlocksPath;
573*f40fafd4SAndroid Build Coastguard Worker             return;
574*f40fafd4SAndroid Build Coastguard Worker         }
575*f40fafd4SAndroid Build Coastguard Worker 
576*f40fafd4SAndroid Build Coastguard Worker     int32_t freeSegments = std::stoi(freeSegmentsStr);
577*f40fafd4SAndroid Build Coastguard Worker     int32_t dirtySegments = std::stoi(dirtySegmentsStr);
578*f40fafd4SAndroid Build Coastguard Worker     int32_t reservedSegments = std::stoi(ovpSegmentsStr) + std::stoi(reservedBlocksStr) / 512;
579*f40fafd4SAndroid Build Coastguard Worker 
580*f40fafd4SAndroid Build Coastguard Worker     freeSegments = freeSegments > reservedSegments ? freeSegments - reservedSegments : 0;
581*f40fafd4SAndroid Build Coastguard Worker     int32_t totalSegments = freeSegments + dirtySegments;
582*f40fafd4SAndroid Build Coastguard Worker     int32_t finalTargetSegments = 0;
583*f40fafd4SAndroid Build Coastguard Worker 
584*f40fafd4SAndroid Build Coastguard Worker     if (totalSegments < minSegmentThreshold) {
585*f40fafd4SAndroid Build Coastguard Worker         LOG(INFO) << "The sum of free segments: " << freeSegments
586*f40fafd4SAndroid Build Coastguard Worker                   << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
587*f40fafd4SAndroid Build Coastguard Worker     } else {
588*f40fafd4SAndroid Build Coastguard Worker         int32_t dirtyRatio = dirtySegments * 100 / totalSegments;
589*f40fafd4SAndroid Build Coastguard Worker         int32_t neededForTargetRatio =
590*f40fafd4SAndroid Build Coastguard Worker                 (dirtyRatio > targetDirtyRatio)
591*f40fafd4SAndroid Build Coastguard Worker                         ? totalSegments * (dirtyRatio - targetDirtyRatio) / 100
592*f40fafd4SAndroid Build Coastguard Worker                         : 0;
593*f40fafd4SAndroid Build Coastguard Worker         neededSegments *= reclaimWeight;
594*f40fafd4SAndroid Build Coastguard Worker         neededSegments = (neededSegments > freeSegments) ? neededSegments - freeSegments : 0;
595*f40fafd4SAndroid Build Coastguard Worker 
596*f40fafd4SAndroid Build Coastguard Worker         finalTargetSegments = std::max(neededSegments, neededForTargetRatio);
597*f40fafd4SAndroid Build Coastguard Worker         if (finalTargetSegments == 0) {
598*f40fafd4SAndroid Build Coastguard Worker             LOG(INFO) << "Enough free segments: " << freeSegments;
599*f40fafd4SAndroid Build Coastguard Worker         } else {
600*f40fafd4SAndroid Build Coastguard Worker             finalTargetSegments =
601*f40fafd4SAndroid Build Coastguard Worker                     std::min(finalTargetSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
602*f40fafd4SAndroid Build Coastguard Worker             if (finalTargetSegments == 0) {
603*f40fafd4SAndroid Build Coastguard Worker                 LOG(INFO) << "Low dirty segments: " << dirtySegments;
604*f40fafd4SAndroid Build Coastguard Worker             } else if (neededSegments >= neededForTargetRatio) {
605*f40fafd4SAndroid Build Coastguard Worker                 LOG(INFO) << "Trigger GC, because of needed segments exceeding free segments";
606*f40fafd4SAndroid Build Coastguard Worker                 needGC = true;
607*f40fafd4SAndroid Build Coastguard Worker             } else {
608*f40fafd4SAndroid Build Coastguard Worker                 LOG(INFO) << "Trigger GC for target dirty ratio diff of: "
609*f40fafd4SAndroid Build Coastguard Worker                           << dirtyRatio - targetDirtyRatio;
610*f40fafd4SAndroid Build Coastguard Worker                 needGC = true;
611*f40fafd4SAndroid Build Coastguard Worker             }
612*f40fafd4SAndroid Build Coastguard Worker         }
613*f40fafd4SAndroid Build Coastguard Worker     }
614*f40fafd4SAndroid Build Coastguard Worker 
615*f40fafd4SAndroid Build Coastguard Worker     if (!needGC) {
616*f40fafd4SAndroid Build Coastguard Worker         if (!WriteStringToFile(std::to_string(GC_NORMAL_MODE), gcUrgentModePath)) {
617*f40fafd4SAndroid Build Coastguard Worker             PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
618*f40fafd4SAndroid Build Coastguard Worker         }
619*f40fafd4SAndroid Build Coastguard Worker         return;
620*f40fafd4SAndroid Build Coastguard Worker     }
621*f40fafd4SAndroid Build Coastguard Worker 
622*f40fafd4SAndroid Build Coastguard Worker     sleepTime = gcPeriod * ONE_MINUTE_IN_MS / finalTargetSegments;
623*f40fafd4SAndroid Build Coastguard Worker     if (sleepTime < minGCSleepTime) {
624*f40fafd4SAndroid Build Coastguard Worker         sleepTime = minGCSleepTime;
625*f40fafd4SAndroid Build Coastguard Worker     }
626*f40fafd4SAndroid Build Coastguard Worker 
627*f40fafd4SAndroid Build Coastguard Worker     if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
628*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
629*f40fafd4SAndroid Build Coastguard Worker         return;
630*f40fafd4SAndroid Build Coastguard Worker     }
631*f40fafd4SAndroid Build Coastguard Worker 
632*f40fafd4SAndroid Build Coastguard Worker     if (!WriteStringToFile(std::to_string(GC_URGENT_MID_MODE), gcUrgentModePath)) {
633*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
634*f40fafd4SAndroid Build Coastguard Worker         return;
635*f40fafd4SAndroid Build Coastguard Worker     }
636*f40fafd4SAndroid Build Coastguard Worker 
637*f40fafd4SAndroid Build Coastguard Worker     LOG(INFO) << "Successfully set gc urgent mode: "
638*f40fafd4SAndroid Build Coastguard Worker               << "free segments: " << freeSegments << ", reclaim target: " << finalTargetSegments
639*f40fafd4SAndroid Build Coastguard Worker               << ", sleep time: " << sleepTime;
640*f40fafd4SAndroid Build Coastguard Worker }
641*f40fafd4SAndroid Build Coastguard Worker 
getLifeTimeWrite()642*f40fafd4SAndroid Build Coastguard Worker static int32_t getLifeTimeWrite() {
643*f40fafd4SAndroid Build Coastguard Worker     std::list<std::string> paths;
644*f40fafd4SAndroid Build Coastguard Worker     addFromFstab(&paths, PathTypes::kBlkDevice, true);
645*f40fafd4SAndroid Build Coastguard Worker     if (paths.empty()) {
646*f40fafd4SAndroid Build Coastguard Worker         LOG(WARNING) << "There is no valid blk device path for data partition";
647*f40fafd4SAndroid Build Coastguard Worker         return -1;
648*f40fafd4SAndroid Build Coastguard Worker     }
649*f40fafd4SAndroid Build Coastguard Worker 
650*f40fafd4SAndroid Build Coastguard Worker     std::string writeKbytesPath = paths.front() + "/lifetime_write_kbytes";
651*f40fafd4SAndroid Build Coastguard Worker     std::string writeKbytesStr;
652*f40fafd4SAndroid Build Coastguard Worker     if (!ReadFileToString(writeKbytesPath, &writeKbytesStr)) {
653*f40fafd4SAndroid Build Coastguard Worker         PLOG(WARNING) << "Reading failed in " << writeKbytesPath;
654*f40fafd4SAndroid Build Coastguard Worker         return -1;
655*f40fafd4SAndroid Build Coastguard Worker     }
656*f40fafd4SAndroid Build Coastguard Worker 
657*f40fafd4SAndroid Build Coastguard Worker     unsigned long long writeBytes = std::strtoull(writeKbytesStr.c_str(), NULL, 0);
658*f40fafd4SAndroid Build Coastguard Worker     /* Careful: values > LLONG_MAX can appear in the file due to a kernel bug. */
659*f40fafd4SAndroid Build Coastguard Worker     if (writeBytes / KBYTES_IN_SEGMENT > INT32_MAX) {
660*f40fafd4SAndroid Build Coastguard Worker         LOG(WARNING) << "Bad lifetime_write_kbytes: " << writeKbytesStr;
661*f40fafd4SAndroid Build Coastguard Worker         return -1;
662*f40fafd4SAndroid Build Coastguard Worker     }
663*f40fafd4SAndroid Build Coastguard Worker     return writeBytes / KBYTES_IN_SEGMENT;
664*f40fafd4SAndroid Build Coastguard Worker }
665*f40fafd4SAndroid Build Coastguard Worker 
RefreshLatestWrite()666*f40fafd4SAndroid Build Coastguard Worker void RefreshLatestWrite() {
667*f40fafd4SAndroid Build Coastguard Worker     int32_t segmentWrite = getLifeTimeWrite();
668*f40fafd4SAndroid Build Coastguard Worker     if (segmentWrite != -1) {
669*f40fafd4SAndroid Build Coastguard Worker         previousSegmentWrite = segmentWrite;
670*f40fafd4SAndroid Build Coastguard Worker     }
671*f40fafd4SAndroid Build Coastguard Worker }
672*f40fafd4SAndroid Build Coastguard Worker 
GetWriteAmount()673*f40fafd4SAndroid Build Coastguard Worker int32_t GetWriteAmount() {
674*f40fafd4SAndroid Build Coastguard Worker     int32_t currentSegmentWrite = getLifeTimeWrite();
675*f40fafd4SAndroid Build Coastguard Worker     if (currentSegmentWrite == -1) {
676*f40fafd4SAndroid Build Coastguard Worker         return -1;
677*f40fafd4SAndroid Build Coastguard Worker     }
678*f40fafd4SAndroid Build Coastguard Worker 
679*f40fafd4SAndroid Build Coastguard Worker     int32_t writeAmount = currentSegmentWrite - previousSegmentWrite;
680*f40fafd4SAndroid Build Coastguard Worker     previousSegmentWrite = currentSegmentWrite;
681*f40fafd4SAndroid Build Coastguard Worker     return writeAmount;
682*f40fafd4SAndroid Build Coastguard Worker }
683*f40fafd4SAndroid Build Coastguard Worker 
684*f40fafd4SAndroid Build Coastguard Worker }  // namespace vold
685*f40fafd4SAndroid Build Coastguard Worker }  // namespace android
686