1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server; 18 19 import android.os.Build; 20 import android.os.Process; 21 import android.util.Slog; 22 23 import com.android.internal.util.ConcurrentUtils; 24 import com.android.internal.util.Preconditions; 25 import com.android.server.am.ActivityManagerService; 26 27 import java.util.ArrayList; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.concurrent.ExecutorService; 31 import java.util.concurrent.Future; 32 import java.util.concurrent.TimeUnit; 33 34 /** 35 * Thread pool used during initialization of system server. 36 * <p>System services can {@link #submit(Runnable)} tasks for execution during boot. 37 * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}. 38 * New tasks <em>should not</em> be submitted afterwards. 39 * 40 * @hide 41 */ 42 public class SystemServerInitThreadPool { 43 private static final String TAG = SystemServerInitThreadPool.class.getSimpleName(); 44 private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000; 45 private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE; 46 47 private static SystemServerInitThreadPool sInstance; 48 49 private ExecutorService mService = ConcurrentUtils.newFixedThreadPool( 50 Runtime.getRuntime().availableProcessors(), 51 "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND); 52 53 private List<String> mPendingTasks = new ArrayList<>(); 54 get()55 public static synchronized SystemServerInitThreadPool get() { 56 if (sInstance == null) { 57 sInstance = new SystemServerInitThreadPool(); 58 } 59 Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG 60 + " - it has been shut down"); 61 return sInstance; 62 } 63 submit(Runnable runnable, String description)64 public Future<?> submit(Runnable runnable, String description) { 65 synchronized (mPendingTasks) { 66 mPendingTasks.add(description); 67 } 68 return mService.submit(() -> { 69 if (IS_DEBUGGABLE) { 70 Slog.d(TAG, "Started executing " + description); 71 } 72 try { 73 runnable.run(); 74 } catch (RuntimeException e) { 75 Slog.e(TAG, "Failure in " + description + ": " + e, e); 76 throw e; 77 } 78 synchronized (mPendingTasks) { 79 mPendingTasks.remove(description); 80 } 81 if (IS_DEBUGGABLE) { 82 Slog.d(TAG, "Finished executing " + description); 83 } 84 }); 85 } 86 87 static synchronized void shutdown() { 88 if (sInstance != null && sInstance.mService != null) { 89 sInstance.mService.shutdown(); 90 boolean terminated; 91 try { 92 terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS, 93 TimeUnit.MILLISECONDS); 94 } catch (InterruptedException e) { 95 Thread.currentThread().interrupt(); 96 dumpStackTraces(); 97 throw new IllegalStateException(TAG + " init interrupted"); 98 } 99 if (!terminated) { 100 // dump stack must be called before shutdownNow() to collect stacktrace of threads 101 // in the thread pool. 102 dumpStackTraces(); 103 } 104 List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow(); 105 if (!terminated) { 106 final List<String> copy = new ArrayList<>(); 107 synchronized (sInstance.mPendingTasks) { 108 copy.addAll(sInstance.mPendingTasks); 109 } 110 throw new IllegalStateException("Cannot shutdown. Unstarted tasks " 111 + unstartedRunnables + " Unfinished tasks " + copy); 112 } 113 sInstance.mService = null; // Make mService eligible for GC 114 sInstance.mPendingTasks = null; 115 Slog.d(TAG, "Shutdown successful"); 116 } 117 } 118 119 /** 120 * A helper function to call ActivityManagerService.dumpStackTraces(). 121 */ 122 private static void dumpStackTraces() { 123 final ArrayList<Integer> pids = new ArrayList<>(); 124 pids.add(Process.myPid()); 125 ActivityManagerService.dumpStackTraces(pids, null, null, 126 Watchdog.getInterestingNativePids()); 127 } 128 } 129