From d32b55d2c5b5e40ef2e310dc09c571a71d583e46 Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 28 Feb 2019 07:55:08 +0000 Subject: [PATCH] Improved boot --- .../java/eu/faircode/email/ActivityMain.java | 3 +- .../eu/faircode/email/FragmentOptions.java | 4 +- .../eu/faircode/email/ReceiverAutostart.java | 35 +--- .../java/eu/faircode/email/ServiceSend.java | 23 +++ .../eu/faircode/email/ServiceSynchronize.java | 185 ++++++++++-------- 5 files changed, 134 insertions(+), 116 deletions(-) diff --git a/app/src/main/java/eu/faircode/email/ActivityMain.java b/app/src/main/java/eu/faircode/email/ActivityMain.java index a6e5df251f..0e5ddaa0cf 100644 --- a/app/src/main/java/eu/faircode/email/ActivityMain.java +++ b/app/src/main/java/eu/faircode/email/ActivityMain.java @@ -58,7 +58,8 @@ public class ActivityMain extends AppCompatActivity implements FragmentManager.O startActivity(new Intent(ActivityMain.this, ActivitySetup.class)); else { startActivity(new Intent(ActivityMain.this, ActivityView.class)); - ServiceSynchronize.init(ActivityMain.this, false); + ServiceSynchronize.boot(ActivityMain.this); + ServiceSend.boot(ActivityMain.this); } finish(); } diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index 2e61953fad..73ca19a7ec 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -197,7 +197,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O if (checked) { if (Helper.isPro(getContext())) { prefs.edit().putBoolean("schedule", true).apply(); - ServiceSynchronize.schedule(getContext()); + ServiceSynchronize.reschedule(getContext()); } else { swSchedule.setChecked(false); FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); @@ -645,7 +645,7 @@ public class FragmentOptions extends FragmentBase implements SharedPreferences.O editor.putBoolean("schedule", true); editor.apply(); - ServiceSynchronize.schedule(getContext()); + ServiceSynchronize.reschedule(getContext()); } } diff --git a/app/src/main/java/eu/faircode/email/ReceiverAutostart.java b/app/src/main/java/eu/faircode/email/ReceiverAutostart.java index 0687f42fed..32d229fb95 100644 --- a/app/src/main/java/eu/faircode/email/ReceiverAutostart.java +++ b/app/src/main/java/eu/faircode/email/ReceiverAutostart.java @@ -23,43 +23,14 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import java.util.List; - -import static android.os.Process.THREAD_PRIORITY_BACKGROUND; - public class ReceiverAutostart extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || Intent.ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) { - EntityLog.log(context, intent.getAction()); - - ServiceSynchronize.init(context, true); - - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - try { - DB db = DB.getInstance(context); - - List messages = db.message().getSnoozed(); - for (EntityMessage message : messages) - EntityMessage.snooze(context, message.id, message.ui_snoozed); - - EntityFolder outbox = db.folder().getOutbox(); - if (outbox == null) - return; - - if (db.operation().getOperations(outbox.id).size() > 0) - ServiceSend.start(context); - - } catch (Throwable ex) { - Log.e(ex); - } - } - }); - thread.setPriority(THREAD_PRIORITY_BACKGROUND); - thread.start(); + Log.i("Received " + intent); + ServiceSynchronize.boot(context); + ServiceSend.boot(context); } } } diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index d6a8caaa20..133c8f85c6 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -60,6 +60,8 @@ import androidx.lifecycle.Observer; public class ServiceSend extends LifecycleService { private int lastUnsent = 0; + private static boolean booted = false; + private static final int IDENTITY_ERROR_AFTER = 30; // minutes @Override @@ -413,6 +415,27 @@ public class ServiceSend extends LifecycleService { } } + static void boot(final Context context) { + if (!booted) { + booted = true; + + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { + DB db = DB.getInstance(context); + EntityFolder outbox = db.folder().getOutbox(); + if (outbox != null && db.operation().getOperations(outbox.id).size() > 0) + start(context); + } catch (Throwable ex) { + Log.e(ex); + } + } + }); + thread.start(); + } + } + static void start(Context context) { context.startService(new Intent(context, ServiceSend.class)); } diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 5644bac08f..0f935353d2 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -89,6 +89,8 @@ public class ServiceSynchronize extends LifecycleService { private TupleAccountStats lastStats = new TupleAccountStats(); private ServiceManager serviceManager = new ServiceManager(); + private static boolean booted = false; + private static final int CONNECT_BACKOFF_START = 8; // seconds private static final int CONNECT_BACKOFF_MAX = 64; // seconds (totally 2 minutes) private static final int CONNECT_BACKOFF_AlARM = 15; // minutes @@ -97,7 +99,7 @@ public class ServiceSynchronize extends LifecycleService { private static final int BACKOFF_ERROR_AFTER = 16; // seconds private static final long STOP_DELAY = 5000L; // milliseconds - static final int PI_SCHEDULE = 1; + static final int PI_ALARM = 1; @Override public void onCreate() { @@ -165,15 +167,13 @@ public class ServiceSynchronize extends LifecycleService { if (action != null) try { - final String[] parts = action.split(":"); - switch (parts[0]) { + switch (action) { case "init": - // Network events will manage the service - serviceManager.service_init(intent.getBooleanExtra("boot", false)); + serviceManager.service_init(); break; - case "schedule": - serviceManager.service_schedule(); + case "alarm": + serviceManager.service_alarm(); break; case "reload": @@ -941,19 +941,14 @@ public class ServiceSynchronize extends LifecycleService { return (db.account().getSynchronizingAccounts(false).size() > 0); } - private void service_init(boolean boot) { - EntityLog.log(ServiceSynchronize.this, "Service init boot=" + boot); - - if (boot) - next_schedule(); - - if (!isEnabled()) - stopSelf(); + private void service_init() { + EntityLog.log(ServiceSynchronize.this, "Service init"); + // Network events will manage the service } - private void service_schedule() { - next_schedule(); - service_reload("schedule"); + private void service_alarm() { + schedule(ServiceSynchronize.this); + service_reload("alarm"); } private void service_reload(String reason) { @@ -1071,61 +1066,6 @@ public class ServiceSynchronize extends LifecycleService { state = null; } - private void next_schedule() { - Intent schedule = new Intent(ServiceSynchronize.this, ServiceSynchronize.class); - schedule.setAction("schedule"); - PendingIntent piSchedule = PendingIntent.getService( - ServiceSynchronize.this, PI_SCHEDULE, schedule, PendingIntent.FLAG_UPDATE_CURRENT); - - AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE); - am.cancel(piSchedule); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSynchronize.this); - if (!prefs.getBoolean("schedule", false)) - return; - - int minuteStart = prefs.getInt("schedule_start", 0); - int minuteEnd = prefs.getInt("schedule_end", 0); - - if (minuteEnd <= minuteStart) - minuteEnd += 24 * 60; - - Calendar calStart = Calendar.getInstance(); - calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60); - calStart.set(Calendar.MINUTE, minuteStart % 60); - calStart.set(Calendar.SECOND, 0); - calStart.set(Calendar.MILLISECOND, 0); - - Calendar calEnd = Calendar.getInstance(); - calEnd.set(Calendar.HOUR_OF_DAY, minuteEnd / 60); - calEnd.set(Calendar.MINUTE, minuteEnd % 60); - calEnd.set(Calendar.SECOND, 0); - calEnd.set(Calendar.MILLISECOND, 0); - - long now = new Date().getTime(); - if (now > calEnd.getTimeInMillis()) { - calStart.set(Calendar.DAY_OF_MONTH, calStart.get(Calendar.DAY_OF_MONTH) + 1); - calEnd.set(Calendar.DAY_OF_MONTH, calEnd.get(Calendar.DAY_OF_MONTH) + 1); - } - - long start = calStart.getTimeInMillis(); - long end = calEnd.getTimeInMillis(); - long next = (now < start ? start : end); - - EntityLog.log(ServiceSynchronize.this, "Schedule now=" + new Date(now)); - EntityLog.log(ServiceSynchronize.this, "Schedule start=" + new Date(start)); - EntityLog.log(ServiceSynchronize.this, "Schedule end=" + new Date(end)); - EntityLog.log(ServiceSynchronize.this, "Schedule next=" + new Date(next)); - - boolean enabled = (now >= start && now < end); - prefs.edit().putBoolean("enabled", enabled).apply(); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) - am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, next, piSchedule); - else - am.set(AlarmManager.RTC_WAKEUP, next, piSchedule); - } - private void queue_reload(final boolean start, final String reason) { final boolean doStop = started; final boolean doStart = (start && isEnabled() && suitableNetwork()); @@ -1192,20 +1132,103 @@ public class ServiceSynchronize extends LifecycleService { } } - public static void init(Context context, boolean boot) { - ContextCompat.startForegroundService(context, - new Intent(context, ServiceSynchronize.class) - .setAction("init") - .putExtra("boot", boot)); + private static void schedule(Context context) { + Intent alarm = new Intent(context, ServiceSynchronize.class); + alarm.setAction("alarm"); + PendingIntent piAlarm = PendingIntent.getService(context, PI_ALARM, alarm, PendingIntent.FLAG_UPDATE_CURRENT); + + AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + am.cancel(piAlarm); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + if (!prefs.getBoolean("schedule", false)) + return; + + int minuteStart = prefs.getInt("schedule_start", 0); + int minuteEnd = prefs.getInt("schedule_end", 0); + + if (minuteEnd <= minuteStart) + minuteEnd += 24 * 60; + + Calendar calStart = Calendar.getInstance(); + calStart.set(Calendar.HOUR_OF_DAY, minuteStart / 60); + calStart.set(Calendar.MINUTE, minuteStart % 60); + calStart.set(Calendar.SECOND, 0); + calStart.set(Calendar.MILLISECOND, 0); + + Calendar calEnd = Calendar.getInstance(); + calEnd.set(Calendar.HOUR_OF_DAY, minuteEnd / 60); + calEnd.set(Calendar.MINUTE, minuteEnd % 60); + calEnd.set(Calendar.SECOND, 0); + calEnd.set(Calendar.MILLISECOND, 0); + + long now = new Date().getTime(); + if (now > calEnd.getTimeInMillis()) { + calStart.set(Calendar.DAY_OF_MONTH, calStart.get(Calendar.DAY_OF_MONTH) + 1); + calEnd.set(Calendar.DAY_OF_MONTH, calEnd.get(Calendar.DAY_OF_MONTH) + 1); + } + + long start = calStart.getTimeInMillis(); + long end = calEnd.getTimeInMillis(); + long next = (now < start ? start : end); + + Log.i("Schedule now=" + new Date(now)); + Log.i("Schedule start=" + new Date(start)); + Log.i("Schedule end=" + new Date(end)); + Log.i("Schedule next=" + new Date(next)); + + boolean enabled = (now >= start && now < end); + prefs.edit().putBoolean("enabled", enabled).apply(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, next, piAlarm); + else + am.set(AlarmManager.RTC_WAKEUP, next, piAlarm); + } + + static void boot(final Context context) { + if (!booted) { + booted = true; + + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + try { + DB db = DB.getInstance(context); + + // Restore snooze timers + for (EntityMessage message : db.message().getSnoozed()) + EntityMessage.snooze(context, message.id, message.ui_snoozed); + + // Restore schedule + schedule(context); + + // Conditionally init service + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + boolean enabled = prefs.getBoolean("enabled", true); + + int accounts = db.account().getSynchronizingAccounts(false).size(); + + if (enabled && accounts > 0) + ContextCompat.startForegroundService(context, + new Intent(context, ServiceSynchronize.class) + .setAction("init")); + } catch (Throwable ex) { + Log.e(ex); + } + } + }); + thread.start(); + } } - public static void schedule(Context context) { + static void reschedule(Context context) { ContextCompat.startForegroundService(context, new Intent(context, ServiceSynchronize.class) - .setAction("schedule")); + .setAction("alarm")); } - public static void reload(Context context, String reason) { + static void reload(Context context, String reason) { ContextCompat.startForegroundService(context, new Intent(context, ServiceSynchronize.class) .setAction("reload")