• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.concurrent.ExecutorService;
30 import java.util.concurrent.Future;
31 import java.util.concurrent.TimeUnit;
32 
33 /**
34  * Thread pool used during initialization of system server.
35  * <p>System services can {@link #submit(Runnable)} tasks for execution during boot.
36  * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}.
37  * New tasks <em>should not</em> be submitted afterwards.
38  *
39  * @hide
40  */
41 public class SystemServerInitThreadPool {
42     private static final String TAG = SystemServerInitThreadPool.class.getSimpleName();
43     private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000;
44     private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE;
45 
46     private static SystemServerInitThreadPool sInstance;
47 
48     private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(
49             Runtime.getRuntime().availableProcessors(),
50             "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
51 
52     private List<String> mPendingTasks = new ArrayList<>();
53 
get()54     public static synchronized SystemServerInitThreadPool get() {
55         if (sInstance == null) {
56             sInstance = new SystemServerInitThreadPool();
57         }
58         Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG
59                 + " - it has been shut down");
60         return sInstance;
61     }
62 
submit(Runnable runnable, String description)63     public Future<?> submit(Runnable runnable, String description) {
64         synchronized (mPendingTasks) {
65             mPendingTasks.add(description);
66         }
67         return mService.submit(() -> {
68             if (IS_DEBUGGABLE) {
69                 Slog.d(TAG, "Started executing " + description);
70             }
71             try {
72                 runnable.run();
73             } catch (RuntimeException e) {
74                 Slog.e(TAG, "Failure in " + description + ": " + e, e);
75                 throw e;
76             }
77             synchronized (mPendingTasks) {
78                 mPendingTasks.remove(description);
79             }
80             if (IS_DEBUGGABLE) {
81                 Slog.d(TAG, "Finished executing " + description);
82             }
83         });
84     }
85 
86     static synchronized void shutdown() {
87         if (sInstance != null && sInstance.mService != null) {
88             sInstance.mService.shutdown();
89             boolean terminated;
90             try {
91                 terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS,
92                         TimeUnit.MILLISECONDS);
93             } catch (InterruptedException e) {
94                 Thread.currentThread().interrupt();
95                 dumpStackTraces();
96                 throw new IllegalStateException(TAG + " init interrupted");
97             }
98             if (!terminated) {
99                 // dump stack must be called before shutdownNow() to collect stacktrace of threads
100                 // in the thread pool.
101                 dumpStackTraces();
102             }
103             List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
104             if (!terminated) {
105                 final List<String> copy = new ArrayList<>();
106                 synchronized (sInstance.mPendingTasks) {
107                     copy.addAll(sInstance.mPendingTasks);
108                 }
109                 throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
110                         + unstartedRunnables + " Unfinished tasks " + copy);
111             }
112             sInstance.mService = null; // Make mService eligible for GC
113             sInstance.mPendingTasks = null;
114             Slog.d(TAG, "Shutdown successful");
115         }
116     }
117 
118     /**
119      * A helper function to call ActivityManagerService.dumpStackTraces().
120      */
121     private static void dumpStackTraces() {
122         final ArrayList<Integer> pids = new ArrayList<>();
123         pids.add(Process.myPid());
124         ActivityManagerService.dumpStackTraces(pids, null, null,
125                 Watchdog.getInterestingNativePids());
126     }
127 }
128