您的位置:首页 > 移动开发 > Android开发

Android Service之设备存储空间监控

2013-04-07 15:20 323 查看
http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763104f84324d03d73d2bd7a7483f818e4891675a434464e8a6747e46448e9e2a7001d9080baab46d23601457b18cb8835dd7cb855f259f5443676cf15665d40edccd512fc437e75dfedc6ff0b1fa25e4a9c5d9df4320c044727f9783804d7067dd18fb033ae6b1e94e022815ade64072f45a605e9b344ac1508ae52f7a42dcb68b530d8577903244c0b835c17f50e642f3081b5504e710ed530d7327e03e7ab802&p=c665c54ad6c24ac30be29f28174f82&newp=c957c64add962dfd05bd9b7e0c1dc4231610db2151d4d21e2ab8c115&user=baidu&fm=sc&query=storage+space+running+out&qid=&p1=1

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

如果你在使用Android手机时有过把memory填满或者即将填满的经历,也许你会注意到在这种情况下手机的Notifications栏会有“Storagespacerunningout”的通知。当点开该通知你会发现Setting–>Storage
settings –>Device memory 下会有如下提示:Not enoughstorage 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);

}

//mLowMemFlag和mMemFullFlag为是否发送了广播的标识。

当空间不足时,DSMS会先尝试clearCache函数,该函数内部会与PackageManager-Service(以下简称PKMS)交互,其代码如下:

[-->DeviceStorageManagerService.java::clearCache]

private final void clearCache() {

if (mClearCacheObserver == null) {

//创建一个CachePackageDataObserver对象,当PKMS清理完空间时会回调该对象的

//onRemoveCompleted函数

mClearCacheObserver = new CachePackageDataObserver();

}

mClearingCache = true;//设置mClearingCache的值为true,表示我们正在清理空间

try {

//调用PKMS的freeStorageAndNotify函数以清理空间,这个函数在分析PKMS时再介绍

IPackageManager.Stub.asInterface(

ServiceManager.getService("package")).

freeStorageAndNotify(mMemLowThreshold, mClearCacheObserver);
//该函数在PackageManagerservice.java

} ......

}

CachePackageDataObserver是DSMS定义的内部类,其onRemoveCompleted函数很简单,就是重新发送消息DEVICE_MEMORY_WHAT (postCheckMemoryMsg(false, 0);),让DSMS再检测一次存储空间。如果剩余空间小于10%,则发送sendNotification()提示 storage space running out。

DeviceStorageManagerService的功能单一,没有重载dump函数。而DiskStats-Service唯一有用的就是dump功能了。不知Google的工程师为什么没有把DeviceStorage-ManagerService和DiskStatsService的功能整合到一起。

ps:

你饿了,想吃饭,就一会去问你妈一声"开饭没有啊?"这就正常函数调用.

但是今天你妈包饺子,花的时间比较长,你跑啊跑啊,就烦了.于是你给你妈说,我先出去玩会,开饭的时候打我手机.等过了一阵,你妈给你打电话说"开饭啦,快回来吃饭吧!"

其中,你告诉你妈打手机找你,就是个你把回调函数句柄保存到你妈的动作.你妈打电话叫你,就是个回调过程.

总结:

(1)首先在构造函数中,获取data,system,cache分区信息,然后注册四个intent,分别为低内存,内存ok,内存满,内存没有满四种情况。然后获取settings数据库里的data目录下剩余空间少于其总空间的百分比值,获取数据库中data目录下剩余空间的大小临界值(用于提示用户空间已满)。然后开始检查,存储空间;checkMemory(true);

(2)

在检查存储空间时,首先判断如果线程正在清除缓存CACHE_PATH ,那么不进行空间检查。否则重新计算3个分区的剩余空间大小。如果剩余空间低于百分比10%,如果需要做缓存清理,先做一次缓存清理;清理完毕后会再次进行新一轮的checkMemory,如果剩余空间低于百分比10%并不用做缓存清理并且没有发通知,则发送通知告诉用户内部空间超出最低值10%,如果此时空间百分比正常,但已发送通知,则将通知取消。同样的,如果空间已满,大于full的临界值,则发送空间已满的广播;空间不满且已经发送了空间已满的广播,则取消。最后会每1分钟会触发一次检查空间checkMemory。

如下:清理完毕后会再次进行新一轮的checkMemory:

做一下onRemoveCompleted动作,该动作发送检查空间的消息【postCheckMemoryMsg(false, 0);这里的false就是不再执行clearCache】,然后handle处理该消息DEVICE_MEMORY_WHAT,再次进入checkMemory(false),发送通知告诉用户storage space running out,空間剩10%時會出現该提示。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: