Merge "Created a mechanism to dump service-less SystemServer state."
This commit is contained in:
committed by
Android (Google) Code Review
commit
1d00c49a94
40
services/core/java/com/android/server/Dumpable.java
Normal file
40
services/core/java/com/android/server/Dumpable.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user