Android 存储空间不足检测逻辑

阅读: 评论:0

Android 存储空间不足检测逻辑

Android 存储空间不足检测逻辑

Android 存储空间不足提示

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
参数注释:

  1. if=文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >
  2. of=文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >

本文发布于:2024-02-03 02:05:30,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170689713047924.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:存储空间   逻辑   Android
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23