Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c0d3505 authored by Neharika Jali's avatar Neharika Jali
Browse files

Periodically clear cache under high storage threshold

Bug: 203650385
Test: atest installd_cache_test
Change-Id: I7660a3b759133b7f5c674061949c9a1df8914928
parent 97c0d421
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -100,6 +100,8 @@ public class Installer extends SystemService {
    public static final int FLAG_FREE_CACHE_V2 = IInstalld.FLAG_FREE_CACHE_V2;
    public static final int FLAG_FREE_CACHE_V2_DEFY_QUOTA = IInstalld.FLAG_FREE_CACHE_V2_DEFY_QUOTA;
    public static final int FLAG_FREE_CACHE_NOOP = IInstalld.FLAG_FREE_CACHE_NOOP;
    public static final int FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES =
            IInstalld.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES;

    public static final int FLAG_USE_QUOTA = IInstalld.FLAG_USE_QUOTA;
    public static final int FLAG_FORCE = IInstalld.FLAG_FORCE;
+17 −0
Original line number Diff line number Diff line
@@ -2733,6 +2733,23 @@ public class PackageManagerService extends IPackageManager.Stub
        });
    }

    /**
     * Blocking call to clear all cached app data above quota.
     */
    public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException {
        synchronized (mInstallLock) {
            // To avoid refactoring Installer.freeCache() and InstalldNativeService.freeCache(),
            // Long.MAX_VALUE is passed as an argument which is used in neither of two methods
            // when FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES is set
            try {
                mInstaller.freeCache(volumeUuid, Long.MAX_VALUE, Installer.FLAG_FREE_CACHE_V2
                        | Installer.FLAG_FREE_CACHE_DEFY_TARGET_FREE_BYTES);
            } catch (InstallerException ignored) {
            }
        }
        return;
    }

    /**
     * Blocking call to clear various types of cached data across the system
     * until the requested bytes are available.
+62 −21
Original line number Diff line number Diff line
@@ -75,10 +75,12 @@ public class DeviceStorageMonitorService extends SystemService {
     */
    public static final String EXTRA_SEQUENCE = "seq";

    private static final int MSG_CHECK = 1;
    private static final int MSG_CHECK_LOW = 1;
    private static final int MSG_CHECK_HIGH = 2;

    private static final long DEFAULT_LOG_DELTA_BYTES = DataUnit.MEBIBYTES.toBytes(64);
    private static final long DEFAULT_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
    private static final long LOW_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS;
    private static final long HIGH_CHECK_INTERVAL = 10 * DateUtils.HOUR_IN_MILLIS;

    // com.android.internal.R.string.low_internal_storage_view_text_no_boot
    // hard codes 250MB in the message as the storage space required for the
@@ -165,12 +167,12 @@ public class DeviceStorageMonitorService extends SystemService {
    }

    /**
     * Core logic that checks the storage state of every mounted private volume.
     * Since this can do heavy I/O, callers should invoke indirectly using
     * {@link #MSG_CHECK}.
     * Core logic that checks the storage state of every mounted private volume and clears cache
     * under low storage state. Since this can do heavy I/O, callers should invoke indirectly using
     * {@link #MSG_CHECK_LOW}.
     */
    @WorkerThread
    private void check() {
    private void checkLow() {
        final StorageManager storage = getContext().getSystemService(StorageManager.class);
        final int seq = mSeq.get();

@@ -234,9 +236,45 @@ public class DeviceStorageMonitorService extends SystemService {

        // 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);
        if (!mHandler.hasMessages(MSG_CHECK_LOW)) {
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_LOW),
                    LOW_CHECK_INTERVAL);
        }
        if (!mHandler.hasMessages(MSG_CHECK_HIGH)) {
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
                    HIGH_CHECK_INTERVAL);
        }
    }

    /**
     * Core logic that checks the storage state of every mounted private volume and clears cache if
     * free space is under 20% of total space. Since this can do heavy I/O, callers should invoke
     * indirectly using {@link #MSG_CHECK_HIGH}.
     */
    @WorkerThread
    private void checkHigh() {
        final StorageManager storage = getContext().getSystemService(StorageManager.class);
        // Check every mounted private volume to see if they're under the high storage threshold
        // which is StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH of total space
        for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
            final File file = vol.getPath();
            if (file.getUsableSpace() < file.getTotalSpace()
                    * StorageManager.STORAGE_THRESHOLD_PERCENT_HIGH / 100) {
                final PackageManagerService pms = (PackageManagerService) ServiceManager
                        .getService("package");
                try {
                    pms.freeAllAppCacheAboveQuota(vol.getFsUuid());
                } catch (IOException e) {
                    Slog.w(TAG, e);
                }
            }
        }

        // 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_HIGH)) {
            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_HIGH),
                    HIGH_CHECK_INTERVAL);
        }
    }

@@ -250,8 +288,11 @@ public class DeviceStorageMonitorService extends SystemService {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_CHECK:
                        check();
                    case MSG_CHECK_LOW:
                        checkLow();
                        return;
                    case MSG_CHECK_HIGH:
                        checkHigh();
                        return;
                }
            }
@@ -282,16 +323,16 @@ public class DeviceStorageMonitorService extends SystemService {
        publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);

        // Kick off pass to examine storage state
        mHandler.removeMessages(MSG_CHECK);
        mHandler.obtainMessage(MSG_CHECK).sendToTarget();
        mHandler.removeMessages(MSG_CHECK_LOW);
        mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
    }

    private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
        @Override
        public void checkMemory() {
            // Kick off pass to examine storage state
            mHandler.removeMessages(MSG_CHECK);
            mHandler.obtainMessage(MSG_CHECK).sendToTarget();
            mHandler.removeMessages(MSG_CHECK_LOW);
            mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
        }

        @Override
@@ -360,8 +401,8 @@ public class DeviceStorageMonitorService extends SystemService {
                mForceLevel = State.LEVEL_LOW;
                int seq = mSeq.incrementAndGet();
                if ((opts & OPTION_FORCE_UPDATE) != 0) {
                    mHandler.removeMessages(MSG_CHECK);
                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
                    mHandler.removeMessages(MSG_CHECK_LOW);
                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                    pw.println(seq);
                }
            } break;
@@ -372,8 +413,8 @@ public class DeviceStorageMonitorService extends SystemService {
                mForceLevel = State.LEVEL_NORMAL;
                int seq = mSeq.incrementAndGet();
                if ((opts & OPTION_FORCE_UPDATE) != 0) {
                    mHandler.removeMessages(MSG_CHECK);
                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
                    mHandler.removeMessages(MSG_CHECK_LOW);
                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                    pw.println(seq);
                }
            } break;
@@ -384,8 +425,8 @@ public class DeviceStorageMonitorService extends SystemService {
                mForceLevel = State.LEVEL_UNKNOWN;
                int seq = mSeq.incrementAndGet();
                if ((opts & OPTION_FORCE_UPDATE) != 0) {
                    mHandler.removeMessages(MSG_CHECK);
                    mHandler.obtainMessage(MSG_CHECK).sendToTarget();
                    mHandler.removeMessages(MSG_CHECK_LOW);
                    mHandler.obtainMessage(MSG_CHECK_LOW).sendToTarget();
                    pw.println(seq);
                }
            } break;