Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d00c49a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 764a15f7 c60be188
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}
+28 −6
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}
+7 −7
Original line number Diff line number Diff line
@@ -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(')');
        }
    }

+32 −23
Original line number Diff line number Diff line
@@ -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();
            if (targetUsersSize > 0) {
                pw.printf("%d target users: ", targetUsersSize);
                for (int i = 0; i < targetUsersSize; i++) {
                mTargetUsers.valueAt(i).dump(builder);
                if (i != targetUsersSize - 1) builder.append(',');
                    mTargetUsers.valueAt(i).dump(pw);
                    if (i != targetUsersSize - 1) pw.print(", ");
                }
            builder.append('\n');
                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");
        }

        Slog.e(TAG, builder.toString());
    }
}
+97 −3
Original line number Diff line number Diff line
@@ -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();
            }