diff --git a/IdleMaint.cpp b/IdleMaint.cpp index 7d3eaf4..fafa280 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -507,6 +507,30 @@ int32_t GetStorageLifeTime() { return -1; } +int32_t GetStorageRemainingLifetime() { + 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) { + int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a"); + int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b"); + lifeTime = std::max(lifeTimeA, lifeTimeB); + if (lifeTime <= 0) { + return -1; + } + + // 1 = 0-10% used, 10 = 90-100% used. Subtract 1 so that a brand new + // device looks 0% used. + lifeTime = (lifeTime - 1) * 10; + } + return 100 - std::clamp(lifeTime, 0, 100); +} + void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate, float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime, int32_t targetDirtyRatio) { diff --git a/IdleMaint.h b/IdleMaint.h index a28cde2..a1387b3 100644 --- a/IdleMaint.h +++ b/IdleMaint.h @@ -26,6 +26,7 @@ void Trim(const android::sp& listener); int RunIdleMaint(bool needGC, const android::sp& listener); int AbortIdleMaint(const android::sp& listener); int32_t GetStorageLifeTime(); +int32_t GetStorageRemainingLifetime(); void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate, float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime, int32_t targetDirtyRatio); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 65731af..96f4eaf 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -504,6 +504,14 @@ binder::Status VoldNativeService::getStorageLifeTime(int32_t* _aidl_return) { return Ok(); } +binder::Status VoldNativeService::getStorageRemainingLifetime(int32_t* _aidl_return) { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_LOCK; + + *_aidl_return = GetStorageRemainingLifetime(); + return Ok(); +} + binder::Status VoldNativeService::setGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate, float reclaimWeight, diff --git a/VoldNativeService.h b/VoldNativeService.h index d9aee57..bb00d35 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -89,6 +89,7 @@ class VoldNativeService : public BinderService, public os::Bn const android::sp& listener); binder::Status abortIdleMaint(const android::sp& listener); binder::Status getStorageLifeTime(int32_t* _aidl_return); + binder::Status getStorageRemainingLifetime(int32_t* _aidl_return); binder::Status setGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate, float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime, int32_t targetDirtyRatio); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 229f173..d121dee 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -66,6 +66,8 @@ interface IVold { void fstrim(int fstrimFlags, IVoldTaskListener listener); void runIdleMaint(boolean needGC, IVoldTaskListener listener); void abortIdleMaint(IVoldTaskListener listener); + // Returns the amount of storage lifetime used, as a percentage. + // (eg, 10 indicates 10% of lifetime used), or -1 on failure. int getStorageLifeTime(); void setGCUrgentPace(int neededSegments, int minSegmentThreshold, float dirtyReclaimRate, float reclaimWeight, @@ -135,6 +137,11 @@ interface IVold { long getStorageSize(); + // Returns the remaining storage lifetime as a percentage, rounded up as + // needed when the underlying hardware reports low precision. Returns -1 + // on failure. + int getStorageRemainingLifetime(); + const int FSTRIM_FLAG_DEEP_TRIM = 1; const int MOUNT_FLAG_PRIMARY = 1;