Fixed
Status Update
Comments
dm...@gmail.com <dm...@gmail.com> #2
Hi Ed, Thank you so much for these suggestions. I've been reviewing them and merging them in. Hopefully it should be live. I've included a thank you note too in the article.
[Deleted User] <[Deleted User]> #3
Great! Thanks a lot, I'll look for the live updates soon!
[Deleted User] <[Deleted User]> #4
Then there's also this leak on Android 10 but I'm not sure if you can fix it without changing the platform code.
ApplicationLeak(className=androidx.biometric.BiometricFragment, leakTrace=
┬
├─ android.hardware.biometrics.BiometricPrompt$1
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.IBiometricServiceReceiver$Stub
│ GC Root: Global variable in native code
│ ↓ BiometricPrompt$1.this$0
│ ~~~~~~
├─ android.hardware.biometrics.BiometricPrompt
│ Leaking: UNKNOWN
│ ↓ BiometricPrompt.mAuthenticationCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ androidx.biometric.BiometricFragment$2
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.BiometricPrompt$AuthenticationCallback
│ ↓ BiometricFragment$2.this$0
│ ~~~~~~
╰→ androidx.biometric.BiometricFragment
Leaking: YES (Fragment#mFragmentManager is null and ObjectWatcher was watching this)
key = e83e567c-4012-4201-9a4b-33fc2a8fd98d
watchDurationMillis = 42513
retainedDurationMillis = 8077
, retainedHeapByteSize=1588)
ApplicationLeak(className=androidx.biometric.BiometricFragment, leakTrace=
┬
├─ android.hardware.biometrics.BiometricPrompt$1
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.IBiometricServiceReceiver$Stub
│ GC Root: Global variable in native code
│ ↓ BiometricPrompt$1.this$0
│ ~~~~~~
├─ android.hardware.biometrics.BiometricPrompt
│ Leaking: UNKNOWN
│ ↓ BiometricPrompt.mAuthenticationCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ androidx.biometric.BiometricFragment$2
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.BiometricPrompt$AuthenticationCallback
│ ↓ BiometricFragment$2.this$0
│ ~~~~~~
╰→ androidx.biometric.BiometricFragment
Leaking: YES (Fragment#mFragmentManager is null and ObjectWatcher was watching this)
key = e83e567c-4012-4201-9a4b-33fc2a8fd98d
watchDurationMillis = 42513
retainedDurationMillis = 8077
, retainedHeapByteSize=1588)
mo...@gmail.com <mo...@gmail.com> #5
Hello I found 2 other leaks related to BiometricFragment: calling finish() after the activity has called biometricprompt.authenticate() causes the Activity and BiometricFragment to leak. These leaks happen before or after the user has successfully authenticated.
Notes:
Fingerprints enrolled
Artifact used: androidx.biometric:biometric:1.0.1
Emulator: Pixel 3A XL API 29 (although the leaks appear on all other devices too).
Here is a link to the StackOverflow question I posted with code:
https://stackoverflow.com/questions/59833360/biometricprompt-biometricfragment-and-activity-memory-leak
Notes:
Fingerprints enrolled
Artifact used: androidx.biometric:biometric:1.0.1
Emulator: Pixel 3A XL API 29 (although the leaks appear on all other devices too).
Here is a link to the StackOverflow question I posted with code:
cu...@google.com <cu...@google.com>
ap...@google.com <ap...@google.com> #6
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 8e4b7413db92c31d302f19c6f78db181ba4c97ff
Author: Curtis Belmonte <curtislb@google.com>
Date: Mon Feb 03 14:01:31 2020
Remove context reference from fingerprint fragments
Having FingerprintDialogFragment and FingerprintHelperFragment retain a
Context reference can cause us to leak the Context. This commit updates
both fragments to ditch the mContext field and instead call getContext
as needed.
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Test: Manually, using the support demo app on Pixel 3, API 27
Bug: 144919472
Change-Id: I79d1704407456c73b5be73a1408ff748b9f03005
M biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
M biometric/biometric/src/main/java/androidx/biometric/FingerprintHelperFragment.java
https://android-review.googlesource.com/1225322
Branch: androidx-master-dev
commit 8e4b7413db92c31d302f19c6f78db181ba4c97ff
Author: Curtis Belmonte <curtislb@google.com>
Date: Mon Feb 03 14:01:31 2020
Remove context reference from fingerprint fragments
Having FingerprintDialogFragment and FingerprintHelperFragment retain a
Context reference can cause us to leak the Context. This commit updates
both fragments to ditch the mContext field and instead call getContext
as needed.
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Test: Manually, using the support demo app on Pixel 3, API 27
Bug: 144919472
Change-Id: I79d1704407456c73b5be73a1408ff748b9f03005
M biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
M biometric/biometric/src/main/java/androidx/biometric/FingerprintHelperFragment.java
ap...@google.com <ap...@google.com> #7
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 688b10235137dd8123a5faddb75441c4500655a9
Author: Curtis Belmonte <curtislb@google.com>
Date: Mon Feb 03 11:32:29 2020
Make fingerprint dialog handler static to avoid leaks
Updates the Handler class within FingerprintDialogFragment to be static
with a WeakReference to the fragment, in order to avoid potentially
leaking the fragment instance.
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Test: Manually with biometric demo app on Pixel 3, API 27
Bug: 144919472
Change-Id: I715db3c0b4a606fe10da7c984d8f8fcf4e226d0a
M biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java
M biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
https://android-review.googlesource.com/1225259
Branch: androidx-master-dev
commit 688b10235137dd8123a5faddb75441c4500655a9
Author: Curtis Belmonte <curtislb@google.com>
Date: Mon Feb 03 11:32:29 2020
Make fingerprint dialog handler static to avoid leaks
Updates the Handler class within FingerprintDialogFragment to be static
with a WeakReference to the fragment, in order to avoid potentially
leaking the fragment instance.
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Test: Manually with biometric demo app on Pixel 3, API 27
Bug: 144919472
Change-Id: I715db3c0b4a606fe10da7c984d8f8fcf4e226d0a
M biometric/biometric/src/main/java/androidx/biometric/BiometricPrompt.java
M biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
dk...@fundrise.com <dk...@fundrise.com> #8
====================================
HEAP ANALYSIS RESULT
====================================
2 APPLICATION LEAKS
References underlined with "~~~" are likely causes.
Learn more athttps://squ.re/leaks .
660848 bytes retained by leaking objects
Signature: e7edf85aa4445657a23a32aa6a189a8194a
┬───
│ GC Root: Global variable in native code
│
├─ android.hardware.fingerprint.FingerprintManager$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.fingerprint.IFingerprintServiceReceiver$Stub
│ ↓ FingerprintManager$2.this$0
│ ~~~~~~
├─ android.hardware.fingerprint.FingerprintManager instance
│ Leaking: UNKNOWN
│ ↓ FingerprintManager.mContext
│ ~~~~~~~~
╰→ ....SplashScreenActivity instance
Leaking: YES (ObjectWatcher was watching this because ....SplashScreenActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
key = 5baec59c-9597-4595-b669-8266062b4afb
watchDurationMillis = 5289
retainedDurationMillis = 280
1877 bytes retained by leaking objects
Signature: 6ada7743617e3ee898c9f63a9cfedd67f4758171
┬───
│ GC Root: Global variable in native code
│
├─ android.hardware.fingerprint.FingerprintManager$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.fingerprint.IFingerprintServiceReceiver$Stub
│ ↓ FingerprintManager$2.this$0
│ ~~~~~~
├─ android.hardware.fingerprint.FingerprintManager instance
│ Leaking: UNKNOWN
│ ↓ FingerprintManager.mAuthenticationCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ androidx.biometric.BiometricFragment$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.BiometricPrompt$AuthenticationCallback
│ ↓ BiometricFragment$2.this$0
│ ~~~~~~
╰→ androidx.biometric.BiometricFragment instance
Leaking: YES (ObjectWatcher was watching this because androidx.biometric.BiometricFragment received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
key = 5ed5df48-d1ed-4365-a8fc-a638ec29ac43
watchDurationMillis = 5288
retainedDurationMillis = 279
key = 61f26804-4b2a-4eef-b4ea-ac06ed762f35
====================================
HEAP ANALYSIS RESULT
====================================
2 APPLICATION LEAKS
References underlined with "~~~" are likely causes.
Learn more at
660848 bytes retained by leaking objects
Signature: e7edf85aa4445657a23a32aa6a189a8194a
┬───
│ GC Root: Global variable in native code
│
├─ android.hardware.fingerprint.FingerprintManager$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.fingerprint.IFingerprintServiceReceiver$Stub
│ ↓ FingerprintManager$2.this$0
│ ~~~~~~
├─ android.hardware.fingerprint.FingerprintManager instance
│ Leaking: UNKNOWN
│ ↓ FingerprintManager.mContext
│ ~~~~~~~~
╰→ ....SplashScreenActivity instance
Leaking: YES (ObjectWatcher was watching this because ....SplashScreenActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
key = 5baec59c-9597-4595-b669-8266062b4afb
watchDurationMillis = 5289
retainedDurationMillis = 280
1877 bytes retained by leaking objects
Signature: 6ada7743617e3ee898c9f63a9cfedd67f4758171
┬───
│ GC Root: Global variable in native code
│
├─ android.hardware.fingerprint.FingerprintManager$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.fingerprint.IFingerprintServiceReceiver$Stub
│ ↓ FingerprintManager$2.this$0
│ ~~~~~~
├─ android.hardware.fingerprint.FingerprintManager instance
│ Leaking: UNKNOWN
│ ↓ FingerprintManager.mAuthenticationCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ androidx.biometric.BiometricFragment$2 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.hardware.biometrics.BiometricPrompt$AuthenticationCallback
│ ↓ BiometricFragment$2.this$0
│ ~~~~~~
╰→ androidx.biometric.BiometricFragment instance
Leaking: YES (ObjectWatcher was watching this because androidx.biometric.BiometricFragment received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
key = 5ed5df48-d1ed-4365-a8fc-a638ec29ac43
watchDurationMillis = 5288
retainedDurationMillis = 279
key = 61f26804-4b2a-4eef-b4ea-ac06ed762f35
====================================
lo...@gmail.com <lo...@gmail.com> #9
I see code merged. When will it release and which version will have fixed code :o
ap...@google.com <ap...@google.com> #10
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 6e031f7cad58675cf1522260727e3894122f9107
Author: Curtis Belmonte <curtislb@google.com>
Date: Thu Jul 30 13:33:30 2020
Fix memory leaks in androidx.biometric library
Addresses several memory leaks reported by LeakCanary for the following
classes:
- The BiometricFragment internal library class
- The BiometricViewModel internal library class
- The host activity from the client application
Test: Biometric integration test app on API 27-30
Test: LeakCanary e2e test added in a follow-up commit
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Bug: 143929280
Bug: 144919472
Bug: 149344544
Change-Id: Ia055ffd6b97e3f3b0ba85c2cd665c94fe467bab6
M biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
M biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java
https://android-review.googlesource.com/1382564
Branch: androidx-master-dev
commit 6e031f7cad58675cf1522260727e3894122f9107
Author: Curtis Belmonte <curtislb@google.com>
Date: Thu Jul 30 13:33:30 2020
Fix memory leaks in androidx.biometric library
Addresses several memory leaks reported by LeakCanary for the following
classes:
- The BiometricFragment internal library class
- The BiometricViewModel internal library class
- The host activity from the client application
Test: Biometric integration test app on API 27-30
Test: LeakCanary e2e test added in a follow-up commit
Test: ./gradlew biometric:biometric:test
Test: ./gradlew biometric:biometric:connectedAndroidTest
Bug: 143929280
Bug: 144919472
Bug: 149344544
Change-Id: Ia055ffd6b97e3f3b0ba85c2cd665c94fe467bab6
M biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
M biometric/biometric/src/main/java/androidx/biometric/BiometricViewModel.java
cu...@google.com <cu...@google.com> #11
This should be addressed as of version 1.1.0-alpha02. We've also added e2e tests with LeakCanary to avoid future regressions.
mi...@gmail.com <mi...@gmail.com> #12
I can confirm that this is fixed on 1.1.0-alpha02
na...@gmail.com <na...@gmail.com> #13
I still have this error in 1.1.0-alpha3 version
Description
Devices/Android versions reproduced on:
Emulator 25 API, X86 (behaves the same on all versions)
Android version 7.1.1
Code:
Steps:
Have a stored fingerprint on the device.
Launch the example app, see the fingerprint dialog.
Rotate the screen.
See 2 leaks in LeakCanary.
Frequency:
Each time on rotation.
Leak #1:
androidx.biometric.DeviceCredentialHandlerBridge
│ Leaking: NO (a class is never leaking)
│ GC Root: System class
│ ↓ static DeviceCredentialHandlerBridge.sInstance
│ ~~~~~~~~~
├─ androidx.biometric.DeviceCredentialHandlerBridge
│ Leaking: UNKNOWN
│ ↓ DeviceCredentialHandlerBridge.mAuthenticationCallback
│ ~~~~~~~~~~~~~~~~~~~~~~~
├─ com.eightbitlab.biometricbugs.MainActivity$onCreate$1
│ Leaking: UNKNOWN
│ Anonymous subclass of androidx.biometric.BiometricPrompt$AuthenticationCallback
│ ↓ MainActivity$onCreate$1.this$0
Leak #2:
┬
├─ androidx.biometric.DeviceCredentialHandlerBridge
│ Leaking: NO (a class is never leaking)
│ GC Root: System class
│ ↓ static DeviceCredentialHandlerBridge.sInstance
│ ~~~~~~~~~
├─ androidx.biometric.DeviceCredentialHandlerBridge
│ Leaking: UNKNOWN
│ ↓ DeviceCredentialHandlerBridge.mOnClickListener
│ ~~~~~~~~~~~~~~~~
├─ androidx.biometric.BiometricPrompt$1
│ Leaking: UNKNOWN
│ Anonymous class implementing android.content.DialogInterface$OnClickListener
│ ↓ BiometricPrompt$1.this$0
│ ~~~~~~
├─ androidx.biometric.BiometricPrompt
│ Leaking: UNKNOWN
│ ↓ BiometricPrompt.mFingerprintDialogFragment
│ ~~~~~~~~~~~~~~~~~~~~~~~~~~
╰→ androidx.biometric.FingerprintDialogFragment
Leaking: YES (Fragment#mFragmentManager is null and ObjectWatcher was watching this)
key = 42dbc3ac-2321-40a0-bfd4-4f74044ca615
watchDurationMillis = 2137697
retainedDurationMillis = 2132696
Another leak, that is not reported by LeakCanary right now is a non-static child of Handler in FingerprintDialogFragment.
Lint gives you a warning:
This Handler class should be static or leaks might occur.