Closed cadeyrn closed 3 years ago
Side note: I'd suggest using triple quotes when sharing traces (recommend admins edit the bug report).
HomeActivity is alive (not destroyed), it references its ViewModelStore which contains a BiometricViewModel. From that we can deduce that the lifecycle of BiometricViewModel is tied to the lifecycle of the activity. However BiometricViewModel has an mClientCallback field that references an anonymous class defined in SavedLoginsAuthFragment, and SavedLoginsAuthFragment is destroyed.
This likely means that SavedLoginsAuthFragment somehow registered a callback to BiometricViewModel but didn't clear it when destroyed.
The leaking object, biometricPromptCallback
, an anonymous implemention of BiometricPrompt.AuthenticationCallback
, is defined here
It's registered here:
biometricPrompt = BiometricPrompt(this, executor, biometricPromptCallback)
Looking at the Android X BiometricPrompt
sources, the callback is set in BiometricPrompt.init()
which is called from the BiometricPrompt
constructor and never unset.
private void init(
@Nullable FragmentActivity activity,
@Nullable FragmentManager fragmentManager,
@Nullable Executor executor,
@NonNull AuthenticationCallback callback) {
mClientFragmentManager = fragmentManager;
if (activity != null) {
final BiometricViewModel viewModel =
new ViewModelProvider(activity).get(BiometricViewModel.class);
if (executor != null) {
viewModel.setClientExecutor(executor);
}
viewModel.setClientCallback(callback);
}
}
So, as it stands, there is no way to clear the callback, and the view model is always created from an activity, so the callback always has the lifecycle of the activity. This looks like a design issue with how Android X BiometricPrompt work. Until Google fixes it, the AuthenticationCallback implementation needs to stop being an anonymous class and it needs to have a nullable reference to the fragment.
/cc @mcomella
Steps to reproduce
Settings > Logins and passwords > Saved logins > unlock
Expected behavior
No leak.
Actual behavior
Device information
┆Issue is synchronized with this Jira Task