diff --git a/app/src/main/java/eu/faircode/email/ActivityAnswer.java b/app/src/main/java/eu/faircode/email/ActivityAnswer.java index c361ee8577..157576a536 100644 --- a/app/src/main/java/eu/faircode/email/ActivityAnswer.java +++ b/app/src/main/java/eu/faircode/email/ActivityAnswer.java @@ -37,10 +37,8 @@ import androidx.constraintlayout.widget.Group; import java.util.Date; import java.util.List; -import java.util.concurrent.ExecutorService; public class ActivityAnswer extends ActivityBase { - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "answer"); @Override @RequiresApi(api = Build.VERSION_CODES.M) @@ -71,7 +69,7 @@ public class ActivityAnswer extends ActivityBase { final Context context = adapterView.getContext(); EntityAnswer answer = (EntityAnswer) adapterView.getAdapter().getItem(pos); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/ActivitySetup.java b/app/src/main/java/eu/faircode/email/ActivitySetup.java index 392aac6f4c..52336d96be 100644 --- a/app/src/main/java/eu/faircode/email/ActivitySetup.java +++ b/app/src/main/java/eu/faircode/email/ActivitySetup.java @@ -1401,9 +1401,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) continue; - if ("query_threads".equals(key)) - continue; - // Prevent restart if ("secure".equals(key) || "load_emoji".equals(key) || diff --git a/app/src/main/java/eu/faircode/email/AdapterContact.java b/app/src/main/java/eu/faircode/email/AdapterContact.java index ab3fdd2359..0b8756634a 100644 --- a/app/src/main/java/eu/faircode/email/AdapterContact.java +++ b/app/src/main/java/eu/faircode/email/AdapterContact.java @@ -59,7 +59,6 @@ import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutorService; public class AdapterContact extends RecyclerView.Adapter { private Fragment parentFragment; @@ -80,9 +79,6 @@ public class AdapterContact extends RecyclerView.Adapter { private Fragment parentFragment; @@ -58,9 +57,6 @@ public class AdapterLog extends RecyclerView.Adapter { private DateFormat TF; - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "contacts"); - public class ViewHolder extends RecyclerView.ViewHolder { private TextView tvTime; private TextView tvData; @@ -174,7 +170,7 @@ public class AdapterLog extends RecyclerView.Adapter { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(parentFragment.getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(context, owner, new Bundle(), "logs:filter"); + }.serial().execute(context, owner, new Bundle(), "logs:filter"); } public void setTypes(@NonNull List types) { diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index f6460ffc6a..ea6346f817 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -334,9 +334,6 @@ public class AdapterMessage extends RecyclerView.Adapter config = new AsyncDifferConfig.Builder<>(callback) - .setBackgroundThreadExecutor(executor) + .setBackgroundThreadExecutor(Helper.getParallelExecutor()) .build(); this.differ = new AsyncPagedListDiffer<>(new AdapterListUpdateCallback(this), config); this.differ.addPagedListListener(new AsyncPagedListDiffer.PagedListListener() { diff --git a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java index 524c2b3be2..944ecbf088 100644 --- a/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java +++ b/app/src/main/java/eu/faircode/email/BoundaryCallbackMessages.java @@ -59,7 +59,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -99,7 +98,6 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback emailLookup = new ConcurrentHashMap<>(); private static final Map emailContactInfo = new HashMap<>(); - private static final ExecutorService executorLookup = - Helper.getBackgroundExecutor(1, "contact"); - - private static final ExecutorService executorFavicon = - Helper.getBackgroundExecutor(0, "favicon"); - private static final int GENERATED_ICON_SIZE = 48; // dp private static final int FAVICON_ICON_SIZE = 64; // dp private static final int FAVICON_CONNECT_TIMEOUT = 5 * 1000; // milliseconds @@ -207,7 +200,7 @@ public class ContactInfo { for (String type : new String[]{"favicons", "generated"}) { final File dir = new File(context.getFilesDir(), type); - executorFavicon.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { @@ -381,7 +374,7 @@ public class ContactInfo { List> futures = new ArrayList<>(); if (bimi) - futures.add(executorFavicon.submit(new Callable() { + futures.add(Helper.getParallelExecutor().submit(new Callable() { @Override public Favicon call() throws Exception { Pair bimi = @@ -391,9 +384,9 @@ public class ContactInfo { })); if (gravatars) - futures.add(executorFavicon.submit(Avatar.getGravatar(email, scaleToPixels, context))); + futures.add(Helper.getParallelExecutor().submit(Avatar.getGravatar(email, scaleToPixels, context))); if (libravatars) - futures.add(executorFavicon.submit(Avatar.getLibravatar(email, scaleToPixels, context))); + futures.add(Helper.getParallelExecutor().submit(Avatar.getLibravatar(email, scaleToPixels, context))); if (favicons) { String host = domain; @@ -402,7 +395,7 @@ public class ContactInfo { while (host.indexOf('.') > 0) { final URL base = new URL("https://" + host); - futures.add(executorFavicon.submit(new Callable() { + futures.add(Helper.getParallelExecutor().submit(new Callable() { @Override public Favicon call() throws Exception { return parseFavicon(base, scaleToPixels, context); @@ -420,7 +413,7 @@ public class ContactInfo { final URL base = new URL("https://" + host); for (String name : FIXED_FAVICONS) - futures.add(executorFavicon.submit(new Callable() { + futures.add(Helper.getParallelExecutor().submit(new Callable() { @Override public Favicon call() throws Exception { return getFavicon(new URL(base, name), null, scaleToPixels, context); @@ -752,7 +745,7 @@ public class ContactInfo { continue; final URL url = new URL(base, favicon); - futures.add(executorFavicon.submit(new Callable>() { + futures.add(Helper.getParallelExecutor().submit(new Callable>() { @Override public Pair call() throws Exception { return new Pair(getFavicon(url, img.attr("type"), scaleToPixels, context), url); @@ -901,7 +894,7 @@ public class ContactInfo { @Override public void onChange(boolean selfChange, Uri uri) { Log.i("Contact changed uri=" + uri); - executorLookup.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { @@ -914,7 +907,7 @@ public class ContactInfo { } }; - executorLookup.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/DB.java b/app/src/main/java/eu/faircode/email/DB.java index 5d1c5ba2c2..55d50c9a06 100644 --- a/app/src/main/java/eu/faircode/email/DB.java +++ b/app/src/main/java/eu/faircode/email/DB.java @@ -41,7 +41,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; -import java.util.concurrent.ExecutorService; import javax.mail.Address; import javax.mail.internet.InternetAddress; @@ -363,7 +362,7 @@ public abstract class DB extends RoomDatabase { sInstance = migrate(sContext, getBuilder(sContext)).build(); - sInstance.getQueryExecutor().execute(new Runnable() { + Helper.getSerialExecutor().execute(new Runnable() { @Override public void run() { checkEmergencyBackup(sContext); @@ -399,17 +398,14 @@ public abstract class DB extends RoomDatabase { private static RoomDatabase.Builder getBuilder(Context context) { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - int threads = prefs.getInt("query_threads", DEFAULT_QUERY_THREADS); boolean wal = prefs.getBoolean("wal", true); - Log.i("DB query threads=" + threads + " wal=" + wal); - ExecutorService executorQuery = Helper.getBackgroundExecutor(threads, "query"); - ExecutorService executorTransaction = Helper.getBackgroundExecutor(0, "transaction"); + Log.i("DB wal=" + wal); RoomDatabase.Builder builder = Room .databaseBuilder(context, DB.class, DB_NAME) //.openHelperFactory(new RequerySQLiteOpenHelperFactory()) - .setQueryExecutor(executorQuery) - .setTransactionExecutor(executorTransaction) + //.setQueryExecutor() + .setTransactionExecutor(Helper.getParallelExecutor()) .setJournalMode(wal ? JournalMode.WRITE_AHEAD_LOGGING : JournalMode.TRUNCATE) // using the latest sqlite .addCallback(new Callback() { @Override @@ -486,7 +482,7 @@ public abstract class DB extends RoomDatabase { public void onQuery(@NonNull String sqlQuery, @NonNull List bindArgs) { Log.i("query=" + sqlQuery); } - }, executorQuery); + }, Helper.getParallelExecutor()); return builder; } @@ -2611,7 +2607,7 @@ public abstract class DB extends RoomDatabase { public static void checkpoint(Context context) { // https://www.sqlite.org/pragma.html#pragma_wal_checkpoint DB db = getInstance(context); - db.getQueryExecutor().execute(new Runnable() { + Helper.getParallelExecutor().execute(new Runnable() { @Override public void run() { try { @@ -2641,7 +2637,7 @@ public abstract class DB extends RoomDatabase { public static void shrinkMemory(Context context) { DB db = getInstance(context); - db.getQueryExecutor().execute(new Runnable() { + Helper.getParallelExecutor().execute(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java b/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java index 36d78a0bdf..fa0c1fb5b9 100644 --- a/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java +++ b/app/src/main/java/eu/faircode/email/DisconnectBlacklist.java @@ -40,13 +40,11 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.concurrent.ExecutorService; import javax.net.ssl.HttpsURLConnection; public class DisconnectBlacklist { private static final Map> map = new HashMap<>(); - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "disconnect"); private final static int FETCH_TIMEOUT = 20 * 1000; // milliseconds private final static String LIST = "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json"; @@ -54,7 +52,7 @@ public class DisconnectBlacklist { static void init(Context context) { final File file = getFile(context); - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/EditTextCompose.java b/app/src/main/java/eu/faircode/email/EditTextCompose.java index 271576b5de..4d1202f74b 100644 --- a/app/src/main/java/eu/faircode/email/EditTextCompose.java +++ b/app/src/main/java/eu/faircode/email/EditTextCompose.java @@ -59,7 +59,6 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import java.util.List; -import java.util.concurrent.ExecutorService; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; @@ -78,9 +77,6 @@ public class EditTextCompose extends FixedEditText { private int quoteGap; private int quoteStripe; - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "paste"); - public EditTextCompose(Context context) { super(context); init(context); @@ -371,7 +367,7 @@ public class EditTextCompose extends FixedEditText { if (snippet.id.equals(id)) { String html = snippet.getHtml(context, to); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { @@ -418,7 +414,7 @@ public class EditTextCompose extends FixedEditText { }); DB db = DB.getInstance(context); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { @@ -527,7 +523,7 @@ public class EditTextCompose extends FixedEditText { } else html = h; - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/EditTextMultiAutoComplete.java b/app/src/main/java/eu/faircode/email/EditTextMultiAutoComplete.java index cbe49d18a9..cd0b320687 100644 --- a/app/src/main/java/eu/faircode/email/EditTextMultiAutoComplete.java +++ b/app/src/main/java/eu/faircode/email/EditTextMultiAutoComplete.java @@ -59,7 +59,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; import javax.mail.Address; import javax.mail.internet.AddressException; @@ -73,8 +72,6 @@ public class EditTextMultiAutoComplete extends AppCompatMultiAutoCompleteTextVie private Tokenizer tokenizer; private Map encryption = new ConcurrentHashMap<>(); - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "chips"); - private static int[] icons = new int[]{ R.drawable.twotone_vpn_key_24_p, R.drawable.twotone_vpn_key_24_s, @@ -339,7 +336,7 @@ public class EditTextMultiAutoComplete extends AppCompatMultiAutoCompleteTextVie Integer has = encryption.get(email); if (has == null) { final List
recipient = Arrays.asList(new Address[]{parsed[0]}); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/EmailProvider.java b/app/src/main/java/eu/faircode/email/EmailProvider.java index 3324fa8bda..542d71d6b2 100644 --- a/app/src/main/java/eu/faircode/email/EmailProvider.java +++ b/app/src/main/java/eu/faircode/email/EmailProvider.java @@ -67,7 +67,6 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import javax.net.SocketFactory; @@ -103,8 +102,6 @@ public class EmailProvider implements Parcelable { enum UserType {LOCAL, EMAIL, VALUE} private static List imported; - private static final ExecutorService executor = - Helper.getBackgroundExecutor(0, "provider"); private static final int SCAN_TIMEOUT = 15 * 1000; // milliseconds private static final int ISPDB_TIMEOUT = 15 * 1000; // milliseconds @@ -132,7 +129,7 @@ public class EmailProvider implements Parcelable { } static void init(Context context) { - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { @@ -1102,7 +1099,7 @@ public class EmailProvider implements Parcelable { private Future getReachable(Context context) { Log.i("Scanning " + this); - return executor.submit(new Callable() { + return Helper.getParallelExecutor().submit(new Callable() { // Returns: // false: closed // true: listening diff --git a/app/src/main/java/eu/faircode/email/EmailService.java b/app/src/main/java/eu/faircode/email/EmailService.java index f20a9b0595..6f112ed978 100644 --- a/app/src/main/java/eu/faircode/email/EmailService.java +++ b/app/src/main/java/eu/faircode/email/EmailService.java @@ -73,7 +73,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; import javax.mail.AuthenticationFailedException; @@ -117,8 +116,6 @@ public class EmailService implements AutoCloseable { private ServiceAuthenticator authenticator; private RingBuffer breadcrumbs; - private ExecutorService executor = Helper.getBackgroundExecutor(0, "mail"); - static final int PURPOSE_CHECK = 1; static final int PURPOSE_USE = 2; static final int PURPOSE_SEARCH = 3; @@ -207,7 +204,7 @@ public class EmailService implements AutoCloseable { " use_top=" + use_top); properties.put("mail.event.scope", "folder"); - properties.put("mail.event.executor", executor); + properties.put("mail.event.executor", Helper.getParallelExecutor()); if (!auth_plain) properties.put("mail." + protocol + ".auth.plain.disable", "true"); diff --git a/app/src/main/java/eu/faircode/email/EntityLog.java b/app/src/main/java/eu/faircode/email/EntityLog.java index 983b593a90..42b3ac507f 100644 --- a/app/src/main/java/eu/faircode/email/EntityLog.java +++ b/app/src/main/java/eu/faircode/email/EntityLog.java @@ -32,7 +32,6 @@ import androidx.room.PrimaryKey; import java.util.Date; import java.util.Objects; -import java.util.concurrent.ExecutorService; @Entity( tableName = EntityLog.TABLE_NAME, @@ -67,9 +66,6 @@ public class EntityLog { public enum Type {General, Statistics, Scheduling, Network, Account, Protocol, Classification, Notification, Rules, Debug} - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "log"); - static void log(final Context context, String data) { log(context, Type.General, data); } @@ -139,7 +135,7 @@ public class EntityLog { final DB db = DB.getInstance(context); final Context acontext = context.getApplicationContext(); - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { // Check available storage space @@ -181,7 +177,7 @@ public class EntityLog { static void clear(final Context context) { final Context acontext = context.getApplicationContext(); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { cleanup(acontext, new Date().getTime()); diff --git a/app/src/main/java/eu/faircode/email/EntityRule.java b/app/src/main/java/eu/faircode/email/EntityRule.java index a31f55b3d8..1dc08596aa 100644 --- a/app/src/main/java/eu/faircode/email/EntityRule.java +++ b/app/src/main/java/eu/faircode/email/EntityRule.java @@ -57,7 +57,6 @@ import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.UUID; -import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; import javax.mail.Address; @@ -130,8 +129,6 @@ public class EntityRule { private static final String JSOUP_PREFIX = "jsoup:"; private static final long SEND_DELAY = 5000L; // milliseconds - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "rule"); - static boolean needsHeaders(EntityMessage message, List rules) { return needs(rules, "header"); } @@ -760,7 +757,7 @@ public class EntityRule { return true; } - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { @@ -982,7 +979,7 @@ public class EntityRule { return true; } - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 6d84fe5ef0..0ce7e77017 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -78,14 +78,10 @@ import android.text.TextUtils; import android.text.TextWatcher; import android.text.method.ArrowKeyMovementMethod; import android.text.style.BackgroundColorSpan; -import android.text.style.BulletSpan; -import android.text.style.CharacterStyle; import android.text.style.ImageSpan; -import android.text.style.ParagraphStyle; import android.text.style.QuoteSpan; import android.text.style.RelativeSizeSpan; import android.text.style.URLSpan; -import android.util.LogPrinter; import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; @@ -206,7 +202,6 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.UUID; -import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; import javax.activation.DataHandler; @@ -340,8 +335,6 @@ public class FragmentCompose extends FragmentBase { private static final int REQUEST_SEND = 15; private static final int REQUEST_REMOVE_ATTACHMENTS = 16; - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "compose"); - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -1399,7 +1392,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentCompose.this, args, "compose:identity"); + }.serial().execute(FragmentCompose.this, args, "compose:identity"); } private void onReferenceEdit() { @@ -1490,7 +1483,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentCompose.this, args, "compose:convert"); + }.serial().execute(FragmentCompose.this, args, "compose:convert"); } private void copyRef() { @@ -2007,7 +2000,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:encrypt"); + }.serial().execute(this, args, "compose:encrypt"); } private void onMenuZoom() { @@ -2262,7 +2255,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentCompose.this, args, "compose:answer"); + }.serial().execute(FragmentCompose.this, args, "compose:answer"); return true; } @@ -2275,7 +2268,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(getContext(), getViewLifecycleOwner(), new Bundle(), "compose:answer"); + }.serial().execute(getContext(), getViewLifecycleOwner(), new Bundle(), "compose:answer"); } private void onMenuAnswerCreate() { @@ -2473,7 +2466,7 @@ public class FragmentCompose extends FragmentBase { etBody.setSelection(paragraph.second); Log.unexpectedError(getParentFragmentManager(), ex, false); } - }.setExecutor(executor).execute(FragmentCompose.this, args, "compose:translate"); + }.serial().execute(FragmentCompose.this, args, "compose:translate"); } }); @@ -2713,7 +2706,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:alias"); + }.serial().execute(this, args, "compose:alias"); } else { try { List
recipients = new ArrayList<>(); @@ -2989,7 +2982,7 @@ public class FragmentCompose extends FragmentBase { else Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:picked"); + }.serial().execute(this, args, "compose:picked"); } @Override @@ -3190,7 +3183,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { handleException(ex); } - }.setExecutor(executor).execute(this, args, "compose:attachment:add"); + }.serial().execute(this, args, "compose:attachment:add"); } void onSharedAttachments(ArrayList uris) { @@ -3639,7 +3632,7 @@ public class FragmentCompose extends FragmentBase { } else Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:pgp"); + }.serial().execute(this, args, "compose:pgp"); } private void onSmime(Bundle args, final int action, final Bundle extras) { @@ -4029,7 +4022,7 @@ public class FragmentCompose extends FragmentBase { Log.unexpectedError(getParentFragmentManager(), ex, !expected); } } - }.setExecutor(executor).execute(this, args, "compose:s/mime"); + }.serial().execute(this, args, "compose:s/mime"); } private void onContactGroupSelected(Bundle args) { @@ -4173,7 +4166,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:picked"); + }.serial().execute(this, args, "compose:picked"); } private void onSelectIdentity(Bundle args) { @@ -5773,7 +5766,7 @@ public class FragmentCompose extends FragmentBase { } else handleException(ex); } - }.setExecutor(executor); + }.serial(); private void handleException(Throwable ex) { // External app sending absolute file @@ -6684,7 +6677,7 @@ public class FragmentCompose extends FragmentBase { if (ani != null && ani.isConnected()) DnsHelper.checkMx(context, addresses); } - }.setExecutor(executor); + }.serial(); private String getActionName(int id) { if (id == R.id.action_delete) { @@ -6934,7 +6927,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:show"); + }.serial().execute(this, args, "compose:show"); } private void setFocus(Integer v, int start, int end, boolean restore) { @@ -7616,7 +7609,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:plain_only"); + }.serial().execute(FragmentDialogSend.this, args, "compose:plain_only"); } }); @@ -7645,7 +7638,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:receipt"); + }.serial().execute(FragmentDialogSend.this, args, "compose:receipt"); } }); @@ -7724,7 +7717,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:encrypt"); + }.serial().execute(FragmentDialogSend.this, args, "compose:encrypt"); } }); @@ -7772,7 +7765,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:priority"); + }.serial().execute(FragmentDialogSend.this, args, "compose:priority"); } }); @@ -7813,7 +7806,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:sensitivity"); + }.serial().execute(FragmentDialogSend.this, args, "compose:sensitivity"); } }); @@ -7985,7 +7978,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { // Ignored } - }.setExecutor(executor).execute(FragmentDialogSend.this, aargs, "send:archive"); + }.serial().execute(FragmentDialogSend.this, aargs, "send:archive"); AlertDialog.Builder builder = new AlertDialog.Builder(context) .setView(dview) @@ -8042,7 +8035,7 @@ public class FragmentCompose extends FragmentBase { protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "compose:snooze"); + }.serial().execute(this, args, "compose:snooze"); } } } diff --git a/app/src/main/java/eu/faircode/email/FragmentDialogFolder.java b/app/src/main/java/eu/faircode/email/FragmentDialogFolder.java index 52dcbb3ee9..017d95b057 100644 --- a/app/src/main/java/eu/faircode/email/FragmentDialogFolder.java +++ b/app/src/main/java/eu/faircode/email/FragmentDialogFolder.java @@ -65,7 +65,6 @@ import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Locale; -import java.util.concurrent.ExecutorService; public class FragmentDialogFolder extends FragmentDialogBase { private int result = 0; @@ -75,9 +74,6 @@ public class FragmentDialogFolder extends FragmentDialogBase { private static final int MAX_SELECTED_FOLDERS = 5; private static final int REQUEST_FOLDER_NAME = 1; - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "folder"); - @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { @@ -219,7 +215,7 @@ public class FragmentDialogFolder extends FragmentDialogBase { final DB db = DB.getInstance(context); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { @@ -387,7 +383,7 @@ public class FragmentDialogFolder extends FragmentDialogBase { private static void increaseSelectedCount(Long id, Context context) { final DB db = DB.getInstance(context); - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index d3bf4775fe..3179a36895 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -243,7 +243,6 @@ import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -449,8 +448,6 @@ public class FragmentMessages extends FragmentBase "time", "unread", "starred", "priority" )); - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "messages"); - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -691,9 +688,7 @@ public class FragmentMessages extends FragmentBase rvMessage.setHasFixedSize(false); - int threads = prefs.getInt("query_threads", DB.DEFAULT_QUERY_THREADS); - if (threads >= 4) - rvMessage.setItemViewCacheSize(ITEM_CACHE_SIZE); + rvMessage.setItemViewCacheSize(ITEM_CACHE_SIZE); //rvMessage.getRecycledViewPool().setMaxRecycledViews(0, 10); // Default 5 final LinearLayoutManager llm = new LinearLayoutManager(getContext()) { @@ -6351,7 +6346,7 @@ public class FragmentMessages extends FragmentBase protected void onException(Bundle args, Throwable ex) { Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).setId("messages:" + FragmentMessages.this.hashCode()).execute(this, args, "quickactions"); + }.serial().setId("messages:" + FragmentMessages.this.hashCode()).execute(this, args, "quickactions"); } else { fabMore.hide(); tvSelectedCount.setVisibility(View.GONE); @@ -8519,7 +8514,7 @@ public class FragmentMessages extends FragmentBase } else Log.unexpectedError(getParentFragmentManager(), ex); } - }.setExecutor(executor).execute(this, args, "decrypt:pgp"); + }.serial().execute(this, args, "decrypt:pgp"); } private void onSmime(Bundle args) { @@ -9176,7 +9171,7 @@ public class FragmentMessages extends FragmentBase } return trace; } - }.setExecutor(executor).execute(this, args, "decrypt:s/mime"); + }.serial().execute(this, args, "decrypt:s/mime"); } private static void checkPep(EntityMessage message, List remotes, Context context) { @@ -9759,8 +9754,6 @@ public class FragmentMessages extends FragmentBase args.putBoolean("print_html_images", print_html_images); new SimpleTask() { - private final ExecutorService executor = Helper.getBackgroundExecutor(0, "print"); - @Override protected String[] onExecute(Context context, Bundle args) throws IOException { long id = args.getLong("id"); @@ -9818,7 +9811,7 @@ public class FragmentMessages extends FragmentBase continue; } - futures.add(executor.submit(new Callable() { + futures.add(Helper.getParallelExecutor().submit(new Callable() { @Override public Void call() throws Exception { try (OutputStream os = new FileOutputStream(out)) { @@ -10111,7 +10104,7 @@ public class FragmentMessages extends FragmentBase return; DB db = DB.getInstance(context); - db.getQueryExecutor().execute(new Runnable() { + Helper.getParallelExecutor().execute(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index 09534047b5..b285e34bd2 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -61,7 +61,6 @@ import com.google.android.material.tabs.TabLayout; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.ExecutorService; public class FragmentOptions extends FragmentBase { private ViewPager pager; @@ -69,9 +68,6 @@ public class FragmentOptions extends FragmentBase { private String searching = null; private SuggestData data = null; - private final ExecutorService executor = - Helper.getBackgroundExecutor(1, "suggest"); - private static final int[] TAB_PAGES = { R.layout.fragment_setup, R.layout.fragment_options_synchronize, @@ -386,8 +382,7 @@ public class FragmentOptions extends FragmentBase { return data; } - }.setExecutor(executor) - .execute(FragmentOptions.this, args, "option:suggest"); + }.serial().execute(FragmentOptions.this, args, "option:suggest"); } private void _suggest(String query) { diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java index 440ff03e86..97cf68978f 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java @@ -176,9 +176,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private SwitchCompat swWorkManager; private SwitchCompat swExternalStorage; private TextView tvExternalStorageFolder; - private TextView tvRoomQueryThreads; - private SeekBar sbRoomQueryThreads; - private ImageButton ibRoom; private SwitchCompat swIntegrity; private SwitchCompat swWal; private SwitchCompat swCheckpoints; @@ -261,7 +258,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc "watchdog", "experiments", "main_log", "main_log_memory", "protocol", "log_level", "debug", "leak_canary", "test1", "test2", "test3", "test4", "test5", "work_manager", // "external_storage", - "query_threads", "sqlite_integrity_check", "wal", "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache", "chunk_size", "thread_range", "undo_manager", "browser_zoom", "fake_dark", @@ -393,9 +389,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc swWorkManager = view.findViewById(R.id.swWorkManager); swExternalStorage = view.findViewById(R.id.swExternalStorage); tvExternalStorageFolder = view.findViewById(R.id.tvExternalStorageFolder); - tvRoomQueryThreads = view.findViewById(R.id.tvRoomQueryThreads); - sbRoomQueryThreads = view.findViewById(R.id.sbRoomQueryThreads); - ibRoom = view.findViewById(R.id.ibRoom); swIntegrity = view.findViewById(R.id.swIntegrity); swWal = view.findViewById(R.id.swWal); swCheckpoints = view.findViewById(R.id.swCheckpoints); @@ -1245,31 +1238,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc } }); - sbRoomQueryThreads.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - prefs.edit().putInt("query_threads", progress).apply(); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - }); - - ibRoom.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - prefs.edit().remove("debug").commit(); - ApplicationEx.restart(v.getContext(), "query_threads"); - } - }); - swIntegrity.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton v, boolean checked) { @@ -2193,10 +2161,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc swWorkManager.setChecked(prefs.getBoolean("work_manager", true)); swExternalStorage.setChecked(prefs.getBoolean("external_storage", false)); - int query_threads = prefs.getInt("query_threads", DB.DEFAULT_QUERY_THREADS); - tvRoomQueryThreads.setText(getString(R.string.title_advanced_room_query_threads, NF.format(query_threads))); - sbRoomQueryThreads.setProgress(query_threads); - swIntegrity.setChecked(prefs.getBoolean("sqlite_integrity_check", true)); swWal.setChecked(prefs.getBoolean("wal", true)); swCheckpoints.setChecked(prefs.getBoolean("sqlite_checkpoints", true)); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java index 1fb1c9e236..112da8969f 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsNotifications.java @@ -59,7 +59,6 @@ import androidx.constraintlayout.widget.Group; import androidx.preference.PreferenceManager; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.function.Consumer; public class FragmentOptionsNotifications extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -125,9 +124,6 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared private Group grpBackground; private Group grpTiles; - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "notifications"); - private final static String[] RESET_OPTIONS = new String[]{ "notify_newest_first", "notify_summary", "notify_trash", "notify_junk", "notify_block_sender", "notify_archive", "notify_move", @@ -817,7 +813,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared ComponentName.createRelative(context, cls.getName()), context.getString(title), Icon.createWithResource(context, icon), - executor, + Helper.getParallelExecutor(), new Consumer() { @Override public void accept(Integer result) { diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index c89454997d..568f389e4f 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -178,6 +178,7 @@ public class Helper { static final float LOW_LIGHT = 0.6f; + static final int OPERATION_WORKERS = 3; static final int WAKELOCK_MAX = 30 * 60 * 1000; // milliseconds static final int BUFFER_SIZE = 8192; // Same as in Files class static final long MIN_REQUIRED_SPACE = 100 * 1000L * 1000L; @@ -245,9 +246,40 @@ public class Helper { "wsc", "wsf", "wsh" )); - private static final ExecutorService executor = getBackgroundExecutor(1, "helper"); + static ExecutorService sSerialExecutor = null; + static ExecutorService sParallelExecutor = null; + static ExecutorService sSerialTaskExecutor = null; - static ExecutorService getBackgroundExecutor(int threads, final String name) { + static int sOperationIndex = 0; + static ExecutorService[] sOperationExecutor = new ExecutorService[OPERATION_WORKERS]; + + static ExecutorService getSerialExecutor() { + if (sSerialExecutor == null) + sSerialExecutor = getBackgroundExecutor(1, "serial"); + return sSerialExecutor; + } + + static ExecutorService getParallelExecutor() { + if (sParallelExecutor == null) + sParallelExecutor = getBackgroundExecutor(0, "parallel"); + return sParallelExecutor; + } + + static ExecutorService getSerialTaskExecutor() { + if (sSerialTaskExecutor == null) + sSerialTaskExecutor = getBackgroundExecutor(1, "task"); + return sSerialTaskExecutor; + } + + static ExecutorService getOperationExecutor() { + if (sOperationExecutor[sOperationIndex] == null) + sOperationExecutor[sOperationIndex] = getBackgroundExecutor(1, "operation"); + ExecutorService result = sOperationExecutor[sOperationIndex]; + sOperationIndex = (sOperationIndex + 1) % sOperationExecutor.length; + return result; + } + + private static ExecutorService getBackgroundExecutor(int threads, final String name) { ThreadFactory factory = new ThreadFactory() { private final AtomicInteger threadId = new AtomicInteger(); @@ -264,7 +296,7 @@ public class Helper { // java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again // 1040 KB native stack size / 32 KB thread stack size ~ 32 threads int processors = Runtime.getRuntime().availableProcessors(); // Modern devices: 8 - threads = processors * (BuildConfig.DEBUG ? 8 : 4); + threads = processors * 2; } if (threads == 0) @@ -396,9 +428,14 @@ public class Helper { } static class PriorityRunnable implements Runnable { + private long group; private int priority; private long order; + long getGroup() { + return this.group; + } + int getPriority() { return this.priority; } @@ -407,7 +444,8 @@ public class Helper { return this.order; } - PriorityRunnable(int priority, long order) { + PriorityRunnable(long group, int priority, long order) { + this.group = group; this.priority = priority; this.order = order; } @@ -2696,7 +2734,7 @@ public class Helper { ? R.string.title_setup_biometrics_disable : R.string.title_setup_biometrics_enable)); - final BiometricPrompt prompt = new BiometricPrompt(activity, executor, + final BiometricPrompt prompt = new BiometricPrompt(activity, Helper.getParallelExecutor(), new BiometricPrompt.AuthenticationCallback() { private int fails = 0; diff --git a/app/src/main/java/eu/faircode/email/ImageHelper.java b/app/src/main/java/eu/faircode/email/ImageHelper.java index 8593f95810..94577d4ec2 100644 --- a/app/src/main/java/eu/faircode/email/ImageHelper.java +++ b/app/src/main/java/eu/faircode/email/ImageHelper.java @@ -81,11 +81,6 @@ import java.util.WeakHashMap; import java.util.concurrent.ExecutorService; class ImageHelper { - private static final ExecutorService executor_1 = - Helper.getBackgroundExecutor(1, "image_1"); - private static final ExecutorService executor_n = - Helper.getBackgroundExecutor(0, "image_n"); - static final int DOWNLOAD_TIMEOUT = 15; // seconds private static final int MAX_PROBE = 128 * 1024; // bytes private static final int SLOW_CONNECTION = 2 * 1024; // Kbps @@ -475,7 +470,9 @@ class ImageHelper { lld.setLevel(1); Integer kbps = ConnectionHelper.getLinkDownstreamBandwidthKbps(context); - ExecutorService executor = (kbps != null && kbps < SLOW_CONNECTION ? executor_1 : executor_n); + ExecutorService executor = (kbps != null && kbps < SLOW_CONNECTION + ? Helper.getSerialExecutor() + : Helper.getParallelExecutor()); executor.submit(new Runnable() { @Override diff --git a/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java b/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java index 3847e962b8..7068096613 100644 --- a/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java +++ b/app/src/main/java/eu/faircode/email/MediaPlayerHelper.java @@ -14,7 +14,6 @@ import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.OnLifecycleEvent; import java.io.IOException; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -22,8 +21,6 @@ public class MediaPlayerHelper { static final int DEFAULT_SOUND_DURATION = 30; // seconds static final int DEFAULT_ALARM_DURATION = 30; // seconds - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "media"); - static void queue(Context context, String uri) { try { queue(context, Uri.parse(uri), false, DEFAULT_SOUND_DURATION); @@ -35,7 +32,7 @@ public class MediaPlayerHelper { static void queue(Context context, Uri uri, boolean alarm, int duration) { Log.i("Queuing sound=" + uri); - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { @@ -114,7 +111,7 @@ public class MediaPlayerHelper { try { if (owner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { if (!registered) { - am.addOnModeChangedListener(executor, listener); + am.addOnModeChangedListener(Helper.getParallelExecutor(), listener); registered = true; } } else { diff --git a/app/src/main/java/eu/faircode/email/ServiceExternal.java b/app/src/main/java/eu/faircode/email/ServiceExternal.java index a9ad3d844e..e4fdd57efe 100644 --- a/app/src/main/java/eu/faircode/email/ServiceExternal.java +++ b/app/src/main/java/eu/faircode/email/ServiceExternal.java @@ -36,7 +36,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.concurrent.ExecutorService; public class ServiceExternal extends Service { private static final String ACTION_POLL = BuildConfig.APPLICATION_ID + ".POLL"; @@ -51,10 +50,6 @@ public class ServiceExternal extends Service { // adb shell am start-foreground-service -a eu.faircode.email.INTERVAL --ei minutes {0, 15, 30, 60, 120, 240, 480, 1440} // adb shell am start-foreground-service -a eu.faircode.email.DISCONNECT - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "external"); - - @Override public void onCreate() { Log.i("Service external create"); @@ -86,7 +81,7 @@ public class ServiceExternal extends Service { EntityLog.log(this, action); final Context context = getApplicationContext(); - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index a2049cc19d..a4d1087d91 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -58,7 +58,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; -import java.util.concurrent.ExecutorService; import javax.mail.Address; import javax.mail.AuthenticationFailedException; @@ -84,8 +83,6 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar private PowerManager.WakeLock wlOutbox; private List handling = new ArrayList<>(); - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "send"); - private static final int RETRY_MAX = 3; private static final int CONNECTIVITY_DELAY = 5000; // milliseconds private static final int PROGRESS_UPDATE_INTERVAL = 1000; // milliseconds @@ -149,7 +146,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar "Send process=" + TextUtils.join(",", process) + " handling=" + TextUtils.join(",", handling)); - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { processOperations(process); @@ -900,7 +897,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar } static void boot(final Context context) { - executor.submit(new Runnable() { + Helper.getSerialExecutor().submit(new Runnable() { @Override public void run() { try { diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 8233aef48b..cc2f088459 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -128,8 +128,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences private final MutableLiveData> liveAccountState = new MutableLiveData<>(); private final MediatorState liveAccountNetworkState = new MediatorState(); - private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "sync"); - private static final long BACKUP_DELAY = 30 * 1000L; // milliseconds private static final long PURGE_DELAY = 30 * 1000L; // milliseconds private static final int QUIT_DELAY = 10; // seconds @@ -260,7 +258,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences private PowerManager pm = Helper.getSystemService(ServiceSynchronize.this, PowerManager.class); private PowerManager.WakeLock wl = pm.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID + ":service"); - private ExecutorService queue = Helper.getBackgroundExecutor(1, "service"); @Override public void onChanged(List accountNetworkStates) { @@ -467,7 +464,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void init(final TupleAccountNetworkState accountNetworkState) { - queue.submit(new RunnableEx("state#init") { + Helper.getSerialExecutor().submit(new RunnableEx("state#init") { @Override public void delegate() { long start = new Date().getTime(); @@ -526,7 +523,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }, "sync.account." + accountNetworkState.accountState.id); coreStates.put(accountNetworkState.accountState.id, astate); - queue.submit(new RunnableEx("state#start") { + Helper.getSerialExecutor().submit(new RunnableEx("state#start") { @Override public void delegate() { long start = new Date().getTime(); @@ -567,7 +564,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling, "Service stop=" + accountNetworkState); - queue.submit(new RunnableEx("state#stop") { + Helper.getSerialExecutor().submit(new RunnableEx("state#stop") { @Override public void delegate() { long start = new Date().getTime(); @@ -605,7 +602,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling, "Service delete=" + accountNetworkState); - queue.submit(new RunnableEx("state#delete") { + Helper.getSerialExecutor().submit(new RunnableEx("state#delete") { @Override public void delegate() { long start = new Date().getTime(); @@ -632,7 +629,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void quit(final Integer eventId) { - queue.submit(new RunnableEx("state#quit") { + Helper.getSerialExecutor().submit(new RunnableEx("state#quit") { @Override public void delegate() { long start = new Date().getTime(); @@ -691,7 +688,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences private final Runnable backup = new RunnableEx("state#backup") { @Override public void delegate() { - queue.submit(new RunnableEx("state#backup#exec") { + Helper.getSerialExecutor().submit(new RunnableEx("state#backup#exec") { @Override public void delegate() { long start = new Date().getTime(); @@ -841,12 +838,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }); mutableUnseenNotify.observe(mowner, new Observer>() { - private final ExecutorService executor = - Helper.getBackgroundExecutor(1, "notify"); - @Override public void onChanged(final List messages) { - executor.submit(new RunnableEx("mutableUnseenNotify") { + Helper.getSerialExecutor().submit(new RunnableEx("mutableUnseenNotify") { @Override public void delegate() { try { @@ -1176,7 +1170,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences String action = intent.getAction(); long id = Long.parseLong(action.split(":")[1]); - executor.submit(new RunnableEx("unsnooze") { + Helper.getSerialExecutor().submit(new RunnableEx("unsnooze") { @Override public void delegate() { try { @@ -1297,7 +1291,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences String action = intent.getAction(); long id = Long.parseLong(action.split(":")[1]); - executor.submit(new RunnableEx("exists") { + Helper.getSerialExecutor().submit(new RunnableEx("exists") { @Override public void delegate() { try { @@ -1333,7 +1327,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void onPoll(Intent intent) { - executor.submit(new RunnableEx("poll") { + Helper.getSerialExecutor().submit(new RunnableEx("poll") { @Override public void delegate() { try { @@ -1532,8 +1526,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences Log.i(account.name + " run thread=" + currentThread); final ObjectHolder cowner = new ObjectHolder<>(); - final ExecutorService executor = - Helper.getBackgroundExecutor(1, "account_" + account.id); + final ExecutorService executor = Helper.getOperationExecutor(); // Debug SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -1633,6 +1626,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } }; + final long group = Thread.currentThread().getId(); final Map mapFolders = new LinkedHashMap<>(); List idlers = new ArrayList<>(); try { @@ -2143,7 +2137,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences crumb.put("serial", Long.toString(serial)); Log.breadcrumb("Queuing", crumb); - executor.submit(new Helper.PriorityRunnable(key.getPriority(), key.getOrder()) { + executor.submit(new Helper.PriorityRunnable(group, key.getPriority(), key.getOrder()) { @Override public void run() { super.run(); @@ -2578,6 +2572,11 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences // Stop executing operations Log.i(account.name + " stop executing operations"); state.nextSerial(); + for (Runnable task : ((ThreadPoolExecutor) executor).getQueue().toArray(new Runnable[0])) + if (task instanceof Helper.PriorityRunnable && + ((Helper.PriorityRunnable) task).getGroup() == group) + ((ThreadPoolExecutor) executor).remove(task); + ((ThreadPoolExecutor) executor).getQueue().clear(); // Close store @@ -3109,7 +3108,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } static void boot(final Context context) { - executor.submit(new RunnableEx("boot") { + Helper.getSerialExecutor().submit(new RunnableEx("boot") { @Override public void delegate() { try { @@ -3170,7 +3169,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences AlarmManagerCompatEx.setAndAllowWhileIdle(context, am, AlarmManager.RTC_WAKEUP, next, pi); } - executor.submit(new RunnableEx("schedule") { + Helper.getSerialExecutor().submit(new RunnableEx("schedule") { @Override protected void delegate() { boolean work = false; diff --git a/app/src/main/java/eu/faircode/email/SimpleTask.java b/app/src/main/java/eu/faircode/email/SimpleTask.java index 5ec0210c38..3fce3275a7 100644 --- a/app/src/main/java/eu/faircode/email/SimpleTask.java +++ b/app/src/main/java/eu/faircode/email/SimpleTask.java @@ -66,7 +66,6 @@ public abstract class SimpleTask implements LifecycleObserver { private Handler handler = null; private static PowerManager.WakeLock wl = null; - private static ExecutorService globalExecutor = null; private static int themeId = -1; @SuppressLint("StaticFieldLeak") private static Context themedContext = null; @@ -108,6 +107,10 @@ public abstract class SimpleTask implements LifecycleObserver { return this; } + public SimpleTask serial() { + return setExecutor(Helper.getSerialTaskExecutor()); + } + @NonNull public SimpleTask setHandler(Handler handler) { this.handler = handler; @@ -124,12 +127,7 @@ public abstract class SimpleTask implements LifecycleObserver { if (localExecutor != null) return localExecutor; - if (globalExecutor == null) { - int processors = Runtime.getRuntime().availableProcessors(); - globalExecutor = Helper.getBackgroundExecutor(processors, "task"); - } - - return globalExecutor; + return Helper.getParallelExecutor(); } @NonNull diff --git a/app/src/main/java/eu/faircode/email/TextHelper.java b/app/src/main/java/eu/faircode/email/TextHelper.java index a7cd37c605..cc0f97b637 100644 --- a/app/src/main/java/eu/faircode/email/TextHelper.java +++ b/app/src/main/java/eu/faircode/email/TextHelper.java @@ -47,7 +47,6 @@ import java.util.List; import java.util.Locale; import java.util.Set; import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -67,9 +66,6 @@ public class TextHelper { private static final int MAX_CONVERSATION_SAMPLE_SIZE = 8192; private static final long MAX_CONVERSATION_DURATION = 3000; // milliseconds - private static final ExecutorService executor = - Helper.getBackgroundExecutor(0, "text"); - static { System.loadLibrary("fairemail"); } @@ -192,7 +188,7 @@ public class TextHelper { .setHints(hints) .build(); - Future future = executor.submit(new Callable() { + Future future = Helper.getParallelExecutor().submit(new Callable() { @Override @RequiresApi(api = Build.VERSION_CODES.Q) public ConversationActions call() throws Exception { diff --git a/app/src/main/java/eu/faircode/email/ViewModelMessages.java b/app/src/main/java/eu/faircode/email/ViewModelMessages.java index 7ccc8ec8c7..4b11d6bfd8 100644 --- a/app/src/main/java/eu/faircode/email/ViewModelMessages.java +++ b/app/src/main/java/eu/faircode/email/ViewModelMessages.java @@ -44,7 +44,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.ExecutorService; public class ViewModelMessages extends ViewModel { private AdapterMessage.ViewType last = AdapterMessage.ViewType.UNIFIED; @@ -68,9 +67,6 @@ public class ViewModelMessages extends ViewModel { } }; - // AndroidX IO = 4 threads - private ExecutorService executor = Helper.getBackgroundExecutor(4, "model"); - private static final int LOCAL_PAGE_SIZE = 50; private static final int THREAD_PAGE_SIZE = 100; private static final int REMOTE_PAGE_SIZE = 10; @@ -204,7 +200,7 @@ public class ViewModelMessages extends ViewModel { break; } - builder.setFetchExecutor(executor); + builder.setFetchExecutor(Helper.getParallelExecutor()); model = new Model(args, builder.build(), boundary); models.put(viewType, model); diff --git a/app/src/main/java/eu/faircode/email/Widget.java b/app/src/main/java/eu/faircode/email/Widget.java index f51b4ac4fe..9b4feae3c5 100644 --- a/app/src/main/java/eu/faircode/email/Widget.java +++ b/app/src/main/java/eu/faircode/email/Widget.java @@ -38,15 +38,11 @@ import androidx.preference.PreferenceManager; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutorService; public class Widget extends AppWidgetProvider { - private static final ExecutorService executor = - Helper.getBackgroundExecutor(1, "widget"); - @Override public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) { - executor.submit(new Runnable() { + Helper.getParallelExecutor().submit(new Runnable() { @Override public void run() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); diff --git a/app/src/main/res/layout/fragment_options_misc.xml b/app/src/main/res/layout/fragment_options_misc.xml index 5cdbb14908..459b495480 100644 --- a/app/src/main/res/layout/fragment_options_misc.xml +++ b/app/src/main/res/layout/fragment_options_misc.xml @@ -1134,50 +1134,6 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/swExternalStorage" /> - - - - - - - - Autostart app Initialize work manager Use external storage - ROOM query threads: %1$s sqlite integrity check sqlite WAL sqlite checkpoints