From af83f236a35e7e7ae53b8d904375ecdf4a66e40c Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 17 Apr 2022 21:34:33 +0200 Subject: [PATCH] Watch services/theads --- .../java/eu.faircode.email/CoalMine.java | 24 +++++- app/src/main/java/eu/faircode/email/Core.java | 1 + .../java/eu/faircode/email/RunnableEx.java | 39 ++++++++++ .../eu/faircode/email/ServiceExternal.java | 1 + .../faircode/email/ServicePowerControl.java | 6 ++ .../java/eu/faircode/email/ServiceSend.java | 1 + .../eu/faircode/email/ServiceSynchronize.java | 77 ++++++++++--------- .../eu/faircode/email/ServiceTileClear.java | 6 ++ .../email/ServiceTileSynchronize.java | 6 ++ .../eu/faircode/email/ServiceTileUnseen.java | 1 + .../java/eu/faircode/email/ServiceUI.java | 1 + .../java/eu/faircode/email/SimpleTask.java | 1 - .../java/eu/faircode/email/TwoStateOwner.java | 1 - .../java/eu.faircode.email/CoalMine.java | 4 +- 14 files changed, 126 insertions(+), 43 deletions(-) create mode 100644 app/src/main/java/eu/faircode/email/RunnableEx.java diff --git a/app/src/debug/java/eu.faircode.email/CoalMine.java b/app/src/debug/java/eu.faircode.email/CoalMine.java index afb4544fa0..7db3b13d30 100644 --- a/app/src/debug/java/eu.faircode.email/CoalMine.java +++ b/app/src/debug/java/eu.faircode.email/CoalMine.java @@ -29,6 +29,7 @@ import java.util.List; import kotlin.Unit; import kotlin.jvm.functions.Function2; +import leakcanary.AppWatcher; import leakcanary.LeakCanary; import shark.HeapField; import shark.HeapObject; @@ -81,6 +82,24 @@ public class CoalMine { } }); + inspectors.add(new ObjectInspector() { + @Override + public void inspect(@NonNull ObjectReporter reporter) { + String clazz = RunnableEx.class.getName(); + reporter.whenInstanceOf(clazz, new Function2() { + @Override + public Unit invoke(ObjectReporter reporter, HeapObject.HeapInstance instance) { + HeapField fname = instance.get(clazz, "name"); + if (fname != null) { + String name = fname.getValue().readAsJavaString(); + reporter.getNotLeakingReasons().add("name=" + name); + } + return null; + } + }); + } + }); + LeakCanary.Config config = LeakCanary.getConfig().newBuilder() .dumpHeap(enabled && BuildConfig.DEBUG) .objectInspectors(inspectors) @@ -93,8 +112,9 @@ public class CoalMine { LeakCanary.INSTANCE.dumpHeap(); } - static void watch(Object object, String reason) { - //AppWatcher.INSTANCE.getObjectWatcher().expectWeaklyReachable(object, reason); + static void watch(@NonNull Object object, String reason) { + Log.i("Watching " + object.getClass() + " because " + reason); + AppWatcher.INSTANCE.getObjectWatcher().expectWeaklyReachable(object, reason); } static Intent getIntent() { diff --git a/app/src/main/java/eu/faircode/email/Core.java b/app/src/main/java/eu/faircode/email/Core.java index 968cc5f677..4a476d5f92 100644 --- a/app/src/main/java/eu/faircode/email/Core.java +++ b/app/src/main/java/eu/faircode/email/Core.java @@ -5882,6 +5882,7 @@ class Core { void join() { join(thread); + CoalMine.watch(thread, getClass().getSimpleName() + "#join()"); } void ensureRunning(String reason) throws OperationCanceledException { diff --git a/app/src/main/java/eu/faircode/email/RunnableEx.java b/app/src/main/java/eu/faircode/email/RunnableEx.java new file mode 100644 index 0000000000..46d01af529 --- /dev/null +++ b/app/src/main/java/eu/faircode/email/RunnableEx.java @@ -0,0 +1,39 @@ +package eu.faircode.email; + +/* + This file is part of FairEmail. + + FairEmail is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FairEmail is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FairEmail. If not, see . + + Copyright 2018-2022 by Marcel Bokhorst (M66B) +*/ + +public abstract class RunnableEx implements Runnable { + public String name; + + public RunnableEx(String name) { + this.name = name; + } + + @Override + public void run() { + try { + delegate(); + } catch (Throwable ex) { + Log.e(ex); + } + } + + protected abstract void delegate(); +} diff --git a/app/src/main/java/eu/faircode/email/ServiceExternal.java b/app/src/main/java/eu/faircode/email/ServiceExternal.java index 9f32987689..d94507bcb5 100644 --- a/app/src/main/java/eu/faircode/email/ServiceExternal.java +++ b/app/src/main/java/eu/faircode/email/ServiceExternal.java @@ -67,6 +67,7 @@ public class ServiceExternal extends Service { Log.i("Service external destroy"); stopForeground(true); super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); } @Override diff --git a/app/src/main/java/eu/faircode/email/ServicePowerControl.java b/app/src/main/java/eu/faircode/email/ServicePowerControl.java index 6d7b218306..587c5ef53a 100644 --- a/app/src/main/java/eu/faircode/email/ServicePowerControl.java +++ b/app/src/main/java/eu/faircode/email/ServicePowerControl.java @@ -131,6 +131,12 @@ public class ServicePowerControl extends ControlsProviderService { } } + @Override + public void onDestroy() { + super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); + } + private PendingIntent getPendingIntent() { Context context = getBaseContext(); return PendingIntentCompat.getActivity( diff --git a/app/src/main/java/eu/faircode/email/ServiceSend.java b/app/src/main/java/eu/faircode/email/ServiceSend.java index 05bccf0506..9eda5e5594 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSend.java +++ b/app/src/main/java/eu/faircode/email/ServiceSend.java @@ -191,6 +191,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar nm.cancel(NotificationHelper.NOTIFICATION_SEND); super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); } @Override diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index e72e063711..6ccffddaa2 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -430,9 +430,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void init(final TupleAccountNetworkState accountNetworkState) { - queue.submit(new Runnable() { + queue.submit(new RunnableEx("state#init") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -473,9 +473,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences "Service start=" + accountNetworkState + " sync=" + sync + " force=" + force); final Core.State astate = new Core.State(accountNetworkState.networkState); - astate.runnable(new Runnable() { + astate.runnable(new RunnableEx("state#monitor") { @Override - public void run() { + public void delegate() { try { monitorAccount(accountNetworkState.accountState, astate, sync, force); } catch (Throwable ex) { @@ -485,9 +485,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }, "sync.account." + accountNetworkState.accountState.id); coreStates.put(accountNetworkState.accountState.id, astate); - queue.submit(new Runnable() { + queue.submit(new RunnableEx("state#start") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -522,9 +522,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling, "Service stop=" + accountNetworkState); - queue.submit(new Runnable() { + queue.submit(new RunnableEx("state#stop") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -556,9 +556,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling, "Service delete=" + accountNetworkState); - queue.submit(new Runnable() { + queue.submit(new RunnableEx("state#delete") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -579,9 +579,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void quit(final Integer eventId) { - queue.submit(new Runnable() { + queue.submit(new RunnableEx("state#quit") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -631,12 +631,12 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }); } - private final Runnable backup = new Runnable() { + private final Runnable backup = new RunnableEx("state#backup") { @Override - public void run() { - queue.submit(new Runnable() { + public void delegate() { + queue.submit(new RunnableEx("state#backup#exec") { @Override - public void run() { + public void delegate() { try { wl.acquire(); @@ -734,9 +734,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences @Override public void onChanged(final List messages) { - executor.submit(new Runnable() { + executor.submit(new RunnableEx("liveUnseenNotify") { @Override - public void run() { + public void delegate() { try { Core.notifyMessages(ServiceSynchronize.this, messages, notificationData, foreground); } catch (SecurityException ex) { @@ -919,6 +919,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences nm.cancel(NotificationHelper.NOTIFICATION_SYNCHRONIZE); super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); } @Override @@ -1059,9 +1060,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences String action = intent.getAction(); long id = Long.parseLong(action.split(":")[1]); - executor.submit(new Runnable() { + executor.submit(new RunnableEx("unsnooze") { @Override - public void run() { + public void delegate() { try { EntityFolder folder; @@ -1178,9 +1179,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences String action = intent.getAction(); long id = Long.parseLong(action.split(":")[1]); - executor.submit(new Runnable() { + executor.submit(new RunnableEx("exists") { @Override - public void run() { + public void delegate() { try { DB db = DB.getInstance(ServiceSynchronize.this); @@ -1214,9 +1215,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } private void onPoll(Intent intent) { - executor.submit(new Runnable() { + executor.submit(new RunnableEx("poll") { @Override - public void run() { + public void delegate() { try { DB db = DB.getInstance(ServiceSynchronize.this); try { @@ -1758,9 +1759,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }); // Idle folder - Thread idler = new Thread(new Runnable() { + Thread idler = new Thread(new RunnableEx("idle") { @Override - public void run() { + public void delegate() { try { Log.i(folder.name + " start idle"); while (ifolder.isOpen() && state.isRunning() && state.isRecoverable()) { @@ -1833,12 +1834,12 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences forced = true; - final Runnable purge = new Runnable() { + final Runnable purge = new RunnableEx("purge") { @Override - public void run() { - executor.submit(new Runnable() { + public void delegate() { + executor.submit(new RunnableEx("purge#exec") { @Override - public void run() { + public void delegate() { try { wlAccount.acquire(); @@ -1858,9 +1859,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences final long serial = state.getSerial(); Log.i(account.name + " observing operations"); - getMainHandler().post(new Runnable() { + getMainHandler().post(new RunnableEx("observe#start") { @Override - public void run() { + public void delegate() { cowner.value = new TwoStateOwner(ServiceSynchronize.this, account.name); cowner.value.start(); @@ -2317,9 +2318,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences Log.i(account.name + " stop watching operations"); final TwoStateOwner _owner = cowner.value; if (_owner != null) - getMainHandler().post(new Runnable() { + getMainHandler().post(new RunnableEx("observe#stop") { @Override - public void run() { + public void delegate() { try { _owner.destroy(); } catch (Throwable ex) { @@ -2694,9 +2695,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences }; private void updateNetworkState(final Network network, final String reason) { - getMainHandler().post(new Runnable() { + getMainHandler().post(new RunnableEx("network") { @Override - public void run() { + public void delegate() { try { Network active = ConnectionHelper.getActiveNetwork(ServiceSynchronize.this); @@ -2845,9 +2846,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences } static void boot(final Context context) { - executor.submit(new Runnable() { + executor.submit(new RunnableEx("boot") { @Override - public void run() { + public void delegate() { try { EntityLog.log(context, "Boot sync service"); diff --git a/app/src/main/java/eu/faircode/email/ServiceTileClear.java b/app/src/main/java/eu/faircode/email/ServiceTileClear.java index bc237075f3..c3d5a00958 100644 --- a/app/src/main/java/eu/faircode/email/ServiceTileClear.java +++ b/app/src/main/java/eu/faircode/email/ServiceTileClear.java @@ -28,4 +28,10 @@ public class ServiceTileClear extends TileService { public void onClick() { startActivityAndCollapse(ActivityClear.getIntent(this)); } + + @Override + public void onDestroy() { + super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); + } } diff --git a/app/src/main/java/eu/faircode/email/ServiceTileSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceTileSynchronize.java index 60a43ebeeb..025be80635 100644 --- a/app/src/main/java/eu/faircode/email/ServiceTileSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceTileSynchronize.java @@ -84,4 +84,10 @@ public class ServiceTileSynchronize extends TileService implements SharedPrefere boolean enabled = !prefs.getBoolean("enabled", true); prefs.edit().putBoolean("enabled", enabled).apply(); } + + @Override + public void onDestroy() { + super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); + } } diff --git a/app/src/main/java/eu/faircode/email/ServiceTileUnseen.java b/app/src/main/java/eu/faircode/email/ServiceTileUnseen.java index 89215692d7..bb5f277d97 100644 --- a/app/src/main/java/eu/faircode/email/ServiceTileUnseen.java +++ b/app/src/main/java/eu/faircode/email/ServiceTileUnseen.java @@ -86,6 +86,7 @@ public class ServiceTileUnseen extends TileService { public void onDestroy() { owner.destroy(); super.onDestroy(); + CoalMine.watch(this, getClass().getSimpleName() + "#onDestroy()"); } public void onStartListening() { diff --git a/app/src/main/java/eu/faircode/email/ServiceUI.java b/app/src/main/java/eu/faircode/email/ServiceUI.java index 7ee039564f..bcc56277b2 100644 --- a/app/src/main/java/eu/faircode/email/ServiceUI.java +++ b/app/src/main/java/eu/faircode/email/ServiceUI.java @@ -79,6 +79,7 @@ public class ServiceUI extends IntentService { public void onDestroy() { Log.i("Service UI destroy"); super.onDestroy(); + CoalMine.watch(this, "ServiceUI#onDestroy()"); } @Override diff --git a/app/src/main/java/eu/faircode/email/SimpleTask.java b/app/src/main/java/eu/faircode/email/SimpleTask.java index beaedd4a78..9c51a229e4 100644 --- a/app/src/main/java/eu/faircode/email/SimpleTask.java +++ b/app/src/main/java/eu/faircode/email/SimpleTask.java @@ -246,7 +246,6 @@ public abstract class SimpleTask implements LifecycleObserver { } } }); - CoalMine.watch(SimpleTask.this, "Task done=" + name); } }); diff --git a/app/src/main/java/eu/faircode/email/TwoStateOwner.java b/app/src/main/java/eu/faircode/email/TwoStateOwner.java index 2a0cf88ae0..22bb7b2893 100644 --- a/app/src/main/java/eu/faircode/email/TwoStateOwner.java +++ b/app/src/main/java/eu/faircode/email/TwoStateOwner.java @@ -72,7 +72,6 @@ public class TwoStateOwner implements LifecycleOwner { owned = false; destroy(); owner.getLifecycle().removeObserver(this); - CoalMine.watch(TwoStateOwner.this, "State done=" + aname); } }); } diff --git a/app/src/release/java/eu.faircode.email/CoalMine.java b/app/src/release/java/eu.faircode.email/CoalMine.java index be746fb4a0..641798d066 100644 --- a/app/src/release/java/eu.faircode.email/CoalMine.java +++ b/app/src/release/java/eu.faircode.email/CoalMine.java @@ -21,6 +21,8 @@ package eu.faircode.email; import android.content.Intent; +import androidx.annotation.NonNull; + public class CoalMine { static void setup(boolean enabled) { } @@ -28,7 +30,7 @@ public class CoalMine { static void check() { } - static void watch(Object object, String reason) { + static void watch(@NonNull Object object, String reason) { } static Intent getIntent() {