Android7.1的存储空间监控

很久没写了,做下笔记,跟踪一下Android系统对存储空间的管理和监控:
对于Android系统的存储空间是由DeviceStorageMonitorService这个服务来进行管理的,现在我们来浅析一下这个类的加载流程和空间管理。
DeviceStorageMonitorService类实现了一个监控设备上存储空间的服务。如果设备的剩余存储空间小于某一个阀值(默认是存储空间的10%和500M,一般选择它们中的最小值为默认值,这个值可以设置)时将会向用户发送剩余空间不足的警告,让用户释放一些空间
位置:frameworks\base\services\core\java\com\android\server\storage\DeviceStorageMonitorService.java

开机启动位置:
我们知道一般service都是由SystemServer加载进来的,这个服务也是,在SystemServer.java由
mSystemServiceManager.startService(DeviceStorageMonitorService.class);启动服务。

服务起来后又干了些啥?发现它会先创建4个intent

mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
//存储空间不足
mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
//存储空间正常
mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL);
//存储空间已满
mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); 

由于每个Intent都设置了FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT标志,因此这三个Intent只能由注册了的BroadcastReceiver接收。

接着我们走到onstart()中,
mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH); //设置的存储空间不足的大小
从StorageManager.java 的getStorageLowBytes()方法中我们可得到

public long getStorageLowBytes(File path) {
      final long lowPercent = Settings.Global.getInt(mResolver,
                Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
        final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
        final long maxLowBytes = Settings.Global.getLong(mResolver,
                Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
        return Math.min(lowBytes, maxLowBytes);
    }

选择的是Math.min(lowBytes, maxLowBytes),返回它们的最小值,DEFAULT_THRESHOLD_PERCENTAGE=10;
DEFAULT_THRESHOLD_MAX_BYTES=500* MB_IN_BYTES;//即500M

同样mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);可得到

  public long getStorageFullBytes(File path) {
        return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
                DEFAULT_FULL_THRESHOLD_BYTES);
    }

DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;//1M
接着重点函数checkMemory(true);开始检查,存储空间

void checkMemory(boolean checkCache) {
        //if the thread that was started to clear cache is still running do nothing till its
        //finished clearing cache. Ideally this flag could be modified by clearCache
        // and should be accessed via a lock but even if it does this test will fail now and
        //hopefully the next time this flag will be set to the correct value.
        //如果线程 正在清除缓存CACHE_PATH ,那么不进行空间检查;
        if(mClearingCache) {
            if(localLOGV) Slog.i(TAG, "Thread already running just skip");
            //make sure the thread is not hung for too long
            long diffTime = System.currentTimeMillis() - mThreadStartTime;
            if(diffTime > (10*60*1000)) {
                Slog.w(TAG, "Thread that clears cache file seems to run for ever");
            }
        } else {
            restatDataDir(); //重新计算3个分区的剩余空间大小;
            if (localLOGV)  Slog.v(TAG, "freeMemory="+mFreeMem+" mMemLowThreshold="+mMemLowThreshold);

            //post intent to NotificationManager to display icon if necessary
            if (mFreeMem < mMemLowThreshold) {
                if (checkCache) {
                    // We are allowed to clear cache files at this point to
                    // try to get down below the limit, because this is not
                    // the initial call after a cache clear has been attempted.
                    // In this case we will try a cache clear if our free
                    // space has gone below the cache clear limit.
                    if (mFreeMem < mMemCacheStartTrimThreshold) {
                        // We only clear the cache if the free storage has changed
                        // a significant amount since the last time.
                        if(localLOGV) Slog.i(TAG, "mMemCacheStartTrimThreshold="+mMemCacheStartTrimThreshold);
                        if ((mFreeMemAfterLastCacheClear-mFreeMem)
                                >= ((mMemLowThreshold-mMemCacheStartTrimThreshold)/4)) {
                            // See if clearing cache helps
                            // Note that clearing cache is asynchronous and so we do a
                            // memory check again once the cache has been cleared.
                            if(localLOGV) Slog.i(TAG, "mFreeMemAfterLastCacheClear="+mFreeMemAfterLastCacheClear);

                            mThreadStartTime = System.currentTimeMillis();
                            mClearSucceeded = false;
                            clearCache();//如果剩余空间低于mMemLowThreshold,先做一次缓存清理
                        }
                    }
                } else {
                    // This is a call from after clearing the cache.  Note
                    // the amount of free storage at this point.
                    mFreeMemAfterLastCacheClear = mFreeMem;
                    if (!mLowMemFlag) {
                        // We tried to clear the cache, but that didn't get us
                        // below the low storage limit.  Tell the user.
                        Slog.i(TAG, "Running low on memory. Sending notification");
                        sendNotification();//如果空间仍然低于mMemLowThreshold, 发送广播并 在状态来设置一个 警告通知,在未取消广播只跑一次
                        mLowMemFlag = true;
                    } else {
                        if (localLOGV) Slog.v(TAG, "Running low on memory " +
                                "notification already sent. do nothing");
                    }
                }
            } else {
                mFreeMemAfterLastCacheClear = mFreeMem;
                if (mLowMemFlag) {//如果 剩余空间 不小于mMemLowThreshold,且已经设置了mLowMemFlag,则 取消空间不足广播。
                    Slog.i(TAG, "Memory available. Cancelling notification");
                    cancelNotification();
                    mLowMemFlag = false;
                }
            }
            if (!mLowMemFlag && !mIsBootImageOnDisk && mFreeMem < BOOT_IMAGE_STORAGE_REQUIREMENT) {
                Slog.i(TAG, "No boot image on disk due to lack of space. Sending notification");
                sendNotification();
                mLowMemFlag = true;
            }
            if (mFreeMem < mMemFullThreshold) {
                if (!mMemFullFlag) {
                    sendFullNotification(); //如果空间已满,则发送空间已满的广播;即小余1M
                    mMemFullFlag = true;
                }
            } else {
                if (mMemFullFlag) {
                    cancelFullNotification();//如果 空间不满 且已经发送了空间已满的广播,则在此取消。
                    mMemFullFlag = false;
                }
            }
        }
        if(localLOGV) Slog.i(TAG, "Posting Message again");
        //keep posting messages to itself periodically
        postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);//DEFAULT_CHECK_INTERVAL为1分钟,即每1分钟 会触发一次检查;
}


     void postCheckMemoryMsg(boolean clearCache, long delay) {
        // Remove queued messages
        mHandler.removeMessages(DEVICE_MEMORY_WHAT);
        mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
                clearCache ?_TRUE : _FALSE, 0),
                delay);
    }

private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //don't handle an invalid message
            if (msg.what != DEVICE_MEMORY_WHAT) {
                Slog.e(TAG, "Will not process invalid message");
                return;
            }
            checkMemory(msg.arg1 == _TRUE);
        }
    };

而在clearCache会立即检查一次

 private void clearCache() {
        if (mClearCacheObserver == null) {
            // Lazy instantiation
            mClearCacheObserver = new CachePackageDataObserver();
        }
        mClearingCache = true;
        try {
            if (localLOGV) Slog.i(TAG, "Clearing cache");
            IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
                    freeStorageAndNotify(null, mMemCacheTrimToThreshold, mClearCacheObserver);
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
            mClearingCache = false;
            mClearSucceeded = false;
        }
    }

且clearCache值设置为false

 private class CachePackageDataObserver extends IPackageDataObserver.Stub {
        public void onRemoveCompleted(String packageName, boolean succeeded) {
            mClearSucceeded = succeeded;
            mClearingCache = false;
            if(localLOGV) Slog.i(TAG, " Clear succeeded:"+mClearSucceeded
                    +", mClearingCache:"+mClearingCache+" Forcing memory check");
            postCheckMemoryMsg(false, 0);
        }
    }

总结:
(1)首先在构造函数中,获取data,system,cache分区信息,然后注册四个intent,分别为低内存,内存ok,内存满,内存没有满四种情况。然后获取settings数据库里的data目录下剩余空间少于其总空间的百分比值,获取数据库中data目录下剩余空间的大小临界值(用于提示用户空间已满)。然后开始检查,存储空间;checkMemory(true);
(2)
在检查存储空间时,首先判断如果线程正在清除缓存CACHE_PATH ,那么不进行空间检查。否则重新计算3个分区的剩余空间大小。如果剩余空间低于设置值,如果需要做缓存清理,先做一次缓存清理;清理完毕后会再次进行新一轮的checkMemory,如果剩余空间低于还是低于设置值,并不用做缓存清理并且没有发通知,则发送通知告诉用户内部空间低于设置值,如果此时空间百分比正常,但已发送通知,则将通知取消。同样的,如果空间已满,大于full的临界值,则发送空间已满的广播;空间不满且已经发送了空间已满的广播,则取消。最后会每1分钟会触发一次检查空间checkMemory。

如下:清理完毕后会再次进行新一轮的checkMemory:
做一下onRemoveCompleted动作,该动作发送检查空间的消息【postCheckMemoryMsg(false, 0);这里的false就是不再执行clearCache】,然后handle处理该消息DEVICE_MEMORY_WHAT,再次进入checkMemory(false),发送通知告诉用户storage space running out,空间小于设置值会出现该提示。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值