I checked the Android source code, and found the following method.
(core/java/android/view/WindowManagerGlobal.java
)
It seems that when who != null
the window/view is leaked. Can anyone explain what's going on behind this?
public void closeAll(IBinder token, String who, String what) {
synchronized (mLock) {
int count = mViews.size();
//Log.i("foo", "Closing all windows of " + token);
for (int i = 0; i < count; i++) {
//Log.i("foo", "@ " + i + " token " + mParams[i].token
// + " view " + mRoots[i].getView());
if (token == null || mParams.get(i).token == token) {
ViewRootImpl root = mRoots.get(i);
//Log.i("foo", "Force closing " + root);
if (who != null) {
WindowLeaked leak = new WindowLeaked(
what + " " + who + " has leaked window "
+ root.getView() + " that was originally added here");
leak.setStackTrace(root.getLocation().getStackTrace());
Log.e(TAG, "", leak);
}
removeViewLocked(i, false);
}
}
}
}
I checked the source... I'm not totally sure about it but her goes my understanding...
"who" argument is Activity Name only
Checking closeAll()
calling methods, you can see that who
is just the Activity class name that was destroyed and left one window behind:
WindowManagerGlobal.getInstance().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
closeAll() is called if leaked occurred
It seems that WindowManagerGlobal.closeAll()
is called when the Windows has leaked already. So, who != null
it just a check to ensure that String
is not NULL
.
If not null, a WindowLeaked
is created and log is printed. WindowLeaked
is an Class that extends AndroidRuntimeException
final class WindowLeaked extends AndroidRuntimeException {
public WindowLeaked(String msg) {
super(msg);
}
}
Most important is the fact that if WindowManagerGlobal.closeAll()
is called, it means that the Windows has leaked already.
CloseAll() calling method
In View.java
, we can see that WindowManagerGlobal.closeAll()
is called when a leacked is detected:
ActivityThread.java
private void handleDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
...
IBinder wtoken = v.getWindowToken();
...
if (wtoken != null && r.mPendingRemoveWindow == null) {
WindowManagerGlobal.getInstance().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
}
In the code above, we can see that WindowManagerGlobal.closeAll()
is fired when an inconsistency is found:
wtoken != null
wtoken
shows that View
has an mAttachInfo.mWindowToken
information. In other words, it is still held by some window.r.mPendingRemoveWindow == null
there's no pending view to be removed.So, it is inconsistent. One view is attached (has an mAttachInfo
yet) but I've already remove all pending windows (mPendingRemoveWindow
is null)... So, that view has leaked.
Hope I could help you Regards
REF: