All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.SystemServerInitThreadPool Maven / Gradle / Ivy

/*
 * Copyright (C) 2016 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.os.Build;
import android.os.Process;
import android.util.IndentingPrintWriter;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.Preconditions;
import com.android.server.am.ActivityManagerService;
import com.android.server.utils.TimingsTraceAndSlog;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Thread pool used during initialization of system server.
 *
 * 

System services can {@link #submit(Runnable, String)} tasks for execution during boot. * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}. * *

New tasks should not be submitted afterwards. * * @hide */ 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; private static final Object LOCK = new Object(); @GuardedBy("LOCK") private static SystemServerInitThreadPool sInstance; private final int mSize; // used by dump() only private final ExecutorService mService; @GuardedBy("mPendingTasks") private final List mPendingTasks = new ArrayList<>(); @GuardedBy("mPendingTasks") private boolean mShutDown; private SystemServerInitThreadPool() { mSize = Runtime.getRuntime().availableProcessors(); Slog.i(TAG, "Creating instance with " + mSize + " threads"); mService = ConcurrentUtils.newFixedThreadPool(mSize, "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); } /** * Submits a task for execution. * * @throws IllegalStateException if it hasn't been started or has been shut down already. */ public static @NonNull Future submit(@NonNull Runnable runnable, @NonNull String description) { Objects.requireNonNull(description, "description cannot be null"); SystemServerInitThreadPool instance; synchronized (LOCK) { Preconditions.checkState(sInstance != null, "Cannot get " + TAG + " - it has been shut down"); instance = sInstance; } return instance.submitTask(runnable, description); } private @NonNull Future submitTask(@NonNull Runnable runnable, @NonNull String description) { synchronized (mPendingTasks) { Preconditions.checkState(!mShutDown, TAG + " already shut down"); mPendingTasks.add(description); } return mService.submit(() -> { TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog(); traceLog.traceBegin("InitThreadPoolExec:" + description); if (IS_DEBUGGABLE) { Slog.d(TAG, "Started executing " + description); } try { runnable.run(); } catch (RuntimeException e) { Slog.e(TAG, "Failure in " + description + ": " + e, e); traceLog.traceEnd(); throw e; } synchronized (mPendingTasks) { mPendingTasks.remove(description); } if (IS_DEBUGGABLE) { Slog.d(TAG, "Finished executing " + description); } traceLog.traceEnd(); }); } /** * Starts it. * *

Note:

should only be called by {@link SystemServer}. * * @throws IllegalStateException if it has been started already without being shut down yet. */ static SystemServerInitThreadPool start() { SystemServerInitThreadPool instance; synchronized (LOCK) { Preconditions.checkState(sInstance == null, TAG + " already started"); instance = sInstance = new SystemServerInitThreadPool(); } return instance; } /** * Shuts it down. * *

Note:

should only be called *after* {@code PHASE_BOOT_COMPLETED} is sent to the * {@link SystemService system services}. */ static void shutdown() { Slog.d(TAG, "Shutdown requested"); synchronized (LOCK) { TimingsTraceAndSlog t = new TimingsTraceAndSlog(); t.traceBegin("WaitInitThreadPoolShutdown"); if (sInstance == null) { t.traceEnd(); Slog.wtf(TAG, "Already shutdown", new Exception()); return; } synchronized (sInstance.mPendingTasks) { sInstance.mShutDown = true; } sInstance.mService.shutdown(); final boolean terminated; try { terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); dumpStackTraces(); t.traceEnd(); throw new IllegalStateException(TAG + " init interrupted"); } if (!terminated) { // dump stack must be called before shutdownNow() to collect stacktrace of threads // in the thread pool. dumpStackTraces(); } final List unstartedRunnables = sInstance.mService.shutdownNow(); if (!terminated) { final List copy = new ArrayList<>(); synchronized (sInstance.mPendingTasks) { copy.addAll(sInstance.mPendingTasks); } t.traceEnd(); throw new IllegalStateException("Cannot shutdown. Unstarted tasks " + unstartedRunnables + " Unfinished tasks " + copy); } sInstance = null; // Make eligible for GC Slog.d(TAG, "Shutdown successful"); t.traceEnd(); } } /** * A helper function to call ActivityManagerService.dumpStackTraces(). */ private static void dumpStackTraces() { final ArrayList pids = new ArrayList<>(); pids.add(Process.myPid()); ActivityManagerService.dumpStackTraces(pids, null, null, Watchdog.getInterestingNativePids(), null, 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); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy