summaryrefslogtreecommitdiffstats
path: root/mobile/android/base/java/org/mozilla/gecko/cleanup/FileCleanupService.java
blob: 76aff733a6acc14e9d2e9a1ad893e3da008eeb7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/.
 */

package org.mozilla.gecko.cleanup;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

import java.io.File;
import java.util.ArrayList;

/**
 * An IntentService to delete files.
 *
 * It takes an {@link ArrayList} of String file paths to delete via the extra
 * {@link #EXTRA_FILE_PATHS_TO_DELETE}. If these file paths are directories, they will
 * not be traversed recursively and will only be deleted if empty. This is to avoid accidentally
 * trashing a users' profile if a folder is accidentally listed.
 *
 * An IntentService was chosen because:
 *   * It generally won't be killed when the Activity is
 *   * (unlike HandlerThread) The system handles scheduling, prioritizing,
 * and shutting down the underlying background thread
 *   * (unlike an existing background thread) We don't block our background operations
 * for this, which doesn't directly affect the user.
 *
 * The major trade-off is that this Service is very dangerous if it's exported... so don't do that!
 */
public class FileCleanupService extends IntentService {
    private static final String LOGTAG = "Gecko" + FileCleanupService.class.getSimpleName();
    private static final String WORKER_THREAD_NAME = LOGTAG + "Worker";

    public static final String ACTION_DELETE_FILES = "org.mozilla.gecko.intent.action.DELETE_FILES";
    public static final String EXTRA_FILE_PATHS_TO_DELETE = "org.mozilla.gecko.file_paths_to_delete";

    public FileCleanupService() {
        super(WORKER_THREAD_NAME);

        // We're likely to get scheduled again - let's wait until then in order to avoid:
        //   * The coding complexity of re-running this
        //   * Consuming system resources: we were probably killed for resource conservation purposes
        setIntentRedelivery(false);
    }

    @Override
    protected void onHandleIntent(final Intent intent) {
        if (!isIntentValid(intent)) {
            return;
        }

        final ArrayList<String> filesToDelete = intent.getStringArrayListExtra(EXTRA_FILE_PATHS_TO_DELETE);
        for (final String path : filesToDelete) {
            final File file = new File(path);
            file.delete();
        }
    }

    private static boolean isIntentValid(final Intent intent) {
        if (intent == null) {
            Log.w(LOGTAG, "Received null intent");
            return false;
        }

        if (!intent.getAction().equals(ACTION_DELETE_FILES)) {
            Log.w(LOGTAG, "Received unknown intent action: " + intent.getAction());
            return false;
        }

        if (!intent.hasExtra(EXTRA_FILE_PATHS_TO_DELETE)) {
            Log.w(LOGTAG, "Received intent with no files extra");
            return false;
        }

        return true;
    }
}