In earlier versions of Android, the system traversed all files owned by a particular app to measure disk usage. This manual measurement could take minutes to compute before displaying the results to users in Settings.
In addition, the internal algorithm to clear cached data files only looked at modified time across all apps. This allowed malicious apps to degrade the overall user experience by setting modified times far in the future to unfairly favor themselves over other apps.
To improve these experiences, Android 8.0 offers to leverage the ext4 filesystem's "quota" support to return disk usage statistics almost instantly. This quota feature also improves system stability by preventing any single app from using more than 90% of disk space or 50% of inodes.
Implementation
The quota feature is part of the default implementation of installd
.
installd
automatically uses the quota feature when enabled on a
particular filesystem. The system automatically and transparently resumes
manual calculation when the quota feature isn't enabled or supported on the
block device being measured.
To enable quota support on a particular block device:
- Enable the
CONFIG_QUOTA
,CONFIG_QFMT_V2
, andCONFIG_QUOTACTL
kernel options. - Add the
quota
option to your userdata partition in your fstab file:/dev/block/platform/soc/624000.ufshc/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,noauto_da_alloc latemount,wait,check,formattable,fileencryption=ice,quota
The fstab
option can safely be enabled or disabled on existing
devices. During the first boot after changing the fstab
option,
fsmgr
forces an fsck
pass to update all quota data
structures, which may cause that first boot to take slightly longer. Subsequent
boots will not be affected.
Quota support has only been tested on ext4 and Linux 3.18 or higher. If enabling on other filesystems, or on older kernel versions, device manufacturers are responsible for testing and vetting for statistics correctness.
No special hardware support is required.
Validation
There are CTS tests under StorageHostTest
, which exercise public
APIs for measuring disk usage. These APIs are expected to return correct values
regardless of quota support being enabled or disabled.
Debugging
The test app carefully allocates disk space regions using unique prime numbers
for the size. When debugging these tests, use this to determine the cause of any
discrepancies. For example, if a test fails with a delta of 11MB, examine the
Utils.useSpace()
method to see that the 11MB blob was stored in
getExternalCacheDir()
.
There are also some internal tests that may be useful for debugging, but they may require disabling security checks to pass:
runtest -x frameworks/base/services/tests/servicestests/ \ src/com/android/server/pm/InstallerTest.java
adb shell /data/nativetest64/installd_utils_test/installd_utils_test
adb shell /data/nativetest64/installd_cache_test/installd_cache_test
adb shell /data/nativetest64/installd_service_test/installd_service_test