前言
对于低存储空间的设备,比如穿戴设备等,存储空间可能只有32G。在这样的设备上安装第三方应用会占用较大的存储空间,因此需要对可用的存储空间进行监控。
一、DeviceStorageMonitorService
系统中存在原生的存储空间的监控机制,当可用空间很少时,会发出notification提示用户。
该监控是存在于DeviceStorageMonitorService.java中。
/frameworks/base/services/java/com/android/server/SystemServer.java
t.traceBegin("StartDeviceMonitor");
mSystemServiceManager.startService(DeviceStorageMonitorService.class);
t.traceEnd();
/frameworks/base/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@Override
public void onStart() {
final Context context = getContext();
mNotifManager = context.getSystemService(NotificationManager.class);
mCacheFileDeletedObserver = new CacheFileDeletedObserver();
mCacheFileDeletedObserver.startWatching();
...
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
// Kick off pass to examine storage statemHandler.removeMessages(MSG_CHECK);
// 服务开始后便开始进行check
mHandler.obtainMessage(MSG_CHECK).sendToTarget();
}
在check()方法中检查存储空间,之后发送1分钟的delay message,然后是下次的重复检查。当出现低存储时会发送notification以及broadcast。
@WorkerThread
private void check() {
final StorageManager storage = getContext().getSystemService(StorageManager.class);
final int seq = mSeq.get();
// Check every mounted private volume to see if they're low on space
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final File file = vol.getPath();
final long fullBytes = storage.getStorageFullBytes(file);
final long lowBytes = storage.getStorageLowBytes(file);
// Automatically trim cached data when nearing the low threshold;
// when it's within 150% of the threshold, we try trimming usage
// back to 200% of the threshold.
if (file.getUsableSpace() < (lowBytes * 3) / 2) {
final PackageManagerService pms = (PackageManagerService) ServiceManager
.getService("package");
try {
pms.freeStorage(vol.getFsUuid(), lowBytes * 2, 0);
} catch (IOException e) {
Slog.w(TAG, e);
}
}
// Send relevant broadcasts and show notifications based on any
// recently noticed state transitions.
final UUID uuid = StorageManager.convert(vol.getFsUuid());
final State state = findOrCreateState(uuid);
final long totalBytes = file.getTotalSpace();
final long usableBytes = file.getUsableSpace();
int oldLevel = state.level;
int newLevel;
if (mForceLevel != State.LEVEL_UNKNOWN) {
// When in testing mode, use unknown old level to force sending
// of any relevant broadcasts.
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;
}
// Log whenever we notice drastic storage changes
if ((Math.abs(state.lastUsableBytes - usableBytes) > DEFAULT_LOG_DELTA_BYTES)
|| oldLevel != newLevel) {
EventLogTags.writeStorageState(uuid.toString(), oldLevel, newLevel,
usableBytes, totalBytes);
state.lastUsableBytes = usableBytes;
}
//发送notification以及broadcast
updateNotifications(vol, oldLevel, newLevel);
updateBroadcasts(vol, oldLevel, newLevel, seq);
state.level = newLevel;
}
// Loop around to check again in future; we don't remove messages since
// there might be an immediate request pending.
if (!mHandler.hasMessages(MSG_CHECK)) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK),
DEFAULT_CHECK_INTERVAL);
}
}
当前系统分了几个等级
LEVEL_UNKNOWN:
LEVEL_NORMAL:正常
LEVEL_LOW:低存储空间,空间不足5%或者不足500M时(选其中较低的值)
LEVEL_FULL:存储空间已满,空间不足1M时
updateNotifications(vol, oldLevel, newLevel);会在空间不足或者解除了空间不足时发送相关的notification。
updateBroadcasts(vol, oldLevel, newLevel, seq);会发送一些广播来通知其他应用空间不足或者解除空间不足的情况。
LEVEL_LOW时发送广播
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@Deprecated
public static final String ACTION_DEVICE_STORAGE_LOW = "android.intent.action.DEVICE_STORAGE_LOW";
退出LEVEL_LOW时发送广播
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@Deprecated
public static final String ACTION_DEVICE_STORAGE_OK = "android.intent.action.DEVICE_STORAGE_OK";