1. 磁盘配额调研报告
1.1. 实际磁盘配额控制
1.1.1. 依赖项情况
Ext4
文件系统默认开启了DQUOT_USAGE_ENABLED
Kernel
中filesystem support
中开启了quota support
1.1.2. 磁盘配额初始化
- 由
Installd
开启data
分区的磁盘配额 (/mnt/runtime/default
)
Sd卡格式化内部存储后,应该也可以支持
StorageStatesService
和installd
的联动
在invalidateMounts
函数中完成了磁盘配额的初始化
1 | Found quota mount " << source << " at " << target; |
并没有将配置放在fstab中,使用fstab对分区的文件系统进行自动配额调整。可以使用fstab对某一分区进行配额的设定。
1.1.3. 磁盘配额的额外设定
为每个应用设置的实际磁盘配额 :
- 90% of
disk blocks
, or50% of disk inodes.
设定原因:
Abusive or broken apps can go crazy and try allocating all of the disk space on the device. To mitigate the impact on system health,
set hard limits to block any given app from using more than 90% of disk blocks, or 50% of disk inodes.
Also define the hard limit for AID_MEDIA_RW to avoid filling up the device via the SD card.
Kick QUOTAON when scanning devices, since ext4 doesn’t toggle DQUOT_LIMITS_ENABLED during initial mount.
2. 虚拟的磁盘配额(cache quota)
Android O 围绕缓存数据提供更加出色的导航和性能。每个应用均获得一定的磁盘空间配额,用于存储 getCacheQuotaBytes(File) 返回的缓存数据。
2.1. cache quota 初始化
由Framework
层的StorageStatsService
进行初始化:
1 | mHandler.sendEmptyMessage(H.MSG_LOAD_CACHED_QUOTAS_FROM_FILE); |
默认生成/data/system/cachequota.xml
文件,用于持久化应用初始的cache磁盘配额。
1 |
|
1 | @startuml |
2.2. 内部存储不足时,根据cache quota 释放cache
当系统需要释放磁盘空间时,将开始从超过配额最多的应用中删除缓存文件。因此,如果将您的缓存数据量始终保持低于配额的水平,则在必须清除系统中的某些文件时,您的缓存文件将能坚持到最后。系统在决定删除您的应用中的哪些缓存文件时,将首先考虑删除最旧的文件(由修改时间决定)。
2.2.1.1. 目录的两种删除机制
可以针对每个目录启用两种新行为,以控制系统如何释放缓存数据:
2.2.1.1.1.1. 整体
setCacheBehaviorAtomic(File, boolean)
可用于指示某个目录及其所有内容应作为一个不可分割的整体进行删除。只能作用于目录。设置后,该目录下的所有子目录及文件都标记为一个整体。
其下面的每一个文件的修改,修改时间都会标记到该目录层级上。
2.2.1.1.1.2. 截断
setCacheBehaviorTombstone(File, boolean)
可用于指示不应删除某个目录内的文件,而应将它们截断到 0 字节长度,使空文件保持完好。也可用于目录,则该级目录下的所有文件(除链接之外的)删除时都会截断到0字节长度。
跳转到的地方
2.2.1.2. 根据cache quota 释放 cache
删除目录层次:
1
2
3/data/user/<user_id>/
/data/user_de/<user_id>
/data/media/<user_id>/Android/data/
在对item进行删除时,首先找到cacheRatio最大的应用相关的目录,去其中的文件按照修改时间的顺序进行删除,每删除一项,检查删除后的空间是否满足要求,如果满足要求,则不再进行删除,如果不满足,重新计算每个应用的cacheRadio,然后,对cacheRadio最大的,找到其中修改时间最早的项。进行删除。 依此步骤,直到删除到满足条件为止。
2.2.2. 为应用分配空间时,查询可使用的空间
在需要为大文件分配磁盘空间时,可考虑使用新的 [allocateBytes(File, long, int)](#allocateBytes(java.io.File, long, int)) API,它将==自动清除==属于其他应用的缓存文件(根据需要),以满足您的请求。在确定设备是否有足够的磁盘空间保存您的新数据时,请调用 [getAllocatableBytes(File, int)](#getAllocatableBytes(java.io.File, int)) 而不要使用 getUsableSpace(),因为前者会考虑系统要为您清除的任何缓存数据。