summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/Dumpable.java40
-rw-r--r--services/core/java/com/android/server/SystemServerInitThreadPool.java34
-rw-r--r--services/core/java/com/android/server/SystemService.java14
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java55
-rw-r--r--services/java/com/android/server/SystemServer.java100
5 files changed, 204 insertions, 39 deletions
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 000000000000..d2bd66f59b62
--- /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.
+ *
+ * <p>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 c0611374679b..c23f1cab0614 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 84d01ec3598d..6c81de6af402 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 ff2661b19b48..71a18218110e 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: ");
+ if (mCurrentUser != null) {
+ pw.print("Current user: "); mCurrentUser.dump(pw); pw.println();
+ } else {
+ pw.println("Current user not set!");
+ }
+
final int targetUsersSize = mTargetUsers.size();
- for (int i = 0; i < targetUsersSize; i++) {
- mTargetUsers.valueAt(i).dump(builder);
- if (i != targetUsersSize - 1) builder.append(',');
+ 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");
}
- builder.append('\n');
}
-
- Slog.e(TAG, builder.toString());
+ 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 975e2265b60c..e116a353c723 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<String, Dumpable> mDumpables = new ArrayMap<>(4);
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final boolean hasArgs = args != null && args.length > 0;
+
+ synchronized (mDumpables) {
+ if (hasArgs && "--list".equals(args[0])) {
+ final int dumpablesSize = mDumpables.size();
+ for (int i = 0; i < dumpablesSize; i++) {
+ pw.println(mDumpables.keyAt(i));
+ }
+ return;
+ }
+
+ if (hasArgs && "--name".equals(args[0])) {
+ if (args.length < 2) {
+ pw.println("Must pass at least one argument to --name");
+ return;
+ }
+ final String name = args[1];
+ final Dumpable dumpable = mDumpables.get(name);
+ if (dumpable == null) {
+ pw.printf("No dummpable named %s\n", name);
+ return;
+ }
+
+ try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ // Strip --name DUMPABLE from args
+ final String[] actualArgs = Arrays.copyOfRange(args, 2, args.length);
+ dumpable.dump(ipw, actualArgs);
+ }
+ return;
+ }
+
+ final int dumpablesSize = mDumpables.size();
+ try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ")) {
+ for (int i = 0; i < dumpablesSize; i++) {
+ final Dumpable dumpable = mDumpables.valueAt(i);
+ ipw.printf("%s:\n", dumpable.getDumpableName());
+ ipw.increaseIndent();
+ dumpable.dump(ipw, args);
+ ipw.decreaseIndent();
+ ipw.println();
+ }
+ }
+ }
+ }
+
+ private void addDumpable(@NonNull Dumpable dumpable) {
+ synchronized (mDumpables) {
+ mDumpables.put(dumpable.getDumpableName(), dumpable);
+ }
+ }
+ }
+
private void run() {
TimingsTraceAndSlog t = new TimingsTraceAndSlog();
try {
@@ -572,13 +654,21 @@ public final class SystemServer {
// Call per-process mainline module initialization.
ActivityThread.initializeMainlineModules();
+ // Sets the dumper service
+ ServiceManager.addService("system_server_dumper", mDumper);
+ mDumper.addDumpable(this);
+
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setStartInfo(mRuntimeRestart,
mRuntimeStartElapsedTime, mRuntimeStartUptime);
+ mDumper.addDumpable(mSystemServiceManager);
+
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Prepare the thread pool for init tasks that can be parallelized
- SystemServerInitThreadPool.start();
+ SystemServerInitThreadPool tp = SystemServerInitThreadPool.start();
+ mDumper.addDumpable(tp);
+
// Attach JVMTI agent if this is a debuggable build and the system property is set.
if (Build.IS_DEBUGGABLE) {
// Property is of the form "library_path=parameters".
@@ -2321,7 +2411,11 @@ public final class SystemServer {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
t.traceBegin("StartCarServiceHelperService");
- mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
+ final SystemService cshs = mSystemServiceManager
+ .startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
+ if (cshs instanceof Dumpable) {
+ mDumper.addDumpable((Dumpable) cshs);
+ }
t.traceEnd();
}