@ -17,7 +17,12 @@
# include "IdleMaint.h"
# include "Utils.h"
# include "VolumeManager.h"
# include "model/PrivateVolume.h"
# include <thread>
# include <android-base/chrono_utils.h>
# include <android-base/file.h>
# include <android-base/stringprintf.h>
# include <android-base/logging.h>
# include <fs_mgr.h>
@ -31,26 +36,60 @@
# include <sys/wait.h>
# include <fcntl.h>
using android : : base : : Basename ;
using android : : base : : ReadFileToString ;
using android : : base : : Realpath ;
using android : : base : : StringPrintf ;
using android : : base : : Timer ;
using android : : base : : WriteStringToFile ;
namespace android {
namespace vold {
enum class PathTypes {
kMountPoint = 1 ,
kBlkDevice ,
} ;
enum class IdleMaintStats {
kStopped = 1 ,
kRunning ,
kAbort ,
} ;
static const char * kWakeLock = " IdleMaint " ;
static const int DIRTY_SEGMENTS_THRESHOLD = 100 ;
static const int GC_TIMEOUT_SEC = 480 ;
static void addFromVolumeManager ( std : : list < std : : string > * paths ) {
static IdleMaintStats idle_maint_stat ( IdleMaintStats : : kStopped ) ;
static std : : condition_variable cv_abort , cv_stop ;
static std : : mutex cv_m ;
static void addFromVolumeManager ( std : : list < std : : string > * paths ,
PathTypes path_type ) {
VolumeManager * vm = VolumeManager : : Instance ( ) ;
std : : list < std : : string > privateIds ;
vm - > listVolumes ( VolumeBase : : Type : : kPrivate , privateIds ) ;
for ( const auto & id : privateIds ) {
auto vol = vm - > findVolume ( id ) ;
PrivateVolume * vol = static_cast < PrivateVolume * > ( vm - > findVolume ( id ) . get ( ) ) ;
if ( vol ! = nullptr & & vol - > getState ( ) = = VolumeBase : : State : : kMounted ) {
paths - > push_back ( vol - > getPath ( ) ) ;
if ( path_type = = PathTypes : : kMountPoint ) {
paths - > push_back ( vol - > getPath ( ) ) ;
} else if ( path_type = = PathTypes : : kBlkDevice ) {
std : : string gc_path ;
const std : : string & fs_type = vol - > getFsType ( ) ;
if ( fs_type = = " f2fs " & &
Realpath ( vol - > getRawDevPath ( ) , & gc_path ) ) {
paths - > push_back ( std : : string ( " /sys/fs/ " ) + fs_type +
" / " + Basename ( gc_path ) ) ;
}
}
}
}
}
static void addFromFstab ( std : : list < std : : string > * paths ) {
static void addFromFstab ( std : : list < std : : string > * paths , PathTypes path_type ) {
std : : unique_ptr < fstab , decltype ( & fs_mgr_free_fstab ) > fstab ( fs_mgr_read_fstab_default ( ) ,
fs_mgr_free_fstab ) ;
struct fstab_rec * prev_rec = NULL ;
@ -79,7 +118,17 @@ static void addFromFstab(std::list<std::string>* paths) {
continue ;
}
paths - > push_back ( fstab - > recs [ i ] . mount_point ) ;
if ( path_type = = PathTypes : : kMountPoint ) {
paths - > push_back ( fstab - > recs [ i ] . mount_point ) ;
} else if ( path_type = = PathTypes : : kBlkDevice ) {
std : : string gc_path ;
if ( std : : string ( fstab - > recs [ i ] . fs_type ) = = " f2fs " & &
Realpath ( fstab - > recs [ i ] . blk_device , & gc_path ) ) {
paths - > push_back ( std : : string ( " /sys/fs/ " ) + fstab - > recs [ i ] . fs_type +
" / " + Basename ( gc_path ) ) ;
}
}
prev_rec = & fstab - > recs [ i ] ;
}
}
@ -89,8 +138,8 @@ void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
// Collect both fstab and vold volumes
std : : list < std : : string > paths ;
addFromFstab ( & paths );
addFromVolumeManager ( & paths );
addFromFstab ( & paths , PathTypes : : kMountPoint );
addFromVolumeManager ( & paths , PathTypes : : kMountPoint );
for ( const auto & path : paths ) {
LOG ( DEBUG ) < < " Starting trim of " < < path ;
@ -138,5 +187,136 @@ void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
release_wake_lock ( kWakeLock ) ;
}
static bool waitForGc ( const std : : list < std : : string > & paths ) {
std : : unique_lock < std : : mutex > lk ( cv_m , std : : defer_lock ) ;
bool stop = false , aborted = false ;
Timer timer ;
while ( ! stop & & ! aborted ) {
stop = true ;
for ( const auto & path : paths ) {
std : : string dirty_segments ;
if ( ! ReadFileToString ( path + " /dirty_segments " , & dirty_segments ) ) {
PLOG ( WARNING ) < < " Reading dirty_segments failed in " < < path ;
continue ;
}
if ( std : : stoi ( dirty_segments ) > DIRTY_SEGMENTS_THRESHOLD ) {
stop = false ;
break ;
}
}
if ( stop ) break ;
if ( timer . duration ( ) > = std : : chrono : : seconds ( GC_TIMEOUT_SEC ) ) {
LOG ( WARNING ) < < " GC timeout " ;
break ;
}
lk . lock ( ) ;
aborted = cv_abort . wait_for ( lk , 10 s , [ ] {
return idle_maint_stat = = IdleMaintStats : : kAbort ; } ) ;
lk . unlock ( ) ;
}
return aborted ;
}
static int startGc ( const std : : list < std : : string > & paths ) {
for ( const auto & path : paths ) {
LOG ( DEBUG ) < < " Start GC on " < < path ;
if ( ! WriteStringToFile ( " 1 " , path + " /gc_urgent " ) ) {
PLOG ( WARNING ) < < " Start GC failed on " < < path ;
}
}
return android : : OK ;
}
static int stopGc ( const std : : list < std : : string > & paths ) {
for ( const auto & path : paths ) {
LOG ( DEBUG ) < < " Stop GC on " < < path ;
if ( ! WriteStringToFile ( " 0 " , path + " /gc_urgent " ) ) {
PLOG ( WARNING ) < < " Stop GC failed on " < < path ;
}
}
return android : : OK ;
}
int RunIdleMaint ( const android : : sp < android : : os : : IVoldTaskListener > & listener ) {
std : : unique_lock < std : : mutex > lk ( cv_m ) ;
if ( idle_maint_stat ! = IdleMaintStats : : kStopped ) {
LOG ( DEBUG ) < < " idle maintenance is already running " ;
if ( listener ) {
android : : os : : PersistableBundle extras ;
listener - > onFinished ( 0 , extras ) ;
}
return android : : OK ;
}
idle_maint_stat = IdleMaintStats : : kRunning ;
lk . unlock ( ) ;
LOG ( DEBUG ) < < " idle maintenance started " ;
acquire_wake_lock ( PARTIAL_WAKE_LOCK , kWakeLock ) ;
std : : list < std : : string > paths ;
addFromFstab ( & paths , PathTypes : : kBlkDevice ) ;
addFromVolumeManager ( & paths , PathTypes : : kBlkDevice ) ;
startGc ( paths ) ;
bool gc_aborted = waitForGc ( paths ) ;
stopGc ( paths ) ;
lk . lock ( ) ;
idle_maint_stat = IdleMaintStats : : kStopped ;
lk . unlock ( ) ;
cv_stop . notify_one ( ) ;
if ( ! gc_aborted ) {
Trim ( nullptr ) ;
}
if ( listener ) {
android : : os : : PersistableBundle extras ;
listener - > onFinished ( 0 , extras ) ;
}
LOG ( DEBUG ) < < " idle maintenance completed " ;
release_wake_lock ( kWakeLock ) ;
return android : : OK ;
}
int AbortIdleMaint ( const android : : sp < android : : os : : IVoldTaskListener > & listener ) {
acquire_wake_lock ( PARTIAL_WAKE_LOCK , kWakeLock ) ;
std : : unique_lock < std : : mutex > lk ( cv_m ) ;
if ( idle_maint_stat ! = IdleMaintStats : : kStopped ) {
idle_maint_stat = IdleMaintStats : : kAbort ;
lk . unlock ( ) ;
cv_abort . notify_one ( ) ;
lk . lock ( ) ;
LOG ( DEBUG ) < < " aborting idle maintenance " ;
cv_stop . wait ( lk , [ ] {
return idle_maint_stat = = IdleMaintStats : : kStopped ; } ) ;
}
lk . unlock ( ) ;
if ( listener ) {
android : : os : : PersistableBundle extras ;
listener - > onFinished ( 0 , extras ) ;
}
release_wake_lock ( kWakeLock ) ;
LOG ( DEBUG ) < < " idle maintenance stopped " ;
return android : : OK ;
}
} // namespace vold
} // namespace android