Merge "Created a mechanism to dump service-less SystemServer state."

This commit is contained in:
TreeHugger Robot
2020-10-26 16:23:04 +00:00
committed by Android (Google) Code Review
5 changed files with 205 additions and 40 deletions

View 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();
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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(')');
}
}

View File

@@ -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");
}
}
}

View File

@@ -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();
}