欢迎来到kaffeel的博客

点滴积累,快乐分享-kaffeel.org
  首页  :: 新随笔  :: 订阅 订阅  :: 管理

Android Service之设备存储空间监控

Posted on 2013-01-10 14:41  kaffeel  阅读(2045)  评论(0编辑  收藏  举报

在负责文件系统模块的过程中,经常会碰到由于系统空间被消耗完而导致的问题,因此要确保为系统功能(如数据库同步)保留一定的空间。在功能机中一般是由文件系统模块预留,那么在Android系统是怎样对设备存储空间进行管理和监控的呢?

如果你在使用Android手机时有过把memory填满或者即将填满的经历,也许你会注意到在这种情况下手机的Notifications栏会有“Storage space running out”的通知。当点开该通知你会发现Setting-->Storage settings –>Device memory 下会有如下提示:Not enough storage space.

这个服务的实现是在android/framework/base/services/java/com/android/server/DeviceStorageMonitorService.java。DeviceStorageMonitorService类实现了一个监控设备上存储空间的服务。如果设备的剩余存储空间小于某一个阀值(默认是存储空间的10%,这个值可以设置)时将会向用户发送剩余空间不足的警告,让用户释放一些空间。

下面就分析一下这个类。首先看一下该服务是如何被添加进来的。在android/frameworks/base/services/java/com/android/server/SystemServer.java中使用ServiceManager.addService()来添加系统服务:

在SystemServer中添加DSMS服务:
1
2
3
4
5
6
7
try {
    Slog.i(TAG, "Device Storage Monitor");
    ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
            new DeviceStorageMonitorService(context));
} catch (Throwable e) {
    reportWtf("starting DeviceStorageMonitor service", e);
}
 
DSMS的构造函数的代码如下:
DSMS服务的构造函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    /**
    * Constructor to run service. initializes the disk space threshold value
    * and posts an empty message to kickstart the process.
    */
    public DeviceStorageMonitorService(Context context) {
        mLastReportedFreeMemTime = 0;
        mContext = context;
        mContentResolver = mContext.getContentResolver();
        //create StatFs object
        mDataFileStats = new StatFs(DATA_PATH); //获取Data分区信息;
        mSystemFileStats = new StatFs(SYSTEM_PATH); //获取System分区信息;
        mCacheFileStats = new StatFs(CACHE_PATH); //获取Cache分区信息;
        //initialize total storage on device
        // 初始化设备总空间信息
        // mTotalMemory 用于保存Data分区总空间;
        mTotalMemory = ((long)mDataFileStats.getBlockCount() *
                        mDataFileStats.getBlockSize())/100L;
        /*
        创建3个Intent,分别用于通知存储空间不足(ACTION_DEVICE_STORAGE_LOW)、
        存储空间回复正常(ACTION_DEVICE_STORAGE_OK)和存储空间满(ACTION_DEVICE_STORAGE_FULL)。
        由于每个Intent都设置了FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT标志,因此这三个Intent只
        能由注册了的BroadcastReceiver接收。
        */
        mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
        mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
        mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL);
        mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
        mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        // cache storage thresholds
        /*
        查询Seetings数据库中sys_storage_threshod_percentage的值,默认是10,即当DATA_PATH
        目录下剩余空间少于其总空间的10%时,认为空间不足(ACTION_DEVICE_STORAGE_LOW)。
        */
        mMemLowThreshold = getMemThreshold();
        /*
        查询Settings数据库中的sys_storage_full_threshold_bytes的值,默认是1MB,即当DATA_PATH
        目录下剩余空间小于等于1M时,任务空间已满,剩余的部分是保留给系统使用的。
        */
        mMemFullThreshold = getMemFullThreshold();
        /*
        开始检查,存储空间;
        */
        checkMemory(true);
    }

下面再来看一下checkMemory()方法的实现。

checkMemory()方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
private final 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 {
        //重新计算3个分区的剩余空间大小;
        restatDataDir();
        if (localLOGV)  Slog.v(TAG, "freeMemory="+mFreeMem);

        //post intent to NotificationManager to display icon if necessary
        ////如果剩余空间低于mMemLowThreshold,先做一次缓存清理;
        if (mFreeMem < mMemLowThreshold) {
            if (!mLowMemFlag) {
                if (checkCache) {
                    // 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.
                    //首先清除缓存
                    mThreadStartTime = System.currentTimeMillis();
                    mClearSucceeded = false;
                    clearCache();
                } else {
                    //如果空间仍然低于mMemLowThreshold,发送广播并在状态来设置一个
                    //警告通知;
                    Slog.i(TAG, "Running low on memory. Sending notification");
                    sendNotification();
                    mLowMemFlag = true;
                }
            } else {
                if (localLOGV) Slog.v(TAG, "Running low on memory " +
                        "notification already sent. do nothing");
            }
        } else {
            if (mLowMemFlag) {
                //剩余空间不小于mMemLowThreshold,且已经设置了mLowMemFlag,则
                //取消空间不足广播。
                Slog.i(TAG, "Memory available. Cancelling notification");
                cancelNotification();
                mLowMemFlag = false;
            }
        }
        if (mFreeMem < mMemFullThreshold) {
            //如果空间已满,则发送空间已满的广播;
            if (!mMemFullFlag) {
                sendFullNotification();
                mMemFullFlag = true;
            }
        } else {
            if (mMemFullFlag) {
                //空间不满且已经发送了空间已满的广播,则在此取消。
                cancelFullNotification();
                mMemFullFlag = false;
            }
        }
    }
    if(localLOGV) Slog.i(TAG, "Posting Message again");
    //keep posting messages to itself periodically
    //DEFAULT_CHECK_INTERVAL为1分钟,即每1分钟会触发一次检查 
    postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
}


文章来源:http://kaffeel.org/20130110/android-service%e4%b9%8b%e8%ae%be%e5%a4%87%e5%ad%98%e5%82%a8%e7%a9%ba%e9%97%b4%e7%9b%91%e6%8e%a7-2/