Merge "Add interfaces required by smart idle maintenance service" am: 6845e06ab9 am: c0c12f5706
Original change: https://android-review.googlesource.com/c/platform/system/vold/+/1936286
Change-Id: I3a12512cc122ee472445652518e7454a7fbfb8ef
diff --git a/IdleMaint.cpp b/IdleMaint.cpp
index 8005cf4..769d7a5 100644
--- a/IdleMaint.cpp
+++ b/IdleMaint.cpp
@@ -85,6 +85,13 @@
*/
static const int GC_TIMEOUT_SEC = 420;
static const int DEVGC_TIMEOUT_SEC = 120;
+static const int KBYTES_IN_SEGMENT = 2048;
+static const int MIN_GC_URGENT_SLEEP_TIME = 500;
+static const int ONE_HOUR_IN_MS = 3600000;
+static const int GC_NORMAL_MODE = 0;
+static const int GC_URGENT_HIGH_MODE = 1;
+
+static int32_t previousSegmentWrite = 0;
static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
static std::condition_variable cv_abort, cv_stop;
@@ -111,7 +118,7 @@
}
}
-static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
+static void addFromFstab(std::list<std::string>* paths, PathTypes path_type, bool only_data_part) {
std::string previous_mount_point;
for (const auto& entry : fstab_default) {
// Skip raw partitions and swap space.
@@ -133,6 +140,10 @@
continue;
}
+ if (only_data_part && entry.mount_point != "/data") {
+ continue;
+ }
+
// Skip the multi-type partitions, which are required to be following each other.
// See fs_mgr.c's mount_with_alternatives().
if (entry.mount_point == previous_mount_point) {
@@ -142,10 +153,10 @@
if (path_type == PathTypes::kMountPoint) {
paths->push_back(entry.mount_point);
} else if (path_type == PathTypes::kBlkDevice) {
- std::string gc_path;
+ std::string path;
if (entry.fs_type == "f2fs" &&
- Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &gc_path)) {
- paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(gc_path));
+ Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &path)) {
+ paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(path));
}
}
@@ -161,7 +172,7 @@
// Collect both fstab and vold volumes
std::list<std::string> paths;
- addFromFstab(&paths, PathTypes::kMountPoint);
+ addFromFstab(&paths, PathTypes::kMountPoint, false);
addFromVolumeManager(&paths, PathTypes::kMountPoint);
for (const auto& path : paths) {
@@ -264,15 +275,18 @@
return android::OK;
}
-static void runDevGcFstab(void) {
- std::string path;
+static std::string getDevSysfsPath() {
for (const auto& entry : fstab_default) {
if (!entry.sysfs_path.empty()) {
- path = entry.sysfs_path;
- break;
+ return entry.sysfs_path;
}
}
+ LOG(WARNING) << "Cannot find dev sysfs path";
+ return "";
+}
+static void runDevGcFstab(void) {
+ std::string path = getDevSysfsPath();
if (path.empty()) {
return;
}
@@ -402,8 +416,10 @@
runDevGcFstab();
}
-int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
+int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
std::unique_lock<std::mutex> lk(cv_m);
+ bool gc_aborted = false;
+
if (idle_maint_stat != IdleMaintStats::kStopped) {
LOG(DEBUG) << "idle maintenance is already running";
if (listener) {
@@ -422,15 +438,17 @@
return android::UNEXPECTED_NULL;
}
- std::list<std::string> paths;
- addFromFstab(&paths, PathTypes::kBlkDevice);
- addFromVolumeManager(&paths, PathTypes::kBlkDevice);
+ if (needGC) {
+ std::list<std::string> paths;
+ addFromFstab(&paths, PathTypes::kBlkDevice, false);
+ addFromVolumeManager(&paths, PathTypes::kBlkDevice);
- startGc(paths);
+ startGc(paths);
- bool gc_aborted = waitForGc(paths);
+ gc_aborted = waitForGc(paths);
- stopGc(paths);
+ stopGc(paths);
+ }
lk.lock();
idle_maint_stat = IdleMaintStats::kStopped;
@@ -480,5 +498,150 @@
return android::OK;
}
+int getLifeTime(const std::string& path) {
+ std::string result;
+
+ if (!ReadFileToString(path, &result)) {
+ PLOG(WARNING) << "Reading lifetime estimation failed for " << path;
+ return -1;
+ }
+ return std::stoi(result, 0, 16);
+}
+
+int32_t GetStorageLifeTime() {
+ std::string path = getDevSysfsPath();
+ if (path.empty()) {
+ return -1;
+ }
+
+ std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
+
+ int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
+ if (lifeTime != -1) {
+ return lifeTime;
+ }
+
+ int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
+ int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
+ lifeTime = std::max(lifeTimeA, lifeTimeB);
+ if (lifeTime != -1) {
+ return lifeTime == 0 ? -1 : lifeTime * 10;
+ }
+ return -1;
+}
+
+void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
+ float reclaimWeight) {
+ std::list<std::string> paths;
+ bool needGC = true;
+
+ addFromFstab(&paths, PathTypes::kBlkDevice, true);
+ if (paths.empty()) {
+ LOG(WARNING) << "There is no valid blk device path for data partition";
+ return;
+ }
+
+ std::string f2fsSysfsPath = paths.front();
+ std::string freeSegmentsPath = f2fsSysfsPath + "/free_segments";
+ std::string dirtySegmentsPath = f2fsSysfsPath + "/dirty_segments";
+ std::string gcSleepTimePath = f2fsSysfsPath + "/gc_urgent_sleep_time";
+ std::string gcUrgentModePath = f2fsSysfsPath + "/gc_urgent";
+ std::string freeSegmentsStr, dirtySegmentsStr;
+
+ if (!ReadFileToString(freeSegmentsPath, &freeSegmentsStr)) {
+ PLOG(WARNING) << "Reading failed in " << freeSegmentsPath;
+ return;
+ }
+
+ if (!ReadFileToString(dirtySegmentsPath, &dirtySegmentsStr)) {
+ PLOG(WARNING) << "Reading failed in " << dirtySegmentsPath;
+ return;
+ }
+
+ int32_t freeSegments = std::stoi(freeSegmentsStr);
+ int32_t dirtySegments = std::stoi(dirtySegmentsStr);
+
+ neededSegments *= reclaimWeight;
+ if (freeSegments >= neededSegments) {
+ LOG(INFO) << "Enough free segments: " << freeSegments
+ << ", needed segments: " << neededSegments;
+ needGC = false;
+ } else if (freeSegments + dirtySegments < minSegmentThreshold) {
+ LOG(INFO) << "The sum of free segments: " << freeSegments
+ << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
+ needGC = false;
+ }
+
+ if (!needGC) {
+ if (!WriteStringToFile(std::to_string(GC_NORMAL_MODE), gcUrgentModePath)) {
+ PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
+ }
+ return;
+ }
+
+ int32_t sleepTime;
+
+ neededSegments -= freeSegments;
+ neededSegments = std::min(neededSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
+ if (neededSegments == 0) {
+ sleepTime = MIN_GC_URGENT_SLEEP_TIME;
+ } else {
+ sleepTime = ONE_HOUR_IN_MS / neededSegments;
+ if (sleepTime < MIN_GC_URGENT_SLEEP_TIME) {
+ sleepTime = MIN_GC_URGENT_SLEEP_TIME;
+ }
+ }
+ if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
+ PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
+ return;
+ }
+
+ if (!WriteStringToFile(std::to_string(GC_URGENT_HIGH_MODE), gcUrgentModePath)) {
+ PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
+ return;
+ }
+
+ LOG(INFO) << "Successfully set gc urgent mode: "
+ << "free segments: " << freeSegments << ", reclaim target: " << neededSegments
+ << ", sleep time: " << sleepTime;
+}
+
+static int32_t getLifeTimeWrite() {
+ std::list<std::string> paths;
+ addFromFstab(&paths, PathTypes::kBlkDevice, true);
+ if (paths.empty()) {
+ LOG(WARNING) << "There is no valid blk device path for data partition";
+ return -1;
+ }
+
+ std::string writeKbytesPath = paths.front() + "/lifetime_write_kbytes";
+ std::string writeKbytesStr;
+ if (!ReadFileToString(writeKbytesPath, &writeKbytesStr)) {
+ PLOG(WARNING) << "Reading failed in " << writeKbytesPath;
+ return -1;
+ }
+
+ long long writeBytes = std::stoll(writeKbytesStr);
+ return writeBytes / KBYTES_IN_SEGMENT;
+}
+
+void RefreshLatestWrite() {
+ int32_t segmentWrite = getLifeTimeWrite();
+ if (segmentWrite != -1) {
+ previousSegmentWrite = segmentWrite;
+ }
+}
+
+int32_t GetWriteAmount() {
+ int32_t currentSegmentWrite = getLifeTimeWrite();
+ if (currentSegmentWrite == -1) {
+ return -1;
+ }
+
+ int32_t writeAmount = currentSegmentWrite - previousSegmentWrite;
+ previousSegmentWrite = currentSegmentWrite;
+ return writeAmount;
+}
+
} // namespace vold
} // namespace android
diff --git a/IdleMaint.h b/IdleMaint.h
index e043db4..ae70b63 100644
--- a/IdleMaint.h
+++ b/IdleMaint.h
@@ -23,8 +23,13 @@
namespace vold {
void Trim(const android::sp<android::os::IVoldTaskListener>& listener);
-int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
+int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener);
int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
+int32_t GetStorageLifeTime();
+void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
+ float reclaimWeight);
+void RefreshLatestWrite();
+int32_t GetWriteAmount();
} // namespace vold
} // namespace android
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 8c9cc16..1c94220 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -470,11 +470,11 @@
}
binder::Status VoldNativeService::runIdleMaint(
- const android::sp<android::os::IVoldTaskListener>& listener) {
+ bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
- std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach();
+ std::thread([=]() { android::vold::RunIdleMaint(needGC, listener); }).detach();
return Ok();
}
@@ -487,6 +487,40 @@
return Ok();
}
+binder::Status VoldNativeService::getStorageLifeTime(int32_t* _aidl_return) {
+ ENFORCE_SYSTEM_OR_ROOT;
+ ACQUIRE_LOCK;
+
+ *_aidl_return = GetStorageLifeTime();
+ return Ok();
+}
+
+binder::Status VoldNativeService::setGCUrgentPace(int32_t neededSegments,
+ int32_t minSegmentThreshold,
+ float dirtyReclaimRate, float reclaimWeight) {
+ ENFORCE_SYSTEM_OR_ROOT;
+ ACQUIRE_LOCK;
+
+ SetGCUrgentPace(neededSegments, minSegmentThreshold, dirtyReclaimRate, reclaimWeight);
+ return Ok();
+}
+
+binder::Status VoldNativeService::refreshLatestWrite() {
+ ENFORCE_SYSTEM_OR_ROOT;
+ ACQUIRE_LOCK;
+
+ RefreshLatestWrite();
+ return Ok();
+}
+
+binder::Status VoldNativeService::getWriteAmount(int32_t* _aidl_return) {
+ ENFORCE_SYSTEM_OR_ROOT;
+ ACQUIRE_LOCK;
+
+ *_aidl_return = GetWriteAmount();
+ return Ok();
+}
+
binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 5fa04f5..49bcbaa 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -85,8 +85,14 @@
binder::Status fstrim(int32_t fstrimFlags,
const android::sp<android::os::IVoldTaskListener>& listener);
- binder::Status runIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
+ binder::Status runIdleMaint(bool needGC,
+ const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status abortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
+ binder::Status getStorageLifeTime(int32_t* _aidl_return);
+ binder::Status setGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold,
+ float dirtyReclaimRate, float reclaimWeight);
+ binder::Status refreshLatestWrite();
+ binder::Status getWriteAmount(int32_t* _aidl_return);
binder::Status mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 8dd7860..c72ceea 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -65,8 +65,13 @@
void destroyObb(@utf8InCpp String volId);
void fstrim(int fstrimFlags, IVoldTaskListener listener);
- void runIdleMaint(IVoldTaskListener listener);
+ void runIdleMaint(boolean needGC, IVoldTaskListener listener);
void abortIdleMaint(IVoldTaskListener listener);
+ int getStorageLifeTime();
+ void setGCUrgentPace(int neededSegments, int minSegmentThreshold,
+ float dirtyReclaimRate, float reclaimWeight);
+ void refreshLatestWrite();
+ int getWriteAmount();
FileDescriptor mountAppFuse(int uid, int mountId);
void unmountAppFuse(int uid, int mountId);