Merge "Add interfaces required by smart idle maintenance service"
This commit is contained in:
commit
6845e06ab9
5 changed files with 234 additions and 21 deletions
195
IdleMaint.cpp
195
IdleMaint.cpp
|
@ -85,6 +85,13 @@ static const int DIRTY_SEGMENTS_THRESHOLD = 100;
|
||||||
*/
|
*/
|
||||||
static const int GC_TIMEOUT_SEC = 420;
|
static const int GC_TIMEOUT_SEC = 420;
|
||||||
static const int DEVGC_TIMEOUT_SEC = 120;
|
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 IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
|
||||||
static std::condition_variable cv_abort, cv_stop;
|
static std::condition_variable cv_abort, cv_stop;
|
||||||
|
@ -111,7 +118,7 @@ static void addFromVolumeManager(std::list<std::string>* paths, PathTypes path_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
std::string previous_mount_point;
|
||||||
for (const auto& entry : fstab_default) {
|
for (const auto& entry : fstab_default) {
|
||||||
// Skip raw partitions and swap space.
|
// Skip raw partitions and swap space.
|
||||||
|
@ -133,6 +140,10 @@ static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (only_data_part && entry.mount_point != "/data") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip the multi-type partitions, which are required to be following each other.
|
// Skip the multi-type partitions, which are required to be following each other.
|
||||||
// See fs_mgr.c's mount_with_alternatives().
|
// See fs_mgr.c's mount_with_alternatives().
|
||||||
if (entry.mount_point == previous_mount_point) {
|
if (entry.mount_point == previous_mount_point) {
|
||||||
|
@ -142,10 +153,10 @@ static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
|
||||||
if (path_type == PathTypes::kMountPoint) {
|
if (path_type == PathTypes::kMountPoint) {
|
||||||
paths->push_back(entry.mount_point);
|
paths->push_back(entry.mount_point);
|
||||||
} else if (path_type == PathTypes::kBlkDevice) {
|
} else if (path_type == PathTypes::kBlkDevice) {
|
||||||
std::string gc_path;
|
std::string path;
|
||||||
if (entry.fs_type == "f2fs" &&
|
if (entry.fs_type == "f2fs" &&
|
||||||
Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &gc_path)) {
|
Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &path)) {
|
||||||
paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(gc_path));
|
paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +172,7 @@ void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
|
||||||
|
|
||||||
// Collect both fstab and vold volumes
|
// Collect both fstab and vold volumes
|
||||||
std::list<std::string> paths;
|
std::list<std::string> paths;
|
||||||
addFromFstab(&paths, PathTypes::kMountPoint);
|
addFromFstab(&paths, PathTypes::kMountPoint, false);
|
||||||
addFromVolumeManager(&paths, PathTypes::kMountPoint);
|
addFromVolumeManager(&paths, PathTypes::kMountPoint);
|
||||||
|
|
||||||
for (const auto& path : paths) {
|
for (const auto& path : paths) {
|
||||||
|
@ -264,15 +275,18 @@ static int stopGc(const std::list<std::string>& paths) {
|
||||||
return android::OK;
|
return android::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runDevGcFstab(void) {
|
static std::string getDevSysfsPath() {
|
||||||
std::string path;
|
|
||||||
for (const auto& entry : fstab_default) {
|
for (const auto& entry : fstab_default) {
|
||||||
if (!entry.sysfs_path.empty()) {
|
if (!entry.sysfs_path.empty()) {
|
||||||
path = entry.sysfs_path;
|
return entry.sysfs_path;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG(WARNING) << "Cannot find dev sysfs path";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runDevGcFstab(void) {
|
||||||
|
std::string path = getDevSysfsPath();
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -402,8 +416,10 @@ static void runDevGc(void) {
|
||||||
runDevGcFstab();
|
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);
|
std::unique_lock<std::mutex> lk(cv_m);
|
||||||
|
bool gc_aborted = false;
|
||||||
|
|
||||||
if (idle_maint_stat != IdleMaintStats::kStopped) {
|
if (idle_maint_stat != IdleMaintStats::kStopped) {
|
||||||
LOG(DEBUG) << "idle maintenance is already running";
|
LOG(DEBUG) << "idle maintenance is already running";
|
||||||
if (listener) {
|
if (listener) {
|
||||||
|
@ -422,15 +438,17 @@ int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
|
||||||
return android::UNEXPECTED_NULL;
|
return android::UNEXPECTED_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::string> paths;
|
if (needGC) {
|
||||||
addFromFstab(&paths, PathTypes::kBlkDevice);
|
std::list<std::string> paths;
|
||||||
addFromVolumeManager(&paths, PathTypes::kBlkDevice);
|
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();
|
lk.lock();
|
||||||
idle_maint_stat = IdleMaintStats::kStopped;
|
idle_maint_stat = IdleMaintStats::kStopped;
|
||||||
|
@ -480,5 +498,150 @@ int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener)
|
||||||
return android::OK;
|
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 vold
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
@ -23,8 +23,13 @@ namespace android {
|
||||||
namespace vold {
|
namespace vold {
|
||||||
|
|
||||||
void Trim(const android::sp<android::os::IVoldTaskListener>& listener);
|
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);
|
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 vold
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
|
@ -470,11 +470,11 @@ binder::Status VoldNativeService::fstrim(
|
||||||
}
|
}
|
||||||
|
|
||||||
binder::Status VoldNativeService::runIdleMaint(
|
binder::Status VoldNativeService::runIdleMaint(
|
||||||
const android::sp<android::os::IVoldTaskListener>& listener) {
|
bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
|
||||||
ENFORCE_SYSTEM_OR_ROOT;
|
ENFORCE_SYSTEM_OR_ROOT;
|
||||||
ACQUIRE_LOCK;
|
ACQUIRE_LOCK;
|
||||||
|
|
||||||
std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach();
|
std::thread([=]() { android::vold::RunIdleMaint(needGC, listener); }).detach();
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +487,40 @@ binder::Status VoldNativeService::abortIdleMaint(
|
||||||
return Ok();
|
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,
|
binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId,
|
||||||
android::base::unique_fd* _aidl_return) {
|
android::base::unique_fd* _aidl_return) {
|
||||||
ENFORCE_SYSTEM_OR_ROOT;
|
ENFORCE_SYSTEM_OR_ROOT;
|
||||||
|
|
|
@ -85,8 +85,14 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
|
||||||
|
|
||||||
binder::Status fstrim(int32_t fstrimFlags,
|
binder::Status fstrim(int32_t fstrimFlags,
|
||||||
const android::sp<android::os::IVoldTaskListener>& listener);
|
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 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,
|
binder::Status mountAppFuse(int32_t uid, int32_t mountId,
|
||||||
android::base::unique_fd* _aidl_return);
|
android::base::unique_fd* _aidl_return);
|
||||||
|
|
|
@ -65,8 +65,13 @@ interface IVold {
|
||||||
void destroyObb(@utf8InCpp String volId);
|
void destroyObb(@utf8InCpp String volId);
|
||||||
|
|
||||||
void fstrim(int fstrimFlags, IVoldTaskListener listener);
|
void fstrim(int fstrimFlags, IVoldTaskListener listener);
|
||||||
void runIdleMaint(IVoldTaskListener listener);
|
void runIdleMaint(boolean needGC, IVoldTaskListener listener);
|
||||||
void abortIdleMaint(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);
|
FileDescriptor mountAppFuse(int uid, int mountId);
|
||||||
void unmountAppFuse(int uid, int mountId);
|
void unmountAppFuse(int uid, int mountId);
|
||||||
|
|
Loading…
Reference in a new issue