From c520cb2622a5f7356f73d59f78751cc9638a652b Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 26 May 2022 22:05:42 +0200 Subject: [PATCH] Check for leaking receivers --- .../java/eu/faircode/email/ActivityBase.java | 41 +++++++++++++++++ .../java/eu/faircode/email/ServiceBase.java | 44 +++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/app/src/main/java/eu/faircode/email/ActivityBase.java b/app/src/main/java/eu/faircode/email/ActivityBase.java index 53cba1dc23..2c2d1180bb 100644 --- a/app/src/main/java/eu/faircode/email/ActivityBase.java +++ b/app/src/main/java/eu/faircode/email/ActivityBase.java @@ -21,9 +21,11 @@ package eu.faircode.email; import android.Manifest; import android.app.ActivityManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Bitmap; @@ -77,6 +79,7 @@ abstract class ActivityBase extends AppCompatActivity implements SharedPreferenc private boolean visible; private boolean contacts; private List keyPressedListeners = new ArrayList<>(); + private List registeredReceivers = new ArrayList<>(); @Override protected void attachBaseContext(Context base) { @@ -347,12 +350,50 @@ abstract class ActivityBase extends AppCompatActivity implements SharedPreferenc } } + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, int flags) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, flags); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler, int flags) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, broadcastPermission, scheduler, flags); + } + + @Override + public void unregisterReceiver(BroadcastReceiver receiver) { + super.unregisterReceiver(receiver); + registeredReceivers.remove(receiver); + } + @Override protected void onDestroy() { Log.i("Destroy " + this.getClass().getName()); PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this); try { getSupportFragmentManager().unregisterFragmentLifecycleCallbacks(lifecycleCallbacks); + + Log.i(this.getClass() + " receivers leaking=" + registeredReceivers.size()); + for (BroadcastReceiver receiver : registeredReceivers) { + Log.e(this.getClass() + " receiver leaking class=" + receiver.getClass()); + unregisterReceiver(receiver); + } + registeredReceivers.clear(); + super.onDestroy(); originalContext = null; } catch (Throwable ex) { diff --git a/app/src/main/java/eu/faircode/email/ServiceBase.java b/app/src/main/java/eu/faircode/email/ServiceBase.java index dbc38d17d1..9452475f54 100644 --- a/app/src/main/java/eu/faircode/email/ServiceBase.java +++ b/app/src/main/java/eu/faircode/email/ServiceBase.java @@ -19,16 +19,23 @@ package eu.faircode.email; Copyright 2018-2022 by Marcel Bokhorst (M66B) */ +import android.content.BroadcastReceiver; import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; +import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleService; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; abstract class ServiceBase extends LifecycleService { + private List registeredReceivers = new ArrayList<>(); + @Override public void onCreate() { Map crumb = new HashMap<>(); @@ -55,12 +62,49 @@ abstract class ServiceBase extends LifecycleService { return super.onStartCommand(intent, flags, startId); } + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, int flags) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, flags); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, broadcastPermission, scheduler); + } + + @Override + public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter, @Nullable String broadcastPermission, @Nullable Handler scheduler, int flags) { + registeredReceivers.add(receiver); + return super.registerReceiver(receiver, filter, broadcastPermission, scheduler, flags); + } + + @Override + public void unregisterReceiver(BroadcastReceiver receiver) { + super.unregisterReceiver(receiver); + registeredReceivers.remove(receiver); + } + @Override public void onDestroy() { Map crumb = new HashMap<>(); crumb.put("state", "destroy"); Log.breadcrumb(this.getClass().getSimpleName(), crumb); + Log.i(this.getClass() + " receivers leaking=" + registeredReceivers.size()); + for (BroadcastReceiver receiver : registeredReceivers) { + Log.e(this.getClass() + " receiver leaking class=" + receiver.getClass()); + unregisterReceiver(receiver); + } + registeredReceivers.clear(); + super.onDestroy(); }