android的存储空间不足主要在DeviceStorageMonitorService中进行逻辑处理的
主要包括以下
1.monitor设备存储
2.每60秒check free space
3.send notification
4.send broadcast
DeviceStorageMonitorService是一个系统服务,在SystemServer的startOtherServices中启动
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {t.traceBegin("StartDeviceMonitor");mSystemServiceManager.startService(DeviceStorageMonitorService.class);t.traceEnd();}
启动之后我们可以通过命令 adb shell dumpsys devicestoragemonitor来查看内部的一些状态
Known volumes:Default:level=NORMAL lastUsableBytes=527691776 lowBytes=524288000 fullBytes=1048576path=/datamSeq=1 mForceState=UNKNOWN
level代表当前状态,分4种
private static final int LEVEL_UNKNOWN = -1; //未知private static final int LEVEL_NORMAL = 0; //正常private static final int LEVEL_LOW = 1; //低存储private static final int LEVEL_FULL = 2; //存储已满
lastUsableBytes表示上一次check时所剩存储空间大小单位Byte
lowBytes表示低存储的阈值 524288000对应500M
fullBytes表示满存储的阈值 1048576对应1M
内部有一个handler循环往复的调用check方法,没60S一次
mHandler = new Looper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_CHECK:check();return;}}};private void check() {final StorageManager storage = getContext().getSystemService(StorageManager.class);if(storage != null) {// 检查所有可用的存储器的剩余存储for (VolumeInfo vol : WritablePrivateVolumes()) {final File file = Path();final long fullBytes = StorageFullBytes(file);final long lowBytes = StorageLowBytes(file);// 当可用空间少于阈值的150%时通知PMS清理应用缓存到200%阈值if (UsableSpace() < (lowBytes * 3) / 2) {final PackageManagerService pms = (PackageManagerService) Service("package");try {pms.FsUuid(), lowBytes * 2, 0);} catch (IOException e) {Slog.w(TAG, e);}}// 根据最近状态转化,来发送通知和广播final UUID uuid = FsUuid());final State state = findOrCreateState(uuid);final long totalBytes = TotalSpace();final long usableBytes = UsableSpace();int oldLevel = state.level;int newLevel;if (mForceLevel != State.LEVEL_UNKNOWN) {// 在测试模式强制执行逻辑oldLevel = State.LEVEL_UNKNOWN;newLevel = mForceLevel;} else if (usableBytes <= fullBytes) {//存储满newLevel = State.LEVEL_FULL;} else if (usableBytes <= lowBytes) {//存储低newLevel = State.LEVEL_LOW;} else if (StorageManager.UUID_DEFAULT.equals(uuid) && !isBootImageOnDisk()&& usableBytes < BOOT_IMAGE_STORAGE_REQUIREMENT) {newLevel = State.LEVEL_LOW;} else {newLevel = State.LEVEL_NORMAL;}//更新通知updateNotifications(vol, oldLevel, newLevel);//更新广播updateBroadcasts(vol, oldLevel, newLevel, seq);state.level = newLevel;}} else {Slog.w(TAG, "StorageManager service not ready !!!");}// 下一次循环,DEFAULT_CHECK_INTERVAL = 60Sif (!mHandler.hasMessages(MSG_CHECK)) {mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK),DEFAULT_CHECK_INTERVAL);}}
updateNotification根据当前状态,更新通知,其中在点击通知时触发ACTION_MANAGE_STORAGE的调用,启动文件管理应用
private void updateNotifications(VolumeInfo vol, int oldLevel, int newLevel) {//获取uuidfinal UUID uuid = FsUuid());if (State.isEntering(State.LEVEL_LOW, oldLevel, newLevel)) {//ACTION_MANAGE_STORAGE,点击通知时触发隐式调用文件管理Intent lowMemIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);lowMemIntent.putExtra(StorageManager.EXTRA_UUID, uuid);lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);PendingIntent intent = ActivityAsUser(context, 0, lowMemIntent, 0,null, UserHandle.CURRENT);Notification notification =new Notification.Builder(context, SystemNotificationChannels.ALERTS)....setContentIntent(intent)....build();String(), SystemMessage.NOTE_LOW_STORAGE,notification, UserHandle.ALL);} else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) {//取消通知mNotifManager.String(), SystemMessage.NOTE_LOW_STORAGE,UserHandle.ALL);}}
updateBroadcasts处理系统低存储的相关广播,主要是低存储和满存储广播的发送和取消
private void updateBroadcasts(VolumeInfo vol, int oldLevel, int newLevel, int seq) {//低存储状态广播final Intent lowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS).putExtra(EXTRA_SEQUENCE, seq);//取消低存储状态广播final Intent notLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS).putExtra(EXTRA_SEQUENCE, seq);//判断发送或者取消广播if (State.isEntering(State.LEVEL_LOW, oldLevel, newLevel)) {getContext().sendStickyBroadcastAsUser(lowIntent, UserHandle.ALL);} else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) {getContext().removeStickyBroadcastAsUser(lowIntent, UserHandle.ALL);getContext().sendBroadcastAsUser(notLowIntent, UserHandle.ALL);}//存储满广播final Intent fullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT).putExtra(EXTRA_SEQUENCE, seq);//存储满取消广播final Intent notFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT).putExtra(EXTRA_SEQUENCE, seq);//判断发送if (State.isEntering(State.LEVEL_FULL, oldLevel, newLevel)) {getContext().sendStickyBroadcastAsUser(fullIntent, UserHandle.ALL);} else if (State.isLeaving(State.LEVEL_FULL, oldLevel, newLevel)) {getContext().removeStickyBroadcastAsUser(fullIntent, UserHandle.ALL);getContext().sendBroadcastAsUser(notFullIntent, UserHandle.ALL);}}
实际调试测试过程中,我们可以使用命令
adb shell dumpsys devicestoragemonitor force-low 触发低存储流程调用
adb shell dumpsys devicestoragemonitor force-not-low 取消低存储流程调用
adb shell dumpsys devicestoragemonitor reset 重置测试状态
案例分析:
客户需要修改低存储的阈值,以及data分区预留空间的大小,方便即使在存储满的情况下,系统关键的进程或服务还能够正常使用,还要修改低存储阈值条件
final long lowBytes = StorageLowBytes(file);
在StorageManager.java中getStorageLowBytes方法会取500M和总可用容量的5%的最小值,
private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;private static final long DEFAULT_THRESHOLD_MAX_BYTES = Bytes(500);public long getStorageLowBytes(File path) {final long lowPercent = Int(mResolver,Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);final long lowBytes = (TotalSpace() * lowPercent) / 100;final long maxLowBytes = Long(mResolver,Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);return Math.min(lowBytes, maxLowBytes);}
data分区预留空间
通过命令adb shell stat -f data
File: "data"ID: 0000fc0900000000 Namelen: 255 Type: 0xf2f52010
Block Size: 4096 Fundamental block size: 4096
Blocks: Total: 6233848 Free: 5872336 Available: 5860277
Inodes: Total: 6029824 Free: 5860277
其中 (Free-Available)*4096
可用的减去可获取的乘上每个Block快大小就是预留空间的大小
预留一部分MTP空间,防止通过MTP方式填满存储造成的问题
修改frameworks/avmedia/mtp/MtpStorage.cpp,返回时预留一定空间
4000*4096=16M
diff --git a/media/mtp/MtpStorage.cpp b/media/mtp/MtpStorage.cpp
index a147325..4ebb134 100644
--- a/media/mtp/MtpStorage.cpp
+++ b/media/mtp/MtpStorage.cpp
@@ -72,7 +72,11 @@struct statfs stat;if (statfs(getPath(), &stat))return -1;
- return (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
+// Liverpool code for ANDYSEVEN-3836 by zhangtisheng at 2021.02.02 10:31 start
+ uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
+ uint64_t thresholdSpace = (uint64_t)(4000) * (uint64_t)stat.f_bsize;
+ return (freeSpace > thresholdSpace ? freeSpace - thresholdSpace : 0);
+// Liverpool code for ANDYSEVEN-3836 by zhangtisheng at 2021.02.02 10:31 end}const char* MtpStorage::getDescription() const {
adb shell dd if=/dev/zero of=/mnt/sdcard/bigfile 注解:
dd:用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。
注意:指定数字的地方若以下列字符结尾,则乘以相应的数字:b=512;c=1;k=1024;w=2
参数注释:
本文发布于:2024-02-03 02:05:30,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170689713047924.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |