diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index 3cedc62365..75cfb30bed 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -146,7 +146,6 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.mail.Address; import javax.mail.internet.InternetAddress; @@ -227,7 +226,7 @@ public class AdapterMessage extends RecyclerView.Adapter PARANOID_QUERY = Collections.unmodifiableList(Arrays.asList( diff --git a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java index a255558c18..9572c08f47 100644 --- a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java +++ b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java @@ -44,7 +44,6 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.mail.FetchProfile; import javax.mail.Flags; @@ -74,7 +73,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback emailLookup = new ConcurrentHashMap<>(); private static final Map emailContactInfo = new HashMap<>(); - private static final ExecutorService executor = - Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(1, "contact"); private static final long CACHE_CONTACT_DURATION = 120 * 1000L; diff --git a/app/src/main/java/eu/faircode/email/DB.java b/app/src/main/java/eu/faircode/email/DB.java index 37e4ed5856..af430045ec 100644 --- a/app/src/main/java/eu/faircode/email/DB.java +++ b/app/src/main/java/eu/faircode/email/DB.java @@ -29,7 +29,6 @@ import java.util.Date; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.mail.Address; import javax.mail.internet.InternetAddress; @@ -98,7 +97,8 @@ public abstract class DB extends RoomDatabase { public abstract DaoLog log(); private static DB sInstance; - private static final ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + private static final ExecutorService executor = + Helper.getBackgroundExecutor(1, "query"); private static final String DB_NAME = "fairemail"; private static final long VACUUM_INTERVAL = 24 * 3600 * 1000L; diff --git a/app/src/main/java/eu/faircode/email/EmailProvider.java b/app/src/main/java/eu/faircode/email/EmailProvider.java index 2fb5490df7..b86c73dd8f 100644 --- a/app/src/main/java/eu/faircode/email/EmailProvider.java +++ b/app/src/main/java/eu/faircode/email/EmailProvider.java @@ -53,7 +53,6 @@ import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; public class EmailProvider { @@ -76,7 +75,7 @@ public class EmailProvider { private static final int ISPDB_TIMEOUT = 15 * 1000; // milliseconds private static final ExecutorService executor = - Executors.newCachedThreadPool(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(0, "provider"); private EmailProvider() { } diff --git a/app/src/main/java/eu/faircode/email/EntityLog.java b/app/src/main/java/eu/faircode/email/EntityLog.java index d8c832bfe3..f94864d025 100644 --- a/app/src/main/java/eu/faircode/email/EntityLog.java +++ b/app/src/main/java/eu/faircode/email/EntityLog.java @@ -28,7 +28,6 @@ import androidx.room.PrimaryKey; import java.util.Date; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; @Entity( tableName = EntityLog.TABLE_NAME, @@ -49,7 +48,7 @@ public class EntityLog { public String data; private static final ExecutorService executor = - Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(1, "log"); static void log(Context context, String data) { Log.i(data); diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index e1e1106052..bf8e57331f 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -95,9 +95,13 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.mail.FolderClosedException; @@ -128,20 +132,45 @@ public class Helper { static final String GITHUB_APPS_URI = "https://github.com/M66B?tab=repositories"; static final String TEST_URI = "https://play.google.com/apps/testing/" + BuildConfig.APPLICATION_ID; - static ThreadFactory backgroundThreadFactory = new ThreadFactory() { - private final AtomicInteger threadId = new AtomicInteger(); + static ExecutorService getBackgroundExecutor(int threads, String name) { + ThreadFactory factory = new ThreadFactory() { + private final AtomicInteger threadId = new AtomicInteger(); + + @Override + public Thread newThread(@NonNull Runnable runnable) { + Thread thread = new Thread(runnable); + thread.setName("FairEmail_bg_" + name + "_" + threadId.getAndIncrement()); + thread.setPriority(THREAD_PRIORITY_BACKGROUND); + return thread; + } + }; + + if (threads == 0) + return new ThreadPoolExecutorEx( + 0, Integer.MAX_VALUE, + 60L, TimeUnit.SECONDS, + new SynchronousQueue(), + factory); + else + return new ThreadPoolExecutorEx( + threads, threads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(), + factory); + } + + private static class ThreadPoolExecutorEx extends ThreadPoolExecutor { + public ThreadPoolExecutorEx(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + } @Override - public Thread newThread(@NonNull Runnable runnable) { - Thread thread = new Thread(runnable); - thread.setName("FairEmail_bg_" + threadId.getAndIncrement()); - thread.setPriority(THREAD_PRIORITY_BACKGROUND); - return thread; + protected void beforeExecute(Thread t, Runnable r) { + Log.i("Executing " + t.getName()); } - }; + } - private static final ExecutorService executor = - Executors.newSingleThreadExecutor(backgroundThreadFactory); + private static final ExecutorService executor = getBackgroundExecutor(1, "helper"); // Features diff --git a/app/src/main/java/eu/faircode/email/ImageHelper.java b/app/src/main/java/eu/faircode/email/ImageHelper.java index bf121f92b0..a94adb2ad9 100644 --- a/app/src/main/java/eu/faircode/email/ImageHelper.java +++ b/app/src/main/java/eu/faircode/email/ImageHelper.java @@ -57,7 +57,6 @@ import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -65,7 +64,7 @@ class ImageHelper { private static final float MIN_LUMINANCE = 0.33f; private static final ExecutorService executor = - Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(1, "image"); static Bitmap generateIdenticon(@NonNull String email, int size, int pixels, boolean dark) { byte[] hash = getHash(email); diff --git a/app/src/main/java/eu/faircode/email/MailService.java b/app/src/main/java/eu/faircode/email/MailService.java index 5c386b4596..764b4c7f40 100644 --- a/app/src/main/java/eu/faircode/email/MailService.java +++ b/app/src/main/java/eu/faircode/email/MailService.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.mail.AuthenticationFailedException; import javax.mail.Folder; @@ -40,7 +39,7 @@ public class MailService implements AutoCloseable { private Session isession; private Service iservice; - private ExecutorService executor = Executors.newCachedThreadPool(Helper.backgroundThreadFactory); + private ExecutorService executor = Helper.getBackgroundExecutor(0, "mail"); static final int AUTH_TYPE_PASSWORD = 1; static final int AUTH_TYPE_GMAIL = 2; diff --git a/app/src/main/java/eu/faircode/email/ServiceExternal.java b/app/src/main/java/eu/faircode/email/ServiceExternal.java index 1024b32c9e..751e37ff6e 100644 --- a/app/src/main/java/eu/faircode/email/ServiceExternal.java +++ b/app/src/main/java/eu/faircode/email/ServiceExternal.java @@ -30,7 +30,6 @@ import androidx.core.app.NotificationCompat; import androidx.preference.PreferenceManager; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; public class ServiceExternal extends Service { private static final String ACTION_POLL = BuildConfig.APPLICATION_ID + ".POLL"; @@ -41,7 +40,8 @@ public class ServiceExternal extends Service { // adb shell am startservice -a eu.faircode.email.ENABLE --es account Gmail // adb shell am startservice -a eu.faircode.email.DISABLE --es account Gmail - private static ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + private static final ExecutorService executor = + Helper.getBackgroundExecutor(1, "external"); @Override diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index d4f8d2c3bd..0a1e56208e 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -48,7 +48,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import javax.mail.Address; import javax.mail.AuthenticationFailedException; @@ -65,7 +64,7 @@ public class ServiceSend extends ServiceBase { private boolean lastSuitable = false; private PowerManager.WakeLock wlOutbox; - private ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + private ExecutorService executor = Helper.getBackgroundExecutor(1, "send"); private static final int IDENTITY_ERROR_AFTER = 30; // minutes diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 642b3755bb..472fc7b675 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -58,7 +58,6 @@ import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import javax.mail.AuthenticationFailedException; @@ -91,7 +90,8 @@ public class ServiceSynchronize extends ServiceBase { private int queued = 0; private long lastLost = 0; private TupleAccountStats lastStats = new TupleAccountStats(); - private ExecutorService queue = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + private ExecutorService queue = + Helper.getBackgroundExecutor(1, "service"); private static boolean sync = true; private static boolean oneshot = false; @@ -226,7 +226,7 @@ public class ServiceSynchronize extends ServiceBase { db.message().liveUnseenNotify().observe(cowner, new Observer>() { private ExecutorService executor = - Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(1, "notify"); @Override public void onChanged(final List messages) { @@ -860,7 +860,8 @@ public class ServiceSynchronize extends ServiceBase { Core.onSynchronizeFolders(this, account, iservice.getStore(), state); // Open synchronizing folders - final ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + final ExecutorService executor = + Helper.getBackgroundExecutor(1, "account_" + account.id); List folders = db.folder().getFolders(account.id, false, true); Collections.sort(folders, new Comparator() { diff --git a/app/src/main/java/eu/faircode/email/SimpleTask.java b/app/src/main/java/eu/faircode/email/SimpleTask.java index 584012e4c9..40ca1878cd 100644 --- a/app/src/main/java/eu/faircode/email/SimpleTask.java +++ b/app/src/main/java/eu/faircode/email/SimpleTask.java @@ -39,7 +39,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; // This simple task is simple to use, but it is also simple to cause bugs that can easily lead to crashes // Make sure to not access any member in any outer scope from onExecute @@ -52,8 +51,8 @@ public abstract class SimpleTask implements LifecycleObserver { private static final List tasks = new ArrayList<>(); - private static final ExecutorService executor = Executors.newFixedThreadPool( - Runtime.getRuntime().availableProcessors(), Helper.backgroundThreadFactory); + private static final ExecutorService executor = + Helper.getBackgroundExecutor(Runtime.getRuntime().availableProcessors(), "task"); static final String ACTION_TASK_COUNT = BuildConfig.APPLICATION_ID + ".ACTION_TASK_COUNT"; diff --git a/app/src/main/java/eu/faircode/email/ViewModelMessages.java b/app/src/main/java/eu/faircode/email/ViewModelMessages.java index 0c18251f89..433692ab18 100644 --- a/app/src/main/java/eu/faircode/email/ViewModelMessages.java +++ b/app/src/main/java/eu/faircode/email/ViewModelMessages.java @@ -44,13 +44,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; public class ViewModelMessages extends ViewModel { private AdapterMessage.ViewType last = AdapterMessage.ViewType.UNIFIED; private Map models = new HashMap<>(); - private ExecutorService executor = Executors.newCachedThreadPool(Helper.backgroundThreadFactory); + private ExecutorService executor = Helper.getBackgroundExecutor(2, "model"); private static final int LOCAL_PAGE_SIZE = 100; private static final int REMOTE_PAGE_SIZE = 10; diff --git a/app/src/main/java/eu/faircode/email/Widget.java b/app/src/main/java/eu/faircode/email/Widget.java index 76a4bad8ff..49b91fc679 100644 --- a/app/src/main/java/eu/faircode/email/Widget.java +++ b/app/src/main/java/eu/faircode/email/Widget.java @@ -32,11 +32,10 @@ import androidx.preference.PreferenceManager; import java.text.NumberFormat; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; public class Widget extends AppWidgetProvider { private static final ExecutorService executor = - Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory); + Helper.getBackgroundExecutor(1, "widget"); @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {