From f43a33c5ea5adb8d100ab0c3da965bac33155cb8 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 27 Sep 2012 00:48:11 -0700 Subject: [PATCH] Work on issue #7232641: ISE crash when rotating phone in label list mode This doesn't fix the problem; I think it is an app problem. It does improve a bunch of the debugging to help better identify what is going on, and introduces some checks when adding a fragment to fail immediately if we are getting into a state when a fragment is going to be in the added list multiple times (which is pretty much guaranteed to lead to a failure at some point in the future). Change-Id: If3a8700763facd61c4505c6ff872ae66875afc8d --- core/java/android/app/BackStackRecord.java | 160 ++++++++++++++------- core/java/android/app/FragmentManager.java | 40 ++++-- 2 files changed, 138 insertions(+), 62 deletions(-) diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 96814b725463f..1b1d3418a5b11 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -20,6 +20,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; +import android.util.LogWriter; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -94,11 +95,12 @@ final class BackStackState implements Parcelable { public BackStackRecord instantiate(FragmentManagerImpl fm) { BackStackRecord bse = new BackStackRecord(fm); int pos = 0; + int num = 0; while (pos < mOps.length) { BackStackRecord.Op op = new BackStackRecord.Op(); op.cmd = mOps[pos++]; if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG, - "BSE " + bse + " set base fragment #" + mOps[pos]); + "Instantiate " + bse + " op #" + num + " base fragment #" + mOps[pos]); int findex = mOps[pos++]; if (findex >= 0) { Fragment f = fm.mActive.get(findex); @@ -115,12 +117,13 @@ final class BackStackState implements Parcelable { op.removed = new ArrayList(N); for (int i=0; i= 0) { + sb.append(" #"); + sb.append(mIndex); + } + if (mName != null) { + sb.append(" "); + sb.append(mName); + } + sb.append("}"); + return sb.toString(); + } + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - writer.print(prefix); writer.print("mName="); writer.print(mName); - writer.print(" mIndex="); writer.print(mIndex); - writer.print(" mCommitted="); writer.println(mCommitted); - if (mTransition != FragmentTransaction.TRANSIT_NONE) { - writer.print(prefix); writer.print("mTransition=#"); - writer.print(Integer.toHexString(mTransition)); - writer.print(" mTransitionStyle=#"); - writer.println(Integer.toHexString(mTransitionStyle)); - } - if (mEnterAnim != 0 || mExitAnim !=0) { - writer.print(prefix); writer.print("mEnterAnim=#"); - writer.print(Integer.toHexString(mEnterAnim)); - writer.print(" mExitAnim=#"); - writer.println(Integer.toHexString(mExitAnim)); - } - if (mPopEnterAnim != 0 || mPopExitAnim !=0) { - writer.print(prefix); writer.print("mPopEnterAnim=#"); - writer.print(Integer.toHexString(mPopEnterAnim)); - writer.print(" mPopExitAnim=#"); - writer.println(Integer.toHexString(mPopExitAnim)); - } - if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) { - writer.print(prefix); writer.print("mBreadCrumbTitleRes=#"); - writer.print(Integer.toHexString(mBreadCrumbTitleRes)); - writer.print(" mBreadCrumbTitleText="); - writer.println(mBreadCrumbTitleText); - } - if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) { - writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#"); - writer.print(Integer.toHexString(mBreadCrumbShortTitleRes)); - writer.print(" mBreadCrumbShortTitleText="); - writer.println(mBreadCrumbShortTitleText); + dump(prefix, writer, true); + } + + void dump(String prefix, PrintWriter writer, boolean full) { + if (full) { + writer.print(prefix); writer.print("mName="); writer.print(mName); + writer.print(" mIndex="); writer.print(mIndex); + writer.print(" mCommitted="); writer.println(mCommitted); + if (mTransition != FragmentTransaction.TRANSIT_NONE) { + writer.print(prefix); writer.print("mTransition=#"); + writer.print(Integer.toHexString(mTransition)); + writer.print(" mTransitionStyle=#"); + writer.println(Integer.toHexString(mTransitionStyle)); + } + if (mEnterAnim != 0 || mExitAnim !=0) { + writer.print(prefix); writer.print("mEnterAnim=#"); + writer.print(Integer.toHexString(mEnterAnim)); + writer.print(" mExitAnim=#"); + writer.println(Integer.toHexString(mExitAnim)); + } + if (mPopEnterAnim != 0 || mPopExitAnim !=0) { + writer.print(prefix); writer.print("mPopEnterAnim=#"); + writer.print(Integer.toHexString(mPopEnterAnim)); + writer.print(" mPopExitAnim=#"); + writer.println(Integer.toHexString(mPopExitAnim)); + } + if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) { + writer.print(prefix); writer.print("mBreadCrumbTitleRes=#"); + writer.print(Integer.toHexString(mBreadCrumbTitleRes)); + writer.print(" mBreadCrumbTitleText="); + writer.println(mBreadCrumbTitleText); + } + if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) { + writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#"); + writer.print(Integer.toHexString(mBreadCrumbShortTitleRes)); + writer.print(" mBreadCrumbShortTitleText="); + writer.println(mBreadCrumbShortTitleText); + } } if (mHead != null) { @@ -254,21 +280,34 @@ final class BackStackRecord extends FragmentTransaction implements Op op = mHead; int num = 0; while (op != null) { - writer.print(prefix); writer.print(" Op #"); writer.print(num); - writer.println(":"); - writer.print(innerPrefix); writer.print("cmd="); writer.print(op.cmd); - writer.print(" fragment="); writer.println(op.fragment); - if (op.enterAnim != 0 || op.exitAnim != 0) { - writer.print(prefix); writer.print("enterAnim=#"); - writer.print(Integer.toHexString(op.enterAnim)); - writer.print(" exitAnim=#"); - writer.println(Integer.toHexString(op.exitAnim)); + String cmdStr; + switch (op.cmd) { + case OP_NULL: cmdStr="NULL"; break; + case OP_ADD: cmdStr="ADD"; break; + case OP_REPLACE: cmdStr="REPLACE"; break; + case OP_REMOVE: cmdStr="REMOVE"; break; + case OP_HIDE: cmdStr="HIDE"; break; + case OP_SHOW: cmdStr="SHOW"; break; + case OP_DETACH: cmdStr="DETACH"; break; + case OP_ATTACH: cmdStr="ATTACH"; break; + default: cmdStr="cmd=" + op.cmd; break; } - if (op.popEnterAnim != 0 || op.popExitAnim != 0) { - writer.print(prefix); writer.print("popEnterAnim=#"); - writer.print(Integer.toHexString(op.popEnterAnim)); - writer.print(" popExitAnim=#"); - writer.println(Integer.toHexString(op.popExitAnim)); + writer.print(prefix); writer.print(" Op #"); writer.print(num); + writer.print(": "); writer.print(cmdStr); + writer.print(" "); writer.println(op.fragment); + if (full) { + if (op.enterAnim != 0 || op.exitAnim != 0) { + writer.print(innerPrefix); writer.print("enterAnim=#"); + writer.print(Integer.toHexString(op.enterAnim)); + writer.print(" exitAnim=#"); + writer.println(Integer.toHexString(op.exitAnim)); + } + if (op.popEnterAnim != 0 || op.popExitAnim != 0) { + writer.print(innerPrefix); writer.print("popEnterAnim=#"); + writer.print(Integer.toHexString(op.popEnterAnim)); + writer.print(" popExitAnim=#"); + writer.println(Integer.toHexString(op.popExitAnim)); + } } if (op.removed != null && op.removed.size() > 0) { for (int i=0; i(); } + if (mAdded.contains(fragment)) { + throw new IllegalStateException("Fragment already added: " + fragment); + } + if (DEBUG) Log.v(TAG, "add from attach: " + fragment); mAdded.add(fragment); fragment.mAdded = true; if (fragment.mHasMenu && fragment.mMenuVisible) { @@ -1717,19 +1734,18 @@ final class FragmentManagerImpl extends FragmentManager { FragmentState fs = fms.mActive[i]; if (fs != null) { Fragment f = fs.instantiate(mActivity, mParent); - if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f); + if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f); mActive.add(f); // Now that the fragment is instantiated (or came from being // retained above), clear mInstance in case we end up re-restoring // from this FragmentState again. fs.mInstance = null; } else { - if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)"); mActive.add(null); if (mAvailIndices == null) { mAvailIndices = new ArrayList(); } - if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i); + if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i); mAvailIndices.add(i); } } @@ -1760,7 +1776,10 @@ final class FragmentManagerImpl extends FragmentManager { "No instantiated fragment for index #" + fms.mAdded[i])); } f.mAdded = true; - if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f); + if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f); + if (mAdded.contains(f)) { + throw new IllegalStateException("Already added!"); + } mAdded.add(f); } } else { @@ -1772,8 +1791,13 @@ final class FragmentManagerImpl extends FragmentManager { mBackStack = new ArrayList(fms.mBackStack.length); for (int i=0; i= 0) { setBackStackIndex(bse.mIndex, bse);