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

Commit 3a8b0c18 authored by Dan Egnor's avatar Dan Egnor
Browse files

Limit DropBox storage to 1000 files (by default).

Also does trimming asynchronously (not directly in the broadcast receiver).

Bug: 2541253
Change-Id: I7daf8bc618e2dce68a98571f5f7fbce4df1d6a76
parent 3e8b72ac
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2902,6 +2902,12 @@ public final class Settings {
         */
        public static final String DROPBOX_AGE_SECONDS =
                "dropbox_age_seconds";
        /**
         * Maximum number of entry files which {@link android.os.IDropBox} will keep around.
         * @hide
         */
        public static final String DROPBOX_MAX_FILES =
                "dropbox_max_files";
        /**
         * Maximum amount of disk space used by {@link android.os.IDropBox} no matter what.
         * @hide
+22 −11
Original line number Diff line number Diff line
@@ -61,10 +61,11 @@ import java.util.zip.GZIPOutputStream;
 */
public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
    private static final String TAG = "DropBoxManagerService";
    private static final int DEFAULT_RESERVE_PERCENT = 10;
    private static final int DEFAULT_QUOTA_PERCENT = 10;
    private static final int DEFAULT_QUOTA_KB = 5 * 1024;
    private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
    private static final int DEFAULT_MAX_FILES = 1000;
    private static final int DEFAULT_QUOTA_KB = 5 * 1024;
    private static final int DEFAULT_QUOTA_PERCENT = 10;
    private static final int DEFAULT_RESERVE_PERCENT = 10;
    private static final int QUOTA_RESCAN_MILLIS = 5000;

    private static final boolean PROFILE_DUMP = false;
@@ -99,6 +100,12 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
        @Override
        public void onReceive(Context context, Intent intent) {
            mCachedQuotaUptimeMillis = 0;  // Force a re-check of quota size

            // Run the initialization in the background (not this main thread).
            // The init() and trimToFit() methods are synchronized, so they still
            // block other users -- but at least the onReceive() call can finish.
            new Thread() {
                public void run() {
                    try {
                        init();
                        trimToFit();
@@ -106,6 +113,8 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
                        Slog.e(TAG, "Can't init", e);
                    }
                }
            }.start();
        }
    };

    /**
@@ -631,10 +640,12 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {

        int ageSeconds = Settings.Secure.getInt(mContentResolver,
                Settings.Secure.DROPBOX_AGE_SECONDS, DEFAULT_AGE_SECONDS);
        int maxFiles = Settings.Secure.getInt(mContentResolver,
                Settings.Secure.DROPBOX_MAX_FILES, DEFAULT_MAX_FILES);
        long cutoffMillis = System.currentTimeMillis() - ageSeconds * 1000;
        while (!mAllFiles.contents.isEmpty()) {
            EntryFile entry = mAllFiles.contents.first();
            if (entry.timestampMillis > cutoffMillis) break;
            if (entry.timestampMillis > cutoffMillis && mAllFiles.contents.size() < maxFiles) break;

            FileList tag = mFilesByTag.get(entry.tag);
            if (tag != null && tag.contents.remove(entry)) tag.blocks -= entry.blocks;
@@ -673,7 +684,7 @@ public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
        // A single circular buffer (a la logcat) would be simpler, but this
        // way we can handle fat/bursty data (like 1MB+ bugreports, 300KB+
        // kernel crash dumps, and 100KB+ ANR reports) without swamping small,
        // well-behaved data // streams (event statistics, profile data, etc).
        // well-behaved data streams (event statistics, profile data, etc).
        //
        // Deleted files are replaced with zero-length tombstones to mark what
        // was lost.  Tombstones are expunged by age (see above).
+50 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ public class DropBoxTest extends AndroidTestCase {
    public void tearDown() throws Exception {
        ContentResolver cr = getContext().getContentResolver();
        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_AGE_SECONDS, "");
        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "");
        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_QUOTA_KB, "");
        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_TAG_PREFIX + "DropBoxTest", "");
    }
@@ -457,6 +458,55 @@ public class DropBoxTest extends AndroidTestCase {
        e0.close();
    }

    public void testFileCountLimits() throws Exception {
        File dir = getEmptyDir("testFileCountLimits");

        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
        DropBoxManager dropbox = new DropBoxManager(service);
        dropbox.addText("DropBoxTest", "TEST0");
        dropbox.addText("DropBoxTest", "TEST1");
        dropbox.addText("DropBoxTest", "TEST2");
        dropbox.addText("DropBoxTest", "TEST3");
        dropbox.addText("DropBoxTest", "TEST4");
        dropbox.addText("DropBoxTest", "TEST5");

        // Verify 6 files added
        DropBoxManager.Entry e0 = dropbox.getNextEntry(null, 0);
        DropBoxManager.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
        DropBoxManager.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
        DropBoxManager.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
        DropBoxManager.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
        DropBoxManager.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
        assertTrue(null == dropbox.getNextEntry(null, e5.getTimeMillis()));
        assertEquals("TEST0", e0.getText(80));
        assertEquals("TEST5", e5.getText(80));

        e0.close();
        e1.close();
        e2.close();
        e3.close();
        e4.close();
        e5.close();

        // Limit to 3 files and add one more entry
        ContentResolver cr = getContext().getContentResolver();
        Settings.Secure.putString(cr, Settings.Secure.DROPBOX_MAX_FILES, "3");
        dropbox.addText("DropBoxTest", "TEST6");

        // Verify only 3 files left
        DropBoxManager.Entry f0 = dropbox.getNextEntry(null, 0);
        DropBoxManager.Entry f1 = dropbox.getNextEntry(null, f0.getTimeMillis());
        DropBoxManager.Entry f2 = dropbox.getNextEntry(null, f1.getTimeMillis());
        assertTrue(null == dropbox.getNextEntry(null, f2.getTimeMillis()));
        assertEquals("TEST4", f0.getText(80));
        assertEquals("TEST5", f1.getText(80));
        assertEquals("TEST6", f2.getText(80));

        f0.close();
        f1.close();
        f2.close();
    }

    public void testCreateDropBoxManagerWithInvalidDirectory() throws Exception {
        // If created with an invalid directory, the DropBoxManager should suffer quietly
        // and fail all operations (this is how it survives a full disk).