diff options
7 files changed, 63 insertions, 24 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3d088ff9e5c3..394edf107737 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -166,9 +166,9 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.InetAddress; import java.text.DateFormat; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -222,7 +222,7 @@ public final class ActivityThread extends ClientTransactionHandler { private static final boolean REPORT_TO_ACTIVITY = true; // Maximum number of recent tokens to maintain for debugging purposes - private static final int MAX_RECENT_TOKENS = 10; + private static final int MAX_DESTROYED_ACTIVITIES = 10; /** * Denotes an invalid sequence number corresponding to a process state change. @@ -256,7 +256,7 @@ public final class ActivityThread extends ClientTransactionHandler { final H mH = new H(); final Executor mExecutor = new HandlerExecutor(mH); final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>(); - final ArrayDeque<Integer> mRecentTokens = new ArrayDeque<>(); + final ArrayList<DestroyedActivityInfo> mRecentDestroyedActivities = new ArrayList<>(); // List of new activities (via ActivityRecord.nextIdle) that should // be reported when next we idle. @@ -339,6 +339,26 @@ public final class ActivityThread extends ClientTransactionHandler { } } + /** + * TODO(b/71506345): Remove this once bug is resolved. + */ + private static final class DestroyedActivityInfo { + private final Integer mToken; + private final String mReason; + private final long mTime; + + DestroyedActivityInfo(Integer token, String reason) { + mToken = token; + mReason = reason; + mTime = System.currentTimeMillis(); + } + + void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "[token:" + mToken + " | time:" + mTime + " | reason:" + mReason + + "]"); + } + } + // The lock of mProviderMap protects the following variables. final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey, ProviderClientRecord>(); @@ -2182,14 +2202,28 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + "mActivities:"); + pw.println(prefix + "Activities:"); - for (ArrayMap.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) { - pw.println(prefix + " [token:" + entry.getKey().hashCode() + " record:" - + entry.getValue().toString() + "]"); + if (!mActivities.isEmpty()) { + final Iterator<Map.Entry<IBinder, ActivityClientRecord>> activitiesIterator = + mActivities.entrySet().iterator(); + + while (activitiesIterator.hasNext()) { + final ArrayMap.Entry<IBinder, ActivityClientRecord> entry = + activitiesIterator.next(); + pw.println(prefix + " [token:" + entry.getKey().hashCode() + " record:" + + entry.getValue().toString() + "]"); + } } - pw.println(prefix + "mRecentTokens:" + mRecentTokens); + if (!mRecentDestroyedActivities.isEmpty()) { + pw.println(prefix + "Recent destroyed activities:"); + for (int i = 0, size = mRecentDestroyedActivities.size(); i < size; i++) { + final DestroyedActivityInfo info = mRecentDestroyedActivities.get(i); + pw.print(prefix); + info.dump(pw, " "); + } + } } public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin, @@ -2876,11 +2910,6 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_CREATE); mActivities.put(r.token, r); - mRecentTokens.push(r.token.hashCode()); - - if (mRecentTokens.size() > MAX_RECENT_TOKENS) { - mRecentTokens.removeLast(); - } } catch (SuperNotCalledException e) { throw e; @@ -4453,7 +4482,7 @@ public final class ActivityThread extends ClientTransactionHandler { /** Core implementation of activity destroy call. */ ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, - int configChanges, boolean getNonConfigInstance) { + int configChanges, boolean getNonConfigInstance, String reason) { ActivityClientRecord r = mActivities.get(token); Class<? extends Activity> activityClass = null; if (localLOGV) Slog.v(TAG, "Performing finish of " + r); @@ -4505,6 +4534,12 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_DESTROY); } mActivities.remove(token); + mRecentDestroyedActivities.add(0, new DestroyedActivityInfo(token.hashCode(), reason)); + + final int recentDestroyedActivitiesSize = mRecentDestroyedActivities.size(); + if (recentDestroyedActivitiesSize > MAX_DESTROYED_ACTIVITIES) { + mRecentDestroyedActivities.remove(recentDestroyedActivitiesSize - 1); + } StrictMode.decrementExpectedActivityCount(activityClass); return r; } @@ -4516,9 +4551,9 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, - boolean getNonConfigInstance) { + boolean getNonConfigInstance, String reason) { ActivityClientRecord r = performDestroyActivity(token, finishing, - configChanges, getNonConfigInstance); + configChanges, getNonConfigInstance, reason); if (r != null) { cleanUpPendingRemoveWindows(r, finishing); WindowManager wm = r.activity.getWindowManager(); @@ -4780,7 +4815,7 @@ public final class ActivityThread extends ClientTransactionHandler { callActivityOnStop(r, true /* saveState */, "handleRelaunchActivity"); } - handleDestroyActivity(r.token, false, configChanges, true); + handleDestroyActivity(r.token, false, configChanges, true, "handleRelaunchActivity"); r.activity = null; r.window = null; diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 5b61fdf8677f..d061a9824f65 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -60,7 +60,7 @@ public abstract class ClientTransactionHandler { /** Destroy the activity. */ public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, - boolean getNonConfigInstance); + boolean getNonConfigInstance, String reason); /** Pause the activity. */ public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 1d3459534f0c..e297719f9e4c 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -380,7 +380,7 @@ public class LocalActivityManager { } if (localLOGV) Log.v(TAG, r.id + ": destroying"); mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */, - false /* getNonConfigInstance */); + false /* getNonConfigInstance */, "LocalActivityManager::performDestroy"); r.activity = null; r.window = null; if (finish) { @@ -645,7 +645,7 @@ public class LocalActivityManager { LocalActivityRecord r = mActivityArray.get(i); if (localLOGV) Log.v(TAG, r.id + ": destroying"); mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */, - false /* getNonConfigInstance */); + false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy"); } mActivities.clear(); mActivityArray.clear(); diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java index cbcf6c750fed..48a79f79dae1 100644 --- a/core/java/android/app/servertransaction/DestroyActivityItem.java +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -37,7 +37,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem { PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); client.handleDestroyActivity(token, mFinished, mConfigChanges, - false /* getNonConfigInstance */); + false /* getNonConfigInstance */, getDescription()); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 78b393a831f9..840fef80a5ff 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -194,7 +194,9 @@ public class TransactionExecutor { break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, - 0 /* configChanges */, false /* getNonConfigInstance */); + 0 /* configChanges */, false /* getNonConfigInstance */, + "performLifecycleSequence. cycling to:" + + mLifecycleSequence.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r.token, false /* start */); diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index cae0d2bc5dd9..2ad23ec856f8 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -375,7 +375,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } String getLifecycleDescription(String reason) { - return "packageName=" + packageName + ", state=" + state + ", reason=" + reason; + return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state + + ", reason=" + reason + ", time=" + System.currentTimeMillis(); } void dump(PrintWriter pw, String prefix) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index ab2dc36d66d0..ae74958fdc21 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -4214,7 +4214,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r); mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken, DestroyActivityItem.obtain(r.finishing, r.configChangeFlags) - .setDescription(r.getLifecycleDescription("destroyActivityLocked"))); + .setDescription( + r.getLifecycleDescription("destroyActivityLocked:" + reason))); } catch (Exception e) { // We can just ignore exceptions here... if the process // has crashed, our death notification will clean things |