diff --git a/services/core/java/com/android/server/Dumpable.java b/services/core/java/com/android/server/Dumpable.java new file mode 100644 index 0000000000000..d2bd66f59b625 --- /dev/null +++ b/services/core/java/com/android/server/Dumpable.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.util.IndentingPrintWriter; + +/** + * Interface used to dump {@link SystemServer} state that is not associated with any service. + */ +public interface Dumpable { + + /** + * Dumps the state. + */ + void dump(@NonNull IndentingPrintWriter pw, @Nullable String[] args); + + /** + * Gets the name of the dumpable. + * + *
If not overridden, will return the simple class name.
+ */
+ default String getDumpableName() {
+ return Dumpable.this.getClass().getSimpleName();
+ }
+}
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index c0611374679b6..c23f1cab0614e 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -19,6 +19,7 @@ package com.android.server;
import android.annotation.NonNull;
import android.os.Build;
import android.os.Process;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -44,7 +45,7 @@ import java.util.concurrent.TimeUnit;
*
* @hide
*/
-public class SystemServerInitThreadPool {
+public final class SystemServerInitThreadPool implements Dumpable {
private static final String TAG = SystemServerInitThreadPool.class.getSimpleName();
private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000;
private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE;
@@ -53,6 +54,7 @@ public class SystemServerInitThreadPool {
@GuardedBy("LOCK")
private static SystemServerInitThreadPool sInstance;
+ private final int mSize; // used by dump() only
private final ExecutorService mService;
@GuardedBy("mPendingTasks")
@@ -62,9 +64,9 @@ public class SystemServerInitThreadPool {
private boolean mShutDown;
private SystemServerInitThreadPool() {
- final int size = Runtime.getRuntime().availableProcessors();
- Slog.i(TAG, "Creating instance with " + size + " threads");
- mService = ConcurrentUtils.newFixedThreadPool(size,
+ mSize = Runtime.getRuntime().availableProcessors();
+ Slog.i(TAG, "Creating instance with " + mSize + " threads");
+ mService = ConcurrentUtils.newFixedThreadPool(mSize,
"system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
}
@@ -123,11 +125,13 @@ public class SystemServerInitThreadPool {
*
* @throws IllegalStateException if it has been started already without being shut down yet.
*/
- static void start() {
+ static SystemServerInitThreadPool start() {
+ SystemServerInitThreadPool instance;
synchronized (LOCK) {
Preconditions.checkState(sInstance == null, TAG + " already started");
- sInstance = new SystemServerInitThreadPool();
+ instance = sInstance = new SystemServerInitThreadPool();
}
+ return instance;
}
/**
@@ -190,4 +194,22 @@ public class SystemServerInitThreadPool {
ActivityManagerService.dumpStackTraces(pids, null, null,
Watchdog.getInterestingNativePids(), null);
}
+
+ @Override
+ public void dump(IndentingPrintWriter pw, String[] args) {
+ synchronized (LOCK) {
+ pw.printf("has instance: %b\n", (sInstance != null));
+ }
+ pw.printf("number of threads: %d\n", mSize);
+ pw.printf("service: %s\n", mService);
+ synchronized (mPendingTasks) {
+ pw.printf("is shutdown: %b\n", mShutDown);
+ final int pendingTasks = mPendingTasks.size();
+ if (pendingTasks == 0) {
+ pw.println("no pending tasks");
+ } else {
+ pw.printf("%d pending tasks: %s\n", pendingTasks, mPendingTasks);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index 84d01ec3598de..6c81de6af402a 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -200,21 +200,21 @@ public abstract class SystemService {
/**
* @hide
*/
- public void dump(@NonNull StringBuilder builder) {
- builder.append(getUserIdentifier());
+ public void dump(@NonNull PrintWriter pw) {
+ pw.print(getUserIdentifier());
if (!isFull() && !isManagedProfile()) return;
- builder.append('(');
+ pw.print('(');
boolean addComma = false;
if (isFull()) {
- builder.append("full");
+ pw.print("full");
}
if (isManagedProfile()) {
- if (addComma) builder.append(',');
- builder.append("mp");
+ if (addComma) pw.print(',');
+ pw.print("mp");
}
- builder.append(')');
+ pw.print(')');
}
}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index ff2661b19b484..71a18218110e9 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -27,6 +27,7 @@ import android.os.Trace;
import android.os.UserManagerInternal;
import android.util.ArrayMap;
import android.util.EventLog;
+import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
@@ -49,7 +50,7 @@ import java.util.ArrayList;
*
* {@hide}
*/
-public final class SystemServiceManager {
+public final class SystemServiceManager implements Dumpable {
private static final String TAG = SystemServiceManager.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int SERVICE_CALL_WARN_TIME_MS = 50;
@@ -489,31 +490,39 @@ public final class SystemServiceManager {
return sSystemDir;
}
- /**
- * Outputs the state of this manager to the System log.
- */
- public void dump() {
- StringBuilder builder = new StringBuilder();
- builder.append("Current phase: ").append(mCurrentPhase).append('\n');
- builder.append("Services:\n");
- final int startedLen = mServices.size();
- for (int i = 0; i < startedLen; i++) {
- final SystemService service = mServices.get(i);
- builder.append("\t")
- .append(service.getClass().getSimpleName())
- .append("\n");
- }
+ @Override
+ public void dump(IndentingPrintWriter pw, String[] args) {
+ pw.printf("Current phase: %d\n", mCurrentPhase);
synchronized (mTargetUsers) {
- builder.append("Current user: ").append(mCurrentUser).append('\n');
- builder.append("Target users: ");
- final int targetUsersSize = mTargetUsers.size();
- for (int i = 0; i < targetUsersSize; i++) {
- mTargetUsers.valueAt(i).dump(builder);
- if (i != targetUsersSize - 1) builder.append(',');
+ if (mCurrentUser != null) {
+ pw.print("Current user: "); mCurrentUser.dump(pw); pw.println();
+ } else {
+ pw.println("Current user not set!");
}
- builder.append('\n');
- }
- Slog.e(TAG, builder.toString());
+ final int targetUsersSize = mTargetUsers.size();
+ if (targetUsersSize > 0) {
+ pw.printf("%d target users: ", targetUsersSize);
+ for (int i = 0; i < targetUsersSize; i++) {
+ mTargetUsers.valueAt(i).dump(pw);
+ if (i != targetUsersSize - 1) pw.print(", ");
+ }
+ pw.println();
+ } else {
+ pw.println("No target users");
+ }
+ }
+ final int startedLen = mServices.size();
+ if (startedLen > 0) {
+ pw.printf("%d started services:\n", startedLen);
+ pw.increaseIndent();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ pw.println(service.getClass().getCanonicalName());
+ }
+ pw.decreaseIndent();
+ } else {
+ pw.println("No started services");
+ }
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 975e2265b60c7..e116a353c723f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -76,14 +76,18 @@ import android.provider.Settings;
import android.server.ServerProtoEnums;
import android.sysprop.VoldProperties;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.EventLog;
+import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
+import android.util.TimeUtils;
import android.view.contentcapture.ContentCaptureManager;
import com.android.i18n.timezone.ZoneInfoDb;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
@@ -188,14 +192,20 @@ import dalvik.system.VMRuntime;
import com.google.android.startop.iorap.IorapForwardingService;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Timer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
-public final class SystemServer {
+/**
+ * Entry point to {@code system_server}.
+ */
+public final class SystemServer implements Dumpable {
private static final String TAG = "SystemServer";
@@ -384,6 +394,9 @@ public final class SystemServer {
private Future> mZygotePreload;
private Future> mBlobStoreServiceStart;
+ private final SystemServerDumper mDumper = new SystemServerDumper();
+
+
/**
* The pending WTF to be logged into dropbox.
*/
@@ -446,6 +459,75 @@ public final class SystemServer {
mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
}
+ @Override
+ public void dump(IndentingPrintWriter pw, String[] args) {
+ pw.printf("Runtime restart: %b\n", mRuntimeRestart);
+ pw.printf("Start count: %d\n", mStartCount);
+ pw.print("Runtime start-up time: ");
+ TimeUtils.formatDuration(mRuntimeStartUptime, pw); pw.println();
+ pw.print("Runtime start-elapsed time: ");
+ TimeUtils.formatDuration(mRuntimeStartElapsedTime, pw); pw.println();
+ }
+
+ private final class SystemServerDumper extends Binder {
+
+ @GuardedBy("mDumpables")
+ private final ArrayMap