diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f861fb441e7ba..cb3afe4cb4170 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -319,6 +319,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; +import com.android.internal.os.TransferPipe; import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; @@ -342,6 +343,7 @@ import com.google.android.collect.Sets; import org.xmlpull.v1.XmlPullParserException; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -1142,6 +1144,76 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLetterboxUiController.dump(pw, prefix); } + static boolean dumpActivity(FileDescriptor fd, PrintWriter pw, int index, ActivityRecord r, + String prefix, String label, boolean complete, boolean brief, boolean client, + String dumpPackage, boolean needNL, Runnable header, Task lastTask) { + if (dumpPackage != null && !dumpPackage.equals(r.packageName)) { + return false; + } + + final boolean full = !brief && (complete || !r.isInHistory()); + if (needNL) { + pw.println(""); + } + if (header != null) { + header.run(); + } + + String innerPrefix = prefix + " "; + String[] args = new String[0]; + if (lastTask != r.getTask()) { + lastTask = r.getTask(); + pw.print(prefix); + pw.print(full ? "* " : " "); + pw.println(lastTask); + if (full) { + lastTask.dump(pw, prefix + " "); + } else if (complete) { + // Complete + brief == give a summary. Isn't that obvious?!? + if (lastTask.intent != null) { + pw.print(prefix); + pw.print(" "); + pw.println(lastTask.intent.toInsecureString()); + } + } + } + pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label); + pw.print(" #"); pw.print(index); pw.print(": "); + pw.println(r); + if (full) { + r.dump(pw, innerPrefix, true /* dumpAll */); + } else if (complete) { + // Complete + brief == give a summary. Isn't that obvious?!? + pw.print(innerPrefix); + pw.println(r.intent.toInsecureString()); + if (r.app != null) { + pw.print(innerPrefix); + pw.println(r.app); + } + } + if (client && r.attachedToProcess()) { + // flush anything that is already in the PrintWriter since the thread is going + // to write to the file descriptor directly + pw.flush(); + try { + TransferPipe tp = new TransferPipe(); + try { + r.app.getThread().dumpActivity( + tp.getWriteFd(), r.appToken, innerPrefix, args); + // Short timeout, since blocking here can deadlock with the application. + tp.go(fd, 2000); + } finally { + tp.kill(); + } + } catch (IOException e) { + pw.println(innerPrefix + "Failure while dumping the activity: " + e); + } catch (RemoteException e) { + pw.println(innerPrefix + "Got a RemoteException while dumping the activity"); + } + } + return true; + } + void setAppTimeTracker(AppTimeTracker att) { appTimeTracker = att; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 4d1488535e731..fde02ec804e7f 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -137,7 +137,6 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.ReferrerIntent; -import com.android.internal.os.TransferPipe; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.pooled.PooledConsumer; @@ -147,7 +146,6 @@ import com.android.server.am.UserState; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import java.io.FileDescriptor; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -1969,76 +1967,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list, String prefix, String label, boolean complete, boolean brief, boolean client, String dumpPackage, boolean needNL, Runnable header, Task lastTask) { - String innerPrefix = null; - String[] args = null; boolean printed = false; - for (int i=list.size()-1; i>=0; i--) { + for (int i = list.size() - 1; i >= 0; i--) { final ActivityRecord r = list.get(i); - if (dumpPackage != null && !dumpPackage.equals(r.packageName)) { - continue; - } - if (innerPrefix == null) { - innerPrefix = prefix + " "; - args = new String[0]; - } - printed = true; - final boolean full = !brief && (complete || !r.isInHistory()); - if (needNL) { - pw.println(""); - needNL = false; - } - if (header != null) { - header.run(); - header = null; - } - if (lastTask != r.getTask()) { - lastTask = r.getTask(); - pw.print(prefix); - pw.print(full ? "* " : " "); - pw.println(lastTask); - if (full) { - lastTask.dump(pw, prefix + " "); - } else if (complete) { - // Complete + brief == give a summary. Isn't that obvious?!? - if (lastTask.intent != null) { - pw.print(prefix); pw.print(" "); - pw.println(lastTask.intent.toInsecureString()); - } - } - } - pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label); - pw.print(" #"); pw.print(i); pw.print(": "); - pw.println(r); - if (full) { - r.dump(pw, innerPrefix, true /* dumpAll */); - } else if (complete) { - // Complete + brief == give a summary. Isn't that obvious?!? - pw.print(innerPrefix); pw.println(r.intent.toInsecureString()); - if (r.app != null) { - pw.print(innerPrefix); pw.println(r.app); - } - } - if (client && r.attachedToProcess()) { - // flush anything that is already in the PrintWriter since the thread is going - // to write to the file descriptor directly - pw.flush(); - try { - TransferPipe tp = new TransferPipe(); - try { - r.app.getThread().dumpActivity( - tp.getWriteFd(), r.appToken, innerPrefix, args); - // Short timeout, since blocking here can deadlock with the application. - tp.go(fd, 2000); - } finally { - tp.kill(); - } - } catch (IOException e) { - pw.println(innerPrefix + "Failure while dumping the activity: " + e); - } catch (RemoteException e) { - pw.println(innerPrefix + "Got a RemoteException while dumping the activity"); - } - needNL = true; - } + ActivityRecord.dumpActivity(fd, pw, i, r, prefix, label, complete, brief, + client, dumpPackage, needNL, header, lastTask); + lastTask = r.getTask(); + header = null; + needNL = client && r.attachedToProcess(); } return printed; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e97410d101153..0fb9739a609f7 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -99,7 +99,6 @@ import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP; import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS; -import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList; import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; @@ -221,7 +220,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -5594,89 +5592,33 @@ class Task extends TaskFragment { boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, String dumpPackage, final boolean needSep) { - Runnable headerPrinter = () -> { - if (needSep) { - pw.println(); - } - pw.println(" RootTask #" + getRootTaskId() - + ": type=" + activityTypeToString(getActivityType()) - + " mode=" + windowingModeToString(getWindowingMode())); - pw.println(" isSleeping=" + shouldSleepActivities()); - pw.println(" mBounds=" + getRequestedOverrideBounds()); - pw.println(" mCreatedByOrganizer=" + mCreatedByOrganizer); - }; - - boolean printed = false; - - if (dumpPackage == null) { - // If we are not filtering by package, we want to print absolutely everything, - // so always print the header even if there are no tasks/activities inside. - headerPrinter.run(); - headerPrinter = null; - printed = true; - } - - printed |= printThisActivity(pw, getTopPausingActivity(), dumpPackage, false, - " mPausingActivity: ", null); - printed |= printThisActivity(pw, getTopResumedActivity(), dumpPackage, false, - " mResumedActivity: ", null); - if (dumpAll) { - printed |= printThisActivity(pw, mLastPausedActivity, dumpPackage, false, - " mLastPausedActivity: ", null); - } - - printed |= dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, false, headerPrinter); - - return printed; + return dump(" ", fd, pw, dumpAll, dumpClient, dumpPackage, needSep, null /* header */); } - private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, - boolean dumpClient, String dumpPackage, boolean needSep, Runnable header) { - if (!hasChild()) { - return false; + @Override + void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) { + pw.print(prefix); pw.print("* "); pw.println(this); + pw.println(prefix + " mBounds=" + getRequestedOverrideBounds()); + pw.println(prefix + " mCreatedByOrganizer=" + mCreatedByOrganizer); + if (mLastNonFullscreenBounds != null) { + pw.print(prefix); pw.print(" mLastNonFullscreenBounds="); + pw.println(mLastNonFullscreenBounds); } - final AtomicBoolean printedHeader = new AtomicBoolean(false); - final AtomicBoolean printed = new AtomicBoolean(false); - forAllLeafTasks((task) -> { - final String prefix = " "; - Runnable headerPrinter = () -> { - printed.set(true); - if (!printedHeader.get()) { - if (needSep) { - pw.println(""); - } - if (header != null) { - header.run(); - } - printedHeader.set(true); - } - pw.print(prefix); pw.print("* "); pw.println(task); - pw.print(prefix); pw.print(" mBounds="); - pw.println(task.getRequestedOverrideBounds()); - pw.print(prefix); pw.print(" mMinWidth="); pw.print(task.mMinWidth); - pw.print(" mMinHeight="); pw.println(task.mMinHeight); - if (mLastNonFullscreenBounds != null) { - pw.print(prefix); - pw.print(" mLastNonFullscreenBounds="); - pw.println(task.mLastNonFullscreenBounds); - } - task.dump(pw, prefix + " "); - }; - if (dumpPackage == null) { - // If we are not filtering by package, we want to print absolutely everything, - // so always print the header even if there are no activities inside. - headerPrinter.run(); - headerPrinter = null; + if (dumpAll) { + printThisActivity(pw, mLastPausedActivity, dumpPackage, false, + prefix + " mLastPausedActivity: ", null); + } + if (isLeafTask()) { + pw.println(prefix + " isSleeping=" + shouldSleepActivities()); + printThisActivity(pw, getTopPausingActivity(), dumpPackage, false, + prefix + " topPausingActivity=", null); + printThisActivity(pw, getTopResumedActivity(), dumpPackage, false, + prefix + " topResumedActivity=", null); + if (mMinWidth != INVALID_MIN_SIZE || mMinHeight != INVALID_MIN_SIZE) { + pw.print(prefix); pw.print(" mMinWidth="); pw.print(mMinWidth); + pw.print(" mMinHeight="); pw.println(mMinHeight); } - final ArrayList activities = new ArrayList<>(); - // Add activities by traversing the hierarchy from bottom to top, since activities - // are dumped in reverse order in {@link ActivityTaskSupervisor#dumpHistoryList()}. - task.forAllActivities((Consumer) activities::add, - false /* traverseTopToBottom */); - dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient, - dumpPackage, false, headerPrinter, task); - }, true /* traverseTopToBottom */); - return printed.get(); + } } ArrayList getDumpActivitiesLocked(String name) { diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 80914a6345514..b83029dec61d9 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -76,6 +76,8 @@ import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -1885,4 +1887,46 @@ class TaskFragment extends WindowContainer { } return getTopChild().getActivityType(); } + + boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll, + boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) { + boolean printed = false; + Runnable headerPrinter = () -> { + if (needSep) { + pw.println(); + } + if (header != null) { + header.run(); + } + + dumpInner(prefix, pw, dumpAll, dumpPackage); + }; + + if (dumpPackage == null) { + // If we are not filtering by package, we want to print absolutely everything, + // so always print the header even if there are no tasks/activities inside. + headerPrinter.run(); + headerPrinter = null; + printed = true; + } + + for (int i = mChildren.size() - 1; i >= 0; --i) { + WindowContainer child = mChildren.get(i); + if (child.asTaskFragment() != null) { + printed |= child.asTaskFragment().dump(prefix + " ", fd, pw, dumpAll, + dumpClient, dumpPackage, needSep, headerPrinter); + } else if (child.asActivityRecord() != null) { + ActivityRecord.dumpActivity(fd, pw, i, child.asActivityRecord(), prefix + " ", + "Hist ", true, !dumpAll, dumpClient, dumpPackage, false, headerPrinter, + getTask()); + } + } + + return printed; + } + + void dumpInner(String prefix, PrintWriter pw, boolean dumpAll, String dumpPackage) { + pw.print(prefix); pw.print("* "); pw.println(this); + pw.println(prefix + " mBounds=" + getRequestedOverrideBounds()); + } }