Android Low Storage机制(DeviceStorageMonitorService)

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");
            }
        }
    };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值