Open niqo01 opened 2 years ago
Until Google provides the APIs we need to do this, there's really no way around it. This strict mode thing is just sad. You can always disable the ServiceWatcher if you really care.
We could potentially provide utilities to help ignore LeakCanary strict mode violations. Not sure about any auto install though.
Something inspired from this:
private fun initializeStrictMode() {
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy())
.run {
if (Build.VERSION.SDK_INT >= 28) {
detectNonSdkApiUsage()
.penaltyListener(
{
it.run()
},
{ violation ->
handleViolation(violation)
}
)
} else {
this
}
}
.build()
)
}
@RequiresApi(28)
private fun handleViolation(violation: Violation) {
when (violation) {
is NonSdkApiUsedViolation -> handleNonSdkApiUsedViolation(violation)
}
}
// non-sdk API calls in code that we have control of.
private val knownViolations = setOf(
// Called in com.squareup.shark.config.ImmCurRootViewFix on API 28 only, where it was on the
// greylist. Later it was moved on the black list, but that's not important anymore.
"Landroid/view/inputmethod/InputMethodManager;->mCurRootView:Landroid/view/View;",
"Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;",
)
private fun handleNonSdkApiUsedViolation(violation: NonSdkApiUsedViolation) {
// Ignore the known violations.
if (violation.message in knownViolations) return
// Exceptions look something like that:
//
// Caused by: android.os.strictmode.NonSdkApiUsedViolation: Landroid/view/View;->mKeyedTags:Landroid/util/SparseArray;
// at android.os.StrictMode.lambda$static$1(StrictMode.java:416)
// at android.os.-$$Lambda$StrictMode$lu9ekkHJ2HMz0jd3F8K8MnhenxQ.accept(Unknown Source:2)
// at java.lang.Class.getDeclaredField(Native Method)
// at com.facebook.flipper.plugins.inspector.descriptors.ViewDescriptor.<clinit>(ViewDescriptor.java:63)
//
// This code gives us the important line after the reflection call.
val offendingCaller = violation.stackTrace.first {
!it.className.startsWith("android.os") && !it.className.startsWith("java.lang.Class")
}
// These callers use elements from the greylist. Unfortunately, the violation object doesn't
// give us any hint about what kind of violation it is. We can safely ignore greylist filters and
// filter them here.
//
// Note that these callers are only third party dependencies. Our own violations are listed in
// the 'knownViolations' collection.
//
// When we upgrade the target SDK, we should check them all again.
when {
// This is fiiiine
offendingCaller.className.startsWith("papa.") -> return
offendingCaller.className.startsWith("curtains.") -> return
offendingCaller.className.startsWith("leakcanary.") -> return
offendingCaller.className.startsWith("radiography.") -> return
// Google probably knows what they're doing.
offendingCaller.className.startsWith("androidx.") -> return
// etc etc
}
throw violation
}
I am running into a new NonSdkApiUsedViolation from LeakCanary 2.14 related to android.view.WindowManagerGlobal. Not sure what introduced this, Android 15 Beta 3 or new LeakCanary version may be to blame.
android.os.strictmode.NonSdkApiUsedViolation: Landroid/view/WindowManagerGlobal;->getInstance()Landroid/view/WindowManagerGlobal;
at android.os.StrictMode.lambda$static$1(StrictMode.java:432)
at android.os.StrictMode$$ExternalSyntheticLambda2.accept(D8$$SyntheticClass:0)
at java.lang.Class.getDeclaredMethodInternal(Native Method)
at java.lang.Class.getPublicMethodRecursive(Class.java:2957)
at java.lang.Class.getMethod(Class.java:2944)
at java.lang.Class.getMethod(Class.java:2450)
at curtains.internal.WindowManagerSpy$windowManagerInstance$2.invoke(WindowManagerSpy.kt:37)
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
at curtains.internal.WindowManagerSpy.getWindowManagerInstance(Unknown Source:2)
at curtains.internal.WindowManagerSpy.swapWindowManagerGlobalMViews(WindowManagerSpy.kt:54)
at curtains.internal.RootViewsSpy$Companion.install(RootViewsSpy.kt:39)
at curtains.Curtains$rootViewsSpy$2.invoke(Curtains.kt:33)
at curtains.Curtains$rootViewsSpy$2.invoke(Curtains.kt:30)
at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81)
at curtains.Curtains.getRootViewsSpy(Unknown Source:2)
at curtains.Curtains.getOnRootViewsChangedListeners(Curtains.kt:68)
at leakcanary.RootViewWatcher.install(RootViewWatcher.kt:84)
at leakcanary.AppWatcher.manualInstall(AppWatcher.kt:113)
at com.bubenheimer.rucksack.leakcanary.LeakCanaryUtilKt.initLeakCanary(LeakCanaryUtil.kt:66)
at com.bubenheimer.rucksack.d.D.injection(Application.kt:164)
at com.bubenheimer.rucksack.d.D.onCreate(Application.kt:100)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1386)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7498)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2415)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8699)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:886)
I also see other WindowManagerGlobal exceptions triggered by LeakCanary. Perhaps the whole class was made unavailable.
@pyricau is there a standing request with Google to provide the APIs LeakCanary needs?
I see quite a lot more triggers for NonSdkApiUsedViolation now. I've had to filter all violations with "curtains.internal" and "leakcanary.ServiceWatcher" in the stacktraces to put an end to it.
Yep, the curtains ones are from: https://github.com/square/curtains
We can't fix that until Google provides proper APIs to listen to when new windows are added and removed.
Same with services, with need the equivalent of ActivityLifecycleCallbacks but for services.
Someone ask the AOSP team to fix this. In the meantime, Google Play reports can go to hell.
Thanks. Just FYI: I use StrictMode things in regular development, not just with Google Play reports.
Description
Google play pre launched report warns of non SDK api used violation by LeakCanary.
Steps to Reproduce
com.squareup.leakcanary:leakcanary-object-watcher-android:2.7
Expected behavior: No NonSdkApiUsedViolation warnings in the reports from LeakCanary
Version Information
Additional Information
Google play pre launch reports: Report 1
Report 2
Report 3