1 // Copyright 2013 The Flutter Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package io.flutter.view; 6 7 import android.content.Context; 8 import android.os.AsyncTask; 9 import android.os.Handler; 10 import android.util.Log; 11 12 import io.flutter.BuildConfig; 13 14 import java.io.File; 15 import java.io.FilenameFilter; 16 17 /** 18 * A class to clean up orphaned resource directories after unclean shutdowns. 19 **/ 20 class ResourceCleaner { 21 private static final String TAG = "ResourceCleaner"; 22 private static final long DELAY_MS = 5000; 23 24 private static class CleanTask extends AsyncTask<Void, Void, Void> { 25 private final File[] mFilesToDelete; 26 CleanTask(File[] filesToDelete)27 CleanTask(File[] filesToDelete) { 28 mFilesToDelete = filesToDelete; 29 } 30 hasFilesToDelete()31 boolean hasFilesToDelete() { 32 return mFilesToDelete != null && mFilesToDelete.length > 0; 33 } 34 35 @Override doInBackground(Void... unused)36 protected Void doInBackground(Void... unused) { 37 if (BuildConfig.DEBUG) { 38 Log.i(TAG, "Cleaning " + mFilesToDelete.length + " resources."); 39 } 40 for (File file : mFilesToDelete) { 41 if (file.exists()) { 42 deleteRecursively(file); 43 } 44 } 45 return null; 46 } 47 deleteRecursively(File parent)48 private void deleteRecursively(File parent) { 49 if (parent.isDirectory()) { 50 for (File child : parent.listFiles()) { 51 deleteRecursively(child); 52 } 53 } 54 parent.delete(); 55 } 56 } 57 58 private final Context mContext; 59 ResourceCleaner(Context context)60 ResourceCleaner(Context context) { 61 mContext = context; 62 } 63 start()64 void start() { 65 File cacheDir = mContext.getCacheDir(); 66 if (cacheDir == null) { 67 return; 68 } 69 70 final CleanTask task = new CleanTask(cacheDir.listFiles(new FilenameFilter() { 71 @Override 72 public boolean accept(File dir, String name) { 73 boolean result = name.startsWith(ResourcePaths.TEMPORARY_RESOURCE_PREFIX); 74 return result; 75 } 76 })); 77 78 if (!task.hasFilesToDelete()) { 79 return; 80 } 81 82 new Handler().postDelayed(new Runnable() { 83 @Override 84 public void run() { 85 task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 86 } 87 }, DELAY_MS); 88 } 89 } 90