文章目录
1.low storage简介(DeviceStorageMonitorService)
Device storage monitor module is composed of device monitor service (Google default)The purposes of device storage monitor service are monitoring device storage status and handling low storage conditions.。
在O之前mtk会定制些low storage的处理,后续已经取消
设备存储监视器服务是一个模块用来
- 1.监视设备存储(“/ data”)。
- 2.每60秒扫描一次免费存储空间(谷歌默认值)
- 3.当设备的存储空间不足时生成“低存储”通知。 //updateNotifications
- 4.引导用户管理设备中安装的所有应用程序,并发送意图。 //updateBroadcasts
- 5.存储严重不足时显示警告对话框。
- 6.为AMS/PMS提供公共API以查询存储状态
2. DeviceStorageMonitorService代码介绍
2.1 服务初始化
- DeviceStorageMonitorService初始化handler用于check
- SystemService.onStart()时,获取通知,添加devicestoragemonitor到Binder Service
- 执行check()
public class DeviceStorageMonitorService extends SystemService {
static final String SERVICE = "devicestoragemonitor";
private static final String TV_NOTIFICATION_CHANNEL_ID = "devicestoragemonitor.tv";
public DeviceStorageMonitorService(Context context) {
super(context);
//初始化HandlerThread后台线程,做check()
mHandlerThread = new HandlerThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CHECK:
check();
return;
}
}
};
}
@Override
public void onStart() {
final Context context = getContext();
//获取通知服务,发送通知
mNotifManager = context.getSystemService(NotificationManager.class);
//cacheFile通知
mCacheFileDeletedObserver = new CacheFileDeletedObserver();
mCacheFileDeletedObserver.startWatching();
// Ensure that the notification channel is set up
PackageManager packageManager = context.getPackageManager();
//判断是否是TV
boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
//电视使用TV_NOTIFICATION_CHANNEL_ID
if (isTv) {
mNotifManager.createNotificationChannel(new NotificationChannel(
TV_NOTIFICATION_CHANNEL_ID,
context.getString(
com.android.internal.R.string.device_storage_monitor_notification_channel),
NotificationManager.IMPORTANCE_HIGH));
}
//addService到BinderService,也添加到LocalService
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
//开始check()
// Kick off pass to examine storage state
mHandler.removeMessages(MSG_CHECK);
mHandler.obtainMessage(MSG_CHECK).sendToTarget();
}
2.2 DeviceStorageMonitorInternal提供的接口
//内部服务提供check():检测接口 isMemoryLow:是否LowStorage getMemoryLowThreshold:data的低存储值
private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
@Override
//发送Msg触发Handler,check()
public void checkMemory() {
// Kick off pass to examine storage state
mHandler.removeMessages(MSG_CHECK);
mHandler.obtainMessage(MSG_CHECK).sendToTarget();
}
//data分区可使用空间<500M
@Override
public boolean isMemoryLow() {
return Environment.getDataDirectory().getUsableSpace() < getMemoryLowThreshold();
}
//500M,具体项目在看
@Override
public long getMemoryLowThreshold() {
return getContext().getSystemService(StorageManager.class)
.getStorageLowBytes(Environment.getDataDirectory());
}
};
2.3 check() /data分区
getUsableSpace获取可用大小
@WorkerThread
private void check() {
final StorageManager storage = getContext().getSystemService(StorageManager.class);
final int seq = mSeq.get();
//本地打印只有/data目录
// 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);//500M
// 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");
//lowBytes的1.5倍容量时触发freeStorage
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();//data总大小
final long usableBytes = file.getUsableSpace();//可使用大小
int oldLevel = state.level;
int newLevel;
//判断是LEVEL_LOW,LEVEL_FULL还是LEVEL_NORMAL
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) {
//log
EventLogTags.writeStorageState(uuid.toString(), oldLevel, newLevel,
usableBytes, totalBytes);
state.lastUsableBytes = usableBytes;
}
//发送通知
updateNotifications(vol, oldLevel, newLevel);
//发送广播
updateBroadcasts(vol, oldLevel, newLevel, seq);
state.level = newLevel;
}
//没有check消息,继续30s检测
// 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);
}
}
private void updateBroadcasts(VolumeInfo vol, int oldLevel, int newLevel, int seq) {
if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, vol.getFsUuid())) {
// We don't currently send broadcasts for secondary volumes
return;
}
//lowStorage广播action ACTION_DEVICE_STORAGE_LOW
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);
//正常Storage广播action ACTION_DEVICE_STORAGE_OK
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)) {
//只发送一次广播ACTION_DEVICE_STORAGE_LOW,粘性广播,进程注册肯定会收到广播
getContext().sendStickyBroadcastAsUser(lowIntent, UserHandle.ALL);
} else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) {
//恢复正常移除lowIntent粘性广播,发送normal的普通广播
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);
//发送FULL Storage广播ACTION_DEVICE_STORAGE_FULL
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);
}
}
3 监听lowStorage广播
public void registerLowStorageBroadcast() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
mContext.registerReceiver(mReceiver, filter);
}
/** Receives events that might indicate a need to clean up files. */
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
Log.i(TAG, "handleStorageLow storage Low");
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
Log.i(TAG, "handleStorageLow storage Ok");
}
}
};