Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LENOVO and INFINIX to list of exclusions for Resources.mContext leaks. #2573

3 changes: 1 addition & 2 deletions detekt-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,7 @@ style:
RedundantVisibilityModifierRule:
active: false
ReturnCount:
#LeakCanary - increased from 2 to 4
active: true
active: false
max: 4
excludedFunctions: "equals"
excludeLabeled: false
Expand Down
16 changes: 15 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@

Please thank our [contributors](https://github.com/square/leakcanary/graphs/contributors) 🙏 🙏 🙏.

I've started working on LeakCanary 3.0 so new 2.x releases only contain bug fixes and new known leak patterns.

## Version 2.12 (2023-06-29)

* 💥 [#2527](https://github.com/square/leakcanary/issues/2527) `LifecycleRegistry` in `androidx.lifecycle:lifecycle-runtime` was migrated to kotlin and its `mState` field name changed to `state` which broke LeakCanary expectations.
* 🐤 [#2545](https://github.com/square/leakcanary/pull/2545) Added several known manufacturer & framework leaks.


## Version 2.11 (2023-05-17)

* 🐛 [#1764](https://github.com/square/leakcanary/issues/1764) Ignore phantom classes that were unloaded than reloaded (long time LeakCanary bug).
* 🐛 [#2471](https://github.com/square/leakcanary/issues/2471) Fix LeakCanary introducing a weird leak in Google's CI infra.
* 🐛 [#2496](https://github.com/square/leakcanary/issues/2496) Fix broken ViewModel leak detection

## Version 2.10 (2022-11-10)

### Experimental Neo4j heap dump exploration
Expand All @@ -12,7 +26,7 @@ Please thank our [contributors](https://github.com/square/leakcanary/graphs/cont
```
brew install leakcanary-shark

shark-cli --process com.example.app.debug neo4j
shark-cli --process com.example.app.debug neo4j
```

![Neo4J heap dump](https://user-images.githubusercontent.com/557033/200693468-aa783bb4-9a5a-4a41-8b92-582d44b31b92.png)
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extra:
leak_canary:
release: '2.11'
release: '2.12'
next_release: '3.0'
social:
- icon: fontawesome/brands/github-alt
Expand Down
8 changes: 8 additions & 0 deletions shark-android/api/shark-android.api
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public final class shark/AndroidMetadataExtractor : shark/MetadataExtractor {

public abstract class shark/AndroidObjectInspectors : java/lang/Enum, shark/ObjectInspector {
public static final field ACTIVITY Lshark/AndroidObjectInspectors;
public static final field ACTIVITY_THREAD Lshark/AndroidObjectInspectors;
public static final field ANDROIDX_FRAGMENT Lshark/AndroidObjectInspectors;
public static final field ANIMATOR Lshark/AndroidObjectInspectors;
public static final field APPLICATION Lshark/AndroidObjectInspectors;
Expand Down Expand Up @@ -78,6 +79,7 @@ public abstract class shark/AndroidReferenceMatchers : java/lang/Enum {
public static final field ASSIST_STRUCTURE Lshark/AndroidReferenceMatchers;
public static final field AUDIO_MANAGER Lshark/AndroidReferenceMatchers;
public static final field AUDIO_MANAGER__MCONTEXT_STATIC Lshark/AndroidReferenceMatchers;
public static final field AW_CONTENTS__A0 Lshark/AndroidReferenceMatchers;
public static final field AW_RESOURCE__SRESOURCES Lshark/AndroidReferenceMatchers;
public static final field BACKDROP_FRAME_RENDERER__MDECORVIEW Lshark/AndroidReferenceMatchers;
public static final field BIOMETRIC_PROMPT Lshark/AndroidReferenceMatchers;
Expand All @@ -91,11 +93,14 @@ public abstract class shark/AndroidReferenceMatchers : java/lang/Enum {
public static final field CONTROLLED_INPUT_CONNECTION_WRAPPER Lshark/AndroidReferenceMatchers;
public static final field Companion Lshark/AndroidReferenceMatchers$Companion;
public static final field DEVICE_POLICY_MANAGER__SETTINGS_OBSERVER Lshark/AndroidReferenceMatchers;
public static final field DREAM_SERVICE Lshark/AndroidReferenceMatchers;
public static final field EDITTEXT_BLINK_MESSAGEQUEUE Lshark/AndroidReferenceMatchers;
public static final field EVENT_RECEIVER__MMESSAGE_QUEUE Lshark/AndroidReferenceMatchers;
public static final field EXTENDED_STATUS_BAR_MANAGER Lshark/AndroidReferenceMatchers;
public static final field FINALIZER_WATCHDOG_DAEMON Lshark/AndroidReferenceMatchers;
public static final field FLIPPER__APPLICATION_DESCRIPTOR Lshark/AndroidReferenceMatchers;
public static final field GESTURE_BOOST_MANAGER Lshark/AndroidReferenceMatchers;
public static final field HMD_GLOBAL Ljava/lang/String;
public static final field HOST_ADPU_SERVICE_MSG_HANDLER Lshark/AndroidReferenceMatchers;
public static final field HUAWEI Ljava/lang/String;
public static final field IMM_CURRENT_INPUT_CONNECTION Lshark/AndroidReferenceMatchers;
Expand All @@ -104,6 +109,7 @@ public abstract class shark/AndroidReferenceMatchers : java/lang/Enum {
public static final field INPUT_METHOD_MANAGER_IS_TERRIBLE Lshark/AndroidReferenceMatchers;
public static final field INSTRUMENTATION_RECOMMEND_ACTIVITY Lshark/AndroidReferenceMatchers;
public static final field IREQUEST_FINISH_CALLBACK Lshark/AndroidReferenceMatchers;
public static final field JOB_SERVICE Lshark/AndroidReferenceMatchers;
public static final field LAYOUT_TRANSITION Lshark/AndroidReferenceMatchers;
public static final field LEAK_CANARY_HEAP_DUMPER Lshark/AndroidReferenceMatchers;
public static final field LEAK_CANARY_INTERNAL Lshark/AndroidReferenceMatchers;
Expand Down Expand Up @@ -156,6 +162,8 @@ public abstract class shark/AndroidReferenceMatchers : java/lang/Enum {
public static final field VIEW_GROUP__M_PRE_SORTED_CHILDREN Lshark/AndroidReferenceMatchers;
public static final field VIVO Ljava/lang/String;
public static final field WINDOW_ON_BACK_INVOKED_DISPATCHER__STUB Lshark/AndroidReferenceMatchers;
public static final field XIAMI__RESOURCES_IMPL Lshark/AndroidReferenceMatchers;
public static final field XIAOMI Ljava/lang/String;
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public static final fun buildKnownReferences (Ljava/util/Set;)Ljava/util/List;
public static final fun getAppDefaults ()Ljava/util/List;
Expand Down
1 change: 1 addition & 0 deletions shark-android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ dependencies {
testImplementation libs.mockito
testImplementation libs.mockitoKotlin
testImplementation libs.okio2
testImplementation projects.sharkHprofTest
testImplementation projects.sharkTest
}
14 changes: 13 additions & 1 deletion shark-android/src/main/java/shark/AndroidObjectInspectors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ enum class AndroidObjectInspectors : ObjectInspector {
}
},

ACTIVITY_THREAD {
override fun inspect(reporter: ObjectReporter) {
reporter.whenInstanceOf("android.app.ActivityThread") {
notLeakingReasons += "ActivityThread is a singleton"
}
}
},

APPLICATION {
override fun inspect(
reporter: ObjectReporter
Expand Down Expand Up @@ -854,7 +862,11 @@ enum class AndroidObjectInspectors : ObjectInspector {

private val HeapInstance.lifecycleRegistryState: String
get() {
val state = this["androidx.lifecycle.LifecycleRegistry", "mState"]!!.valueAsInstance!!
// LifecycleRegistry was converted to Kotlin
// https://cs.android.com/androidx/platform/frameworks/support/+/36833f9ab0c50bf449fc795e297a0e124df3356e
val stateField = this["androidx.lifecycle.LifecycleRegistry", "state"]
?: this["androidx.lifecycle.LifecycleRegistry", "mState"]!!
val state = stateField.valueAsInstance!!
return state["java.lang.Enum", "name"]!!.value.readAsJavaString()!!
}
},
Expand Down
108 changes: 93 additions & 15 deletions shark-android/src/main/java/shark/AndroidReferenceMatchers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,21 @@ enum class AndroidReferenceMatchers {
}
},

/**
* See AndroidReferenceReaders.ACTIVITY_THREAD__NEW_ACTIVITIES for more context
*/
ACTIVITY_THREAD__M_NEW_ACTIVITIES {
override fun add(
references: MutableList<ReferenceMatcher>
) {
references += instanceFieldLeak(
"android.app.ActivityThread", "mNewActivities",
description = """
New activities are leaks by ActivityThread until the main thread becomes idle.
New activities are leaked by ActivityThread until the main thread becomes idle.
Tracked here: https://issuetracker.google.com/issues/258390457
""".trimIndent()
) {
sdkInt in 19..33
sdkInt >= 19
}
}
},
Expand Down Expand Up @@ -245,7 +248,7 @@ enum class AndroidReferenceMatchers {
InputMethodManager.mImeInsetsConsumer isn't set to null when the activity is destroyed.
""".trimIndent()
) {
sdkInt == 31
sdkInt >= 31
}
}
},
Expand Down Expand Up @@ -541,7 +544,7 @@ enum class AndroidReferenceMatchers {
" on the screen. TextView.ChangeWatcher and android.widget.Editor end up in spans and" +
" typically hold on to the view hierarchy"
) {
sdkInt in 24..30
sdkInt >= 24
}
}
},
Expand Down Expand Up @@ -814,15 +817,17 @@ enum class AndroidReferenceMatchers {
override fun add(
references: MutableList<ReferenceMatcher>
) {
references += instanceFieldLeak(
"android.app.AppOpsManager\$3", "this\$0",
references += nativeGlobalVariableLeak(
"android.app.AppOpsManager\$3",
description = """
AppOpsManager\$3 implements IAppOpsActiveCallback.Stub and is held by a native ref and
holds on to am AppOpsManager which references an activity context.
Report: https://issuetracker.google.com/issues/210899127
Fix: Update androidx.core:core to 1.10.0-alpha01 or greater as it includes an Android 12
fix for this leak on Android 12, see https://github.com/androidx/androidx/pull/435 .
AppOpsManager\$3 implements IAppOpsActiveCallback.Stub and is held by a native ref long
until the calling side gets GCed, which can happen long after the stub is no longer of
use.
""".trimIndent()
) {
sdkInt in 31..33
sdkInt in 31..32
}
}
},
Expand Down Expand Up @@ -895,6 +900,60 @@ enum class AndroidReferenceMatchers {
}
},

FLIPPER__APPLICATION_DESCRIPTOR {
override fun add(
references: MutableList<ReferenceMatcher>
) {
references += staticFieldLeak(
"com.facebook.flipper.plugins.inspector.descriptors.ApplicationDescriptor", "editedDelegates",
description = """
Flipper's ApplicationDescriptor leaks root views after they've been detached.
https://github.com/facebook/flipper/issues/4270
""".trimIndent()
)
}
},

AW_CONTENTS__A0 {
override fun add(references: MutableList<ReferenceMatcher>) {
staticFieldLeak(
"org.chromium.android_webview.AwContents",
"A0",
description = """
WindowAndroidWrapper has a strong ref to the context key so this breaks the WeakHashMap
contracts and WeakHashMap is unable to perform its job of auto cleaning.
https://github.com/square/leakcanary/issues/2538
""".trimIndent()
)
}
},

JOB_SERVICE {
override fun add(
references: MutableList<ReferenceMatcher>
) {
AndroidReferenceMatchers.nativeGlobalVariableLeak(
className = "android.app.job.JobService\$1",
description = """
JobService used to be leaked via a binder stub.
Fix: https://cs.android.com/android/_/android/platform/frameworks/base/+/0796e9fb3dc2dd03fa5ff2053c63f14861cffa2f
""".trimIndent()
) { sdkInt < 24 }
}
},

DREAM_SERVICE {
override fun add(references: MutableList<ReferenceMatcher>) {
AndroidReferenceMatchers.nativeGlobalVariableLeak(
className = "android.service.dreams.DreamService\$1",
description = """
DreamService leaks a binder stub.
https://github.com/square/leakcanary/issues/2534
""".trimIndent()
) { sdkInt >= 33 }
}
},

// ######## Manufacturer specific known leaks ########

// SAMSUNG
Expand Down Expand Up @@ -1319,15 +1378,15 @@ enum class AndroidReferenceMatchers {
override fun add(
references: MutableList<ReferenceMatcher>
) {
references += staticFieldLeak(
"android.app.ExtendedStatusBarManager", "sInstance",
references += instanceFieldLeak(
"android.app.ExtendedStatusBarManager", "mContext",
description =
"""
ExtendedStatusBarManager is held in a static sInstance field and has a mContext
field which references a decor context which references a destroyed activity.
ExtendedStatusBarManager has a mContext field which references a decor context which
references a destroyed activity.
""".trimIndent()
) {
manufacturer == SHARP && sdkInt == 30
manufacturer == SHARP && sdkInt >= 30
}
}
},
Expand Down Expand Up @@ -1381,6 +1440,21 @@ enum class AndroidReferenceMatchers {
}
},

XIAMI__RESOURCES_IMPL {
override fun add(references: MutableList<ReferenceMatcher>) {
references += staticFieldLeak(
"android.content.res.ResourcesImpl", "mAppContext",
description = """
A few device manufacturers added a static mAppContext field to the ResourcesImpl class
and that field ends up referencing lower contexts (e.g. service).
""".trimIndent()
) {
listOf(HMD_GLOBAL, INFINIX, LENOVO, XIAOMI).contains(manufacturer) &&
sdkInt >= 30
}
}
},

// ######## Ignored references (not leaks) ########

REFERENCES {
Expand Down Expand Up @@ -1479,6 +1553,10 @@ enum class AndroidReferenceMatchers {
const val VIVO = "vivo"
const val RAZER = "Razer"
const val SHARP = "SHARP"
const val XIAOMI = "Xiaomi"
const val HMD_GLOBAL = "HMD Global"
const val INFINIX = "INFINIX"


/**
* Returns a list of [ReferenceMatcher] that only contains [IgnoredReferenceMatcher] and no
Expand Down
Loading
Loading