Context leak in android.net.ConnectivityManager
In com.mapbox.mapboxsdk.testapp:3.1.0:7.
- com.mapbox.mapboxsdk.testapp.MainActivity has leaked:
- GC ROOT static android.net.ConnectivityManager.sInstance
- references android.net.ConnectivityManager.mContext
- leaks com.mapbox.mapboxsdk.testapp.MainActivity instance
- Retaining: 4.4 KB.
- Reference Key: 6de18d7f-4a02-4269-90a6-c7456a4f9911
- Device: LGE google Nexus 5 hammerhead
- Android Version: 6.0 API: 23 LeakCanary: 1.4-beta1 02804f3
- Durations: watch=6886ms, gc=124ms, heap dump=5054ms, analysis=30699ms
- Details:
- Class android.net.ConnectivityManager
| static EXTRA_EXTRA_INFO = java.lang.String@1882454888 (0x7033fb68)
| static CALLBACK_RESUMED = 524300
| static CALLBACK_LOSING = 524291
| static ACTION_DATA_ACTIVITY_CHANGE = java.lang.String@1882333888 (0x703222c0)
| static sInstance = android.net.ConnectivityManager@316836096 (0x12e28900)
| static TYPE_WIFI = 1
| static EXTRA_OTHER_NETWORK_INFO = java.lang.String@1882559584 (0x70359460)
| static EXTRA_IS_ACTIVE = java.lang.String@1882504768 (0x7034be40)
| static TYPE_ETHERNET = 9
| static TYPE_NONE = -1
| static NETID_UNSET = 0
| static ACTION_TETHER_STATE_CHANGED = java.lang.String@1882334168 (0x703223d8)
| static EXTRA_REALTIME_NS = java.lang.String@1882674192 (0x70375410)
| static EXTRA_DEVICE_TYPE = java.lang.String@1882435136 (0x7033ae40)
| static EXTRA_CAPTIVE_PORTAL = java.lang.String@1882334264 (0x70322438)
| static TYPE_MOBILE_IA = 14
| static ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = java.lang.String@1882333688 (0x703221f8)
| static TYPE_MOBILE_SUPL = 3
| static MAX_NETWORK_TYPE = 17
| static MAX_NETWORK_REQUEST_TIMEOUT_MS = 6000000
| static TETHER_ERROR_ENABLE_NAT_ERROR = 8
| static TAG = java.lang.String@1881886920 (0x702b50c8)
| static EXTRA_IS_CAPTIVE_PORTAL = java.lang.String@1882401328 (0x70332a30)
| static EXTRA_NETWORK_REQUEST = java.lang.String@1882334416 (0x703224d0)
| static TYPE_MOBILE_HIPRI = 5
| static TETHER_ERROR_MASTER_ERROR = 5
| static EXTRA_NETWORK_TYPE = java.lang.String@1882538352 (0x70354170)
| static BASE = 524288
| static ACTION_PROMPT_UNVALIDATED = java.lang.String@1882334080 (0x70322380)
| static TYPE_DUMMY = 8
| static sCallbackRefCount = java.util.concurrent.atomic.AtomicInteger@1884144296 (0x704dc2a8)
| static CALLBACK_CAP_CHANGED = 524294
| static ACTION_BACKGROUND_DATA_SETTING_CHANGED = java.lang.String@1882333496 (0x70322138)
| static $staticOverhead = byte[664]@1885773009 (0x70669cd1)
| static EXTRA_AVAILABLE_TETHER = java.lang.String@1882386048 (0x7032ee80)
| static DEFAULT_NETWORK_PREFERENCE = 1
| static TYPE_MOBILE_FOTA = 10
| static CALLBACK_EXIT = 524297
| static EXTRA_ACTIVE_TETHER = java.lang.String@1882250584 (0x7030dd58)
| static CALLBACK_RELEASED = 524296
| static CALLBACK_IP_CHANGED = 524295
| static CONNECTIVITY_ACTION = java.lang.String@1882333800 (0x70322268)
| static sNetworkCallback = java.util.HashMap@1884146272 (0x704dca60)
| static REQUEST_ID_UNSET = 0
| static ACTION_CAPTIVE_PORTAL_SIGN_IN = java.lang.String@1882333608 (0x703221a8)
| static EXTRA_NETWORK_INFO = java.lang.String@1882538168 (0x703540b8)
| static TETHER_ERROR_IFACE_CFG_ERROR = 10
| static MAX_RADIO_TYPE = 17
| static INET_CONDITION_ACTION = java.lang.String@1882333984 (0x70322320)
| static EXTRA_IS_FAILOVER = java.lang.String@1882505048 (0x7034bf58)
| static TYPE_BLUETOOTH = 7
| static EXTRA_INET_CONDITION = java.lang.String@1882496528 (0x70349e10)
| static TETHER_ERROR_DISABLE_NAT_ERROR = 9
| static TYPE_MOBILE_DUN = 4
| static EXTRA_NETWORK = java.lang.String@1882334344 (0x70322488)
| static TYPE_MOBILE = 0
| static TETHER_ERROR_UNAVAIL_IFACE = 4
| static EXTRA_NO_CONNECTIVITY = java.lang.String@1882540592 (0x70354a30)
| static TYPE_MOBILE_EMERGENCY = 15
| static CALLBACK_UNAVAIL = 524293
| static TYPE_MOBILE_IMS = 11
| static sCallbackHandler = null
| static TYPE_MOBILE_CBS = 12
| static CALLBACK_PRECHECK = 524289
| static TETHER_ERROR_UNTETHER_IFACE_ERROR = 7
| static TETHER_ERROR_NO_ERROR = 0
| static TYPE_WIMAX = 6
| static sLegacyRequests = java.util.HashMap@1884146224 (0x704dca30)
| static TYPE_MOBILE_MMS = 2
| static TETHER_ERROR_SERVICE_UNAVAIL = 2
| static EXTRA_REASON = java.lang.String@1881615128 (0x70272b18)
| static TYPE_VPN = 17
| static EXTRA_ERRORED_TETHER = java.lang.String@1882451936 (0x7033efe0)
| static EXPIRE_LEGACY_REQUEST = 524298
| static REQUEST = 2
| static CALLBACK_SUSPENDED = 524299
| static TETHER_ERROR_UNKNOWN_IFACE = 1
| static TYPE_PROXY = 16
| static TETHER_ERROR_UNSUPPORTED = 3
| static CALLBACK_LOST = 524292
| static TYPE_WIFI_P2P = 13
| static TETHER_ERROR_TETHER_IFACE_ERROR = 6
| static LISTEN = 1
| static CALLBACK_AVAILABLE = 524290- Instance of android.net.ConnectivityManager
| static EXTRA_EXTRA_INFO = java.lang.String@1882454888 (0x7033fb68)
| static CALLBACK_RESUMED = 524300
| static CALLBACK_LOSING = 524291
| static ACTION_DATA_ACTIVITY_CHANGE = java.lang.String@1882333888 (0x703222c0)
| static sInstance = android.net.ConnectivityManager@316836096 (0x12e28900)
| static TYPE_WIFI = 1
| static EXTRA_OTHER_NETWORK_INFO = java.lang.String@1882559584 (0x70359460)
| static EXTRA_IS_ACTIVE = java.lang.String@1882504768 (0x7034be40)
| static TYPE_ETHERNET = 9
| static TYPE_NONE = -1
| static NETID_UNSET = 0
| static ACTION_TETHER_STATE_CHANGED = java.lang.String@1882334168 (0x703223d8)
| static EXTRA_REALTIME_NS = java.lang.String@1882674192 (0x70375410)
| static EXTRA_DEVICE_TYPE = java.lang.String@1882435136 (0x7033ae40)
| static EXTRA_CAPTIVE_PORTAL = java.lang.String@1882334264 (0x70322438)
| static TYPE_MOBILE_IA = 14
| static ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = java.lang.String@1882333688 (0x703221f8)
| static TYPE_MOBILE_SUPL = 3
| static MAX_NETWORK_TYPE = 17
| static MAX_NETWORK_REQUEST_TIMEOUT_MS = 6000000
| static TETHER_ERROR_ENABLE_NAT_ERROR = 8
| static TAG = java.lang.String@1881886920 (0x702b50c8)
| static EXTRA_IS_CAPTIVE_PORTAL = java.lang.String@1882401328 (0x70332a30)
| static EXTRA_NETWORK_REQUEST = java.lang.String@1882334416 (0x703224d0)
| static TYPE_MOBILE_HIPRI = 5
| static TETHER_ERROR_MASTER_ERROR = 5
| static EXTRA_NETWORK_TYPE = java.lang.String@1882538352 (0x70354170)
| static BASE = 524288
| static ACTION_PROMPT_UNVALIDATED = java.lang.String@1882334080 (0x70322380)
| static TYPE_DUMMY = 8
| static sCallbackRefCount = java.util.concurrent.atomic.AtomicInteger@1884144296 (0x704dc2a8)
| static CALLBACK_CAP_CHANGED = 524294
| static ACTION_BACKGROUND_DATA_SETTING_CHANGED = java.lang.String@1882333496 (0x70322138)
| static $staticOverhead = byte[664]@1885773009 (0x70669cd1)
| static EXTRA_AVAILABLE_TETHER = java.lang.String@1882386048 (0x7032ee80)
| static DEFAULT_NETWORK_PREFERENCE = 1
| static TYPE_MOBILE_FOTA = 10
| static CALLBACK_EXIT = 524297
| static EXTRA_ACTIVE_TETHER = java.lang.String@1882250584 (0x7030dd58)
| static CALLBACK_RELEASED = 524296
| static CALLBACK_IP_CHANGED = 524295
| static CONNECTIVITY_ACTION = java.lang.String@1882333800 (0x70322268)
| static sNetworkCallback = java.util.HashMap@1884146272 (0x704dca60)
| static REQUEST_ID_UNSET = 0
| static ACTION_CAPTIVE_PORTAL_SIGN_IN = java.lang.String@1882333608 (0x703221a8)
| static EXTRA_NETWORK_INFO = java.lang.String@1882538168 (0x703540b8)
| static TETHER_ERROR_IFACE_CFG_ERROR = 10
| static MAX_RADIO_TYPE = 17
| static INET_CONDITION_ACTION = java.lang.String@1882333984 (0x70322320)
| static EXTRA_IS_FAILOVER = java.lang.String@1882505048 (0x7034bf58)
| static TYPE_BLUETOOTH = 7
| static EXTRA_INET_CONDITION = java.lang.String@1882496528 (0x70349e10)
| static TETHER_ERROR_DISABLE_NAT_ERROR = 9
| static TYPE_MOBILE_DUN = 4
| static EXTRA_NETWORK = java.lang.String@1882334344 (0x70322488)
| static TYPE_MOBILE = 0
| static TETHER_ERROR_UNAVAIL_IFACE = 4
| static EXTRA_NO_CONNECTIVITY = java.lang.String@1882540592 (0x70354a30)
| static TYPE_MOBILE_EMERGENCY = 15
| static CALLBACK_UNAVAIL = 524293
| static TYPE_MOBILE_IMS = 11
| static sCallbackHandler = null
| static TYPE_MOBILE_CBS = 12
| static CALLBACK_PRECHECK = 524289
| static TETHER_ERROR_UNTETHER_IFACE_ERROR = 7
| static TETHER_ERROR_NO_ERROR = 0
| static TYPE_WIMAX = 6
| static sLegacyRequests = java.util.HashMap@1884146224 (0x704dca30)
| static TYPE_MOBILE_MMS = 2
| static TETHER_ERROR_SERVICE_UNAVAIL = 2
| static EXTRA_REASON = java.lang.String@1881615128 (0x70272b18)
| static TYPE_VPN = 17
| static EXTRA_ERRORED_TETHER = java.lang.String@1882451936 (0x7033efe0)
| static EXPIRE_LEGACY_REQUEST = 524298
| static REQUEST = 2
| static CALLBACK_SUSPENDED = 524299
| static TETHER_ERROR_UNKNOWN_IFACE = 1
| static TYPE_PROXY = 16
| static TETHER_ERROR_UNSUPPORTED = 3
| static CALLBACK_LOST = 524292
| static TYPE_WIFI_P2P = 13
| static TETHER_ERROR_TETHER_IFACE_ERROR = 6
| static LISTEN = 1
| static CALLBACK_AVAILABLE = 524290
| mContext = com.mapbox.mapboxsdk.testapp.MainActivity@314880656 (0x12c4b290)
| mNMService = null
| mNetworkActivityListeners = android.util.ArrayMap@316836128 (0x12e28920)
| mService = android.net.IConnectivityManager$Stub$Proxy@316539792 (0x12de0390)
| shadow$_klass_ = android.net.ConnectivityManager
| shadow$_monitor_ = 0- Instance of com.mapbox.mapboxsdk.testapp.MainActivity
| static STATE_IS_ANNOTATIONS_ON = java.lang.String@315761856 (0x12d224c0)
| static STATE_SELECTED_STYLE = java.lang.String@315761952 (0x12d22520)
| static PERMISSIONS_TRACKING_MODE_ACTIVITY = 1
| static PERMISSIONS_LOCATION = 0
| static LAT_LON_FORMATTER = java.text.DecimalFormat@315762048 (0x12d22580)
| static $staticOverhead = byte[56]@315891713 (0x12d42001)
| static STATE_MARKER_LIST = java.lang.String@315761904 (0x12d224f0)
| static TAG = java.lang.String@315762000 (0x12d22550)
| mCoordinatorLayout = android.support.design.widget.CoordinatorLayout@316290048 (0x12da3400)
| mDrawerLayout = android.support.v4.widget.DrawerLayout@314678272 (0x12c19c00)
| mFpsTextView = android.support.v7.widget.AppCompatTextView@316324864 (0x12dabc00)
| mIsAnnotationsOn = false
| mIsShowingCustomLayer = false
| mLocationFAB = android.support.design.widget.FloatingActionButton@316325888 (0x12dac000)
| mMapView = com.mapbox.mapboxsdk.views.MapView@316291072 (0x12da3800)
| mMarkerList = java.util.ArrayList@315783968 (0x12d27b20)
| mNavigationView = android.support.design.widget.NavigationView@316340224 (0x12daf800)
| mSelectedStyle = 2131493041
| mDelegate = android.support.v7.app.AppCompatDelegateImplV23@315772336 (0x12d24db0)
| mCreated = true
| mFragments = android.support.v4.app.FragmentController@315786384 (0x12d28490)
| mHandler = android.support.v4.app.FragmentActivity$1@315783808 (0x12d27a80)
| mMediaController = null
| mOptionsMenuInvalidated = false
| mReallyStopped = true
| mRequestedPermissionsFromFragment = false
| mResumed = false
| mRetaining = false
| mStopped = true
| mActionBar = null
| mActionModeTypeStarting = 0
| mActivityInfo = android.content.pm.ActivityInfo@315437696 (0x12cd3280)
| mActivityTransitionState = android.app.ActivityTransitionState@315822656 (0x12d31240)
| mApplication = com.mapbox.mapboxsdk.testapp.MapboxApplication@315498016 (0x12ce1e20)
| mCalled = true
| mChangeCanvasToTranslucent = false
| mChangingConfigurations = false
| mComponent = android.content.ComponentName@315203760 (0x12c9a0b0)
| mConfigChangeFlags = 0
| mCurrentConfig = android.content.res.Configuration@315492864 (0x12ce0a00)
| mDecor = null
| mDefaultKeyMode = 0
| mDefaultKeySsb = null
| mDestroyed = true
| mDoReportFullyDrawn = false
| mEmbeddedID = null
| mEnableDefaultActionBarUp = false
| mEnterTransitionListener = android.app.SharedElementCallback$1@1884135360 (0x704d9fc0)
| mExitTransitionListener = android.app.SharedElementCallback$1@1884135360 (0x704d9fc0)
| mFinished = false
| mFragments = android.app.FragmentController@315786272 (0x12d28420)
| mHandler = android.os.Handler@315783680 (0x12d27a00)
| mIdent = 145642231
| mInstanceTracker = android.os.StrictMode$InstanceTracker@315786288 (0x12d28430)
| mInstrumentation = android.app.Instrumentation@315268000 (0x12ca9ba0)
| mIntent = android.content.Intent@315441472 (0x12cd4140)
| mLastNonConfigurationInstances = null
| mMainThread = android.app.ActivityThread@316496512 (0x12dd5a80)
| mManagedCursors = java.util.ArrayList@315783712 (0x12d27a20)
| mManagedDialogs = null
| mMenuInflater = null
| mParent = null
| mReferrer = null
| mResultCode = 0
| mResultData = null
| mResumed = false
| mSearchEvent = null
| mSearchManager = null
| mStartedActivity = false
| mStopped = true
| mTemporaryPause = false
| mTitle = java.lang.String@315762384 (0x12d226d0)
| mTitleColor = 0
| mTitleReady = true
| mToken = android.os.BinderProxy@315196576 (0x12c984a0)
| mTranslucentCallback = null
| mUiThread = java.lang.Thread@1945301664 (0x73f2f2a0)
| mVisibleBehind = false
| mVisibleFromClient = true
| mVisibleFromServer = false
| mVoiceInteractor = null
| mWindow = com.android.internal.policy.PhoneWindow@315937152 (0x12d4d180)
| mWindowAdded = true
| mWindowManager = android.view.WindowManagerImpl@315784672 (0x12d27de0)
| mInflater = com.android.internal.policy.PhoneLayoutInflater@315762624 (0x12d227c0)
| mOverrideConfiguration = null
| mResources = android.content.res.Resources@315267840 (0x12ca9b00)
| mTheme = android.content.res.Resources$Theme@315784704 (0x12d27e00)
| mThemeResource = 2131230852
| mBase = android.app.ContextImpl@315867520 (0x12d3c180)
| shadow$_klass_ = com.mapbox.mapboxsdk.testapp.MainActivity
| shadow$_monitor_ = -2081387007- Excluded Refs:
| Field: android.view.inputmethod.InputMethodManager.mNextServedView
| Field: android.view.inputmethod.InputMethodManager.mServedView
| Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)
| Root Class:android.os.Binder (always)
HeapDump can be found here
Code samples to reproduce:
/**
* You must call this method from the parent's {@link Activity#onResume()} or {@link Fragment#onResume()}.
*/
@UiThread
public void onResume() {
// Register for connectivity changes
mConnectivityReceiver = new ConnectivityReceiver();
getContext().registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
/**
* You must call this method from the parent's {@link Activity#onPause()} or {@link Fragment#onPause()}.
*/
@UiThread
public void onPause() {
// Register for connectivity changes
getContext().unregisterReceiver(mConnectivityReceiver);
mConnectivityReceiver = null;
}
// This class handles connectivity changes
private class ConnectivityReceiver extends BroadcastReceiver {
// Called when an action we are listening to in the manifest has been sent
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
onConnectivityChanged(!noConnectivity);
}
}
}
Nice find! This leak still exists in the latest sources: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/net/ConnectivityManager.java#L1566
Could you file an issue to AOSP? This needs to be fixed. See here for an example: https://code.google.com/p/android/issues/detail?id=171190
Ah, I see you've done it here: https://code.google.com/p/android/issues/detail?id=198852
Please always include more info in AOSP bugs, otherwise they won't look at it.
@tobrun btw you can totally have a temporary fix for this. All you need to do is make sure the ConnectivityManager is first created with an App Context. E.g. in some static init do: context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE)
@pyricau thank you for adding that info to the AOSP ticket and suggested fix resolved this memory leak!
We should add an entry to AndroidExcludedRefs
But if this leak have workaround, maybe, it will be better not to exclude it?
Sorry, i didn't see last updates
I have build 1.6.2 but this leak is still present. However i ended up fixing it by creating an object of ConnectivityManager in my class that extends Application using applicationContext. Earlier, i was doing it later in one of my activities but the bug persisted as probably some of the library was internally using connectivityManager.
Most helpful comment
@tobrun btw you can totally have a temporary fix for this. All you need to do is make sure the ConnectivityManager is first created with an App Context. E.g. in some static init do:
context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE)