• 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 
26 import java.util.List;
27 import java.util.concurrent.Callable;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.TimeUnit;
31 
32 /**
33  * Thread pool used during initialization of system server.
34  * <p>System services can {@link #submit(Runnable)} tasks for execution during boot.
35  * The pool will be shut down after {@link SystemService#PHASE_BOOT_COMPLETED}.
36  * New tasks <em>should not</em> be submitted afterwards.
37  *
38  * @hide
39  */
40 public class SystemServerInitThreadPool {
41     private static final String TAG = SystemServerInitThreadPool.class.getSimpleName();
42     private static final int SHUTDOWN_TIMEOUT_MILLIS = 20000;
43     private static final boolean IS_DEBUGGABLE = Build.IS_DEBUGGABLE;
44 
45     private static SystemServerInitThreadPool sInstance;
46 
47     private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
48             "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
49 
get()50     public static synchronized SystemServerInitThreadPool get() {
51         if (sInstance == null) {
52             sInstance = new SystemServerInitThreadPool();
53         }
54         Preconditions.checkState(sInstance.mService != null, "Cannot get " + TAG
55                 + " - it has been shut down");
56         return sInstance;
57     }
58 
submit(Runnable runnable, String description)59     public Future<?> submit(Runnable runnable, String description) {
60         if (IS_DEBUGGABLE) {
61             return mService.submit(() -> {
62                 Slog.d(TAG, "Started executing " + description);
63                 try {
64                     runnable.run();
65                 } catch (RuntimeException e) {
66                     Slog.e(TAG, "Failure in " + description + ": " + e, e);
67                     throw e;
68                 }
69                 Slog.d(TAG, "Finished executing "  + description);
70             });
71         }
72         return mService.submit(runnable);
73     }
74 
shutdown()75     static synchronized void shutdown() {
76         if (sInstance != null && sInstance.mService != null) {
77             sInstance.mService.shutdown();
78             boolean terminated;
79             try {
80                 terminated = sInstance.mService.awaitTermination(SHUTDOWN_TIMEOUT_MILLIS,
81                         TimeUnit.MILLISECONDS);
82             } catch (InterruptedException e) {
83                 Thread.currentThread().interrupt();
84                 throw new IllegalStateException(TAG + " init interrupted");
85             }
86             List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
87             if (!terminated) {
88                 throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
89                         + unstartedRunnables);
90             }
91             sInstance.mService = null; // Make mService eligible for GC
92             Slog.d(TAG, "Shutdown successful");
93         }
94     }
95 
96 }
97