Loading services/core/java/com/android/server/SystemServerInitThreadPool.java +67 −18 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.server; import android.annotation.NonNull; import android.os.Build; import android.os.Process; 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; Loading @@ -32,9 +34,11 @@ import java.util.concurrent.TimeUnit; /** * Thread pool used during initialization of system server. * * <p>System services can {@link #submit(Runnable)} tasks for execution during boot. * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}. * New tasks <em>should not</em> be submitted afterwards. * * <p>New tasks <em>should not</em> be submitted afterwards. * * @hide */ Loading @@ -42,26 +46,46 @@ public class SystemServerInitThreadPool { 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 ExecutorService mService = ConcurrentUtils.newFixedThreadPool( Runtime.getRuntime().availableProcessors(), "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); private final ExecutorService mService; private List<String> mPendingTasks = new ArrayList<>(); @GuardedBy("mPendingTasks") private final List<String> mPendingTasks = new ArrayList<>(); public static synchronized SystemServerInitThreadPool get() { if (sInstance == null) { sInstance = new SystemServerInitThreadPool(); @GuardedBy("mPendingTasks") private boolean mShutDown; private SystemServerInitThreadPool() { final int size = Runtime.getRuntime().availableProcessors(); Slog.i(TAG, "Creating instance with " + size + " threads"); mService = ConcurrentUtils.newFixedThreadPool(size, "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); } Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG /** * Gets the singleton. * * @throws IllegalStateException if it hasn't been started or has been shut down already. */ public static SystemServerInitThreadPool get() { synchronized (LOCK) { Preconditions.checkState(sInstance != null, "Cannot get " + TAG + " - it has been shut down"); return sInstance; } } public Future<?> submit(Runnable runnable, String description) { /** * Submits a task for execution. */ public @NonNull Future<?> submit(@NonNull Runnable runnable, @NonNull String description) { Preconditions.checkNotNull(description, "description cannot be null"); synchronized (mPendingTasks) { Preconditions.checkState(!mShutDown, TAG + " already shut down"); mPendingTasks.add(description); } return mService.submit(() -> { Loading @@ -83,10 +107,36 @@ public class SystemServerInitThreadPool { }); } static synchronized void shutdown() { if (sInstance != null && sInstance.mService != null) { /** * Starts it. * * <p>Note:</p> should only be called by {@link SystemServer}. * * @throws IllegalStateException if it has been started already without being shut down yet. */ static void start() { synchronized (LOCK) { Preconditions.checkState(sInstance == null, TAG + " already started"); sInstance = new SystemServerInitThreadPool(); } } /** * Shuts it down. * * <p>Note:</p> should only be called by {@link SystemServer}. */ static void shutdown() { synchronized (LOCK) { if (sInstance == null) { Slog.wtf(TAG, "Already shutdown", new Exception()); return; } synchronized (sInstance.mPendingTasks) { sInstance.mShutDown = true; } sInstance.mService.shutdown(); boolean terminated; final boolean terminated; try { terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); Loading @@ -100,7 +150,7 @@ public class SystemServerInitThreadPool { // in the thread pool. dumpStackTraces(); } List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); final List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); if (!terminated) { final List<String> copy = new ArrayList<>(); synchronized (sInstance.mPendingTasks) { Loading @@ -109,8 +159,7 @@ public class SystemServerInitThreadPool { throw new IllegalStateException("Cannot shutdown. Unstarted tasks " + unstartedRunnables + " Unfinished tasks " + copy); } sInstance.mService = null; // Make mService eligible for GC sInstance.mPendingTasks = null; sInstance = null; // Make eligible for GC Slog.d(TAG, "Shutdown successful"); } } Loading services/java/com/android/server/SystemServer.java +1 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,7 @@ public final class SystemServer { mRuntimeStartElapsedTime, mRuntimeStartUptime); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Prepare the thread pool for init tasks that can be parallelized SystemServerInitThreadPool.get(); SystemServerInitThreadPool.start(); } finally { t.traceEnd(); // InitBeforeStartServices } Loading Loading
services/core/java/com/android/server/SystemServerInitThreadPool.java +67 −18 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package com.android.server; import android.annotation.NonNull; import android.os.Build; import android.os.Process; 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; Loading @@ -32,9 +34,11 @@ import java.util.concurrent.TimeUnit; /** * Thread pool used during initialization of system server. * * <p>System services can {@link #submit(Runnable)} tasks for execution during boot. * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}. * New tasks <em>should not</em> be submitted afterwards. * * <p>New tasks <em>should not</em> be submitted afterwards. * * @hide */ Loading @@ -42,26 +46,46 @@ public class SystemServerInitThreadPool { 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 ExecutorService mService = ConcurrentUtils.newFixedThreadPool( Runtime.getRuntime().availableProcessors(), "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); private final ExecutorService mService; private List<String> mPendingTasks = new ArrayList<>(); @GuardedBy("mPendingTasks") private final List<String> mPendingTasks = new ArrayList<>(); public static synchronized SystemServerInitThreadPool get() { if (sInstance == null) { sInstance = new SystemServerInitThreadPool(); @GuardedBy("mPendingTasks") private boolean mShutDown; private SystemServerInitThreadPool() { final int size = Runtime.getRuntime().availableProcessors(); Slog.i(TAG, "Creating instance with " + size + " threads"); mService = ConcurrentUtils.newFixedThreadPool(size, "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); } Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG /** * Gets the singleton. * * @throws IllegalStateException if it hasn't been started or has been shut down already. */ public static SystemServerInitThreadPool get() { synchronized (LOCK) { Preconditions.checkState(sInstance != null, "Cannot get " + TAG + " - it has been shut down"); return sInstance; } } public Future<?> submit(Runnable runnable, String description) { /** * Submits a task for execution. */ public @NonNull Future<?> submit(@NonNull Runnable runnable, @NonNull String description) { Preconditions.checkNotNull(description, "description cannot be null"); synchronized (mPendingTasks) { Preconditions.checkState(!mShutDown, TAG + " already shut down"); mPendingTasks.add(description); } return mService.submit(() -> { Loading @@ -83,10 +107,36 @@ public class SystemServerInitThreadPool { }); } static synchronized void shutdown() { if (sInstance != null && sInstance.mService != null) { /** * Starts it. * * <p>Note:</p> should only be called by {@link SystemServer}. * * @throws IllegalStateException if it has been started already without being shut down yet. */ static void start() { synchronized (LOCK) { Preconditions.checkState(sInstance == null, TAG + " already started"); sInstance = new SystemServerInitThreadPool(); } } /** * Shuts it down. * * <p>Note:</p> should only be called by {@link SystemServer}. */ static void shutdown() { synchronized (LOCK) { if (sInstance == null) { Slog.wtf(TAG, "Already shutdown", new Exception()); return; } synchronized (sInstance.mPendingTasks) { sInstance.mShutDown = true; } sInstance.mService.shutdown(); boolean terminated; final boolean terminated; try { terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); Loading @@ -100,7 +150,7 @@ public class SystemServerInitThreadPool { // in the thread pool. dumpStackTraces(); } List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); final List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); if (!terminated) { final List<String> copy = new ArrayList<>(); synchronized (sInstance.mPendingTasks) { Loading @@ -109,8 +159,7 @@ public class SystemServerInitThreadPool { throw new IllegalStateException("Cannot shutdown. Unstarted tasks " + unstartedRunnables + " Unfinished tasks " + copy); } sInstance.mService = null; // Make mService eligible for GC sInstance.mPendingTasks = null; sInstance = null; // Make eligible for GC Slog.d(TAG, "Shutdown successful"); } } Loading
services/java/com/android/server/SystemServer.java +1 −1 Original line number Diff line number Diff line Loading @@ -501,7 +501,7 @@ public final class SystemServer { mRuntimeStartElapsedTime, mRuntimeStartUptime); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Prepare the thread pool for init tasks that can be parallelized SystemServerInitThreadPool.get(); SystemServerInitThreadPool.start(); } finally { t.traceEnd(); // InitBeforeStartServices } Loading