I'm using this code to DismissKeyguard after activity finished LeakCanary displays below message. how to prevent these leak.
keyguardManager = (KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE);
if(Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true);
setTurnScreenOn(true);
if (keyguardManager != null) {
keyguardManager.requestDismissKeyguard(this, null);
}
}
LeakCanary showing
GC Root: Global variable in native code
│
├─ android.app.KeyguardManager$1 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of com.android.internal.policy.IKeyguardDismissCallback$Stub
│ ↓ KeyguardManager$1.val$activity
│ ~~~~~~~~~~~~
╰→ com.example.myapplication.MainActivity instance
Leaking: YES (ObjectWatcher was watching this because com.example.myapplication.MainActivity received Activity#onDestroy() callback and Activity#mDestroyed is true)
The leaktrace indicates that there is a global variable in native code that keeps a reference to an instance of KeyguardManager$1
which implements com.android.internal.policy.IKeyguardDismissCallback$Stub
, and KeyguardManager$1
itself holds a reference to the activity.
The sources for the implementation of KeyguardManager#requestDismissKeyguard can be found here: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/KeyguardManager.java#574 :
ActivityTaskManager.getService().dismissKeyguard(
activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
@Override
public void onDismissError() throws RemoteException {
if (callback != null && !activity.isDestroyed()) {
activity.mHandler.post(callback::onDismissError);
}
}
@Override
public void onDismissSucceeded() throws RemoteException {
if (callback != null && !activity.isDestroyed()) {
activity.mHandler.post(callback::onDismissSucceeded);
}
}
@Override
public void onDismissCancelled() throws RemoteException {
if (callback != null && !activity.isDestroyed()) {
activity.mHandler.post(callback::onDismissCancelled);
}
}
}, message);
That's an Inter Process Call to the ActivityTaskManager service process. The stubs that is set to receive a result when the ActivityTaskManager service process calls back holds the reference to the activity. Unfortunately, native stubs tend to be held in memory longer than expected because they're dependent on the GC running in the other process.
This is clearly a bug in the Android framework. You should file a bug to the Android framework and provide a sample app that reproduces it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With