• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.wm.shell.dagger;
18 
19 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
20 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
21 import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
22 import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
23 
24 import android.content.Context;
25 import android.os.Build;
26 import android.os.Handler;
27 import android.os.HandlerThread;
28 import android.os.Looper;
29 import android.os.Trace;
30 import android.view.Choreographer;
31 
32 import androidx.annotation.Nullable;
33 
34 import com.android.wm.shell.R;
35 import com.android.wm.shell.common.HandlerExecutor;
36 import com.android.wm.shell.common.ShellExecutor;
37 import com.android.wm.shell.shared.annotations.ExternalMainThread;
38 import com.android.wm.shell.shared.annotations.ShellAnimationThread;
39 import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
40 import com.android.wm.shell.shared.annotations.ShellDesktopThread;
41 import com.android.wm.shell.shared.annotations.ShellMainThread;
42 import com.android.wm.shell.shared.annotations.ShellSplashscreenThread;
43 
44 import dagger.Module;
45 import dagger.Provides;
46 
47 /**
48  * Provides basic concurrency-related dependencies from {@link com.android.wm.shell}, these
49  * dependencies are only accessible from components within the WM subcomponent.
50  */
51 @Module
52 public abstract class WMShellConcurrencyModule {
53 
54     private static final int MSGQ_SLOW_DELIVERY_THRESHOLD_MS = 30;
55     private static final int MSGQ_SLOW_DISPATCH_THRESHOLD_MS = 30;
56 
57     /**
58      * Returns whether to enable a separate shell thread for the shell features.
59      */
enableShellMainThread(Context context)60     public static boolean enableShellMainThread(Context context) {
61         return context.getResources().getBoolean(R.bool.config_enableShellMainThread);
62     }
63 
64     //
65     // Shell Concurrency - Components used for managing threading in the Shell and SysUI
66     //
67 
68 
69     /**
70      * Provide a SysUI main-thread Handler.
71      *
72      * Prefer the Main Executor when possible.
73      */
74     @Provides
75     @ExternalMainThread
provideMainHandler()76     public static Handler provideMainHandler() {
77         return new Handler(Looper.getMainLooper());
78     }
79 
80     /**
81      * Provide a SysUI main-thread Executor.
82      */
83     @WMSingleton
84     @Provides
85     @ExternalMainThread
provideSysUIMainExecutor( @xternalMainThread Handler sysuiMainHandler)86     public static ShellExecutor provideSysUIMainExecutor(
87             @ExternalMainThread Handler sysuiMainHandler) {
88         return new HandlerExecutor(sysuiMainHandler);
89     }
90 
91     /**
92      * Creates a shell main thread to be injected into the shell components.  This does not provide
93      * the {@param HandleThread}, but is used to create the thread prior to initializing the
94      * WM component, and is explicitly bound.
95      *
96      * See {@link com.android.systemui.SystemUIFactory#init(Context, boolean)}.
97      */
createShellMainThread()98     public static HandlerThread createShellMainThread() {
99         HandlerThread mainThread = new HandlerThread("wmshell.main", THREAD_PRIORITY_DISPLAY);
100         return mainThread;
101     }
102 
103     /**
104      * Shell main-thread Handler, don't use this unless really necessary (ie. need to dedupe
105      * multiple types of messages, etc.)
106      *
107      * @param mainThread If non-null, this thread is expected to be started already
108      */
109     @WMSingleton
110     @Provides
111     @ShellMainThread
provideShellMainHandler(Context context, @Nullable @ShellMainThread HandlerThread mainThread, @ExternalMainThread Handler sysuiMainHandler)112     public static Handler provideShellMainHandler(Context context,
113             @Nullable @ShellMainThread HandlerThread mainThread,
114             @ExternalMainThread Handler sysuiMainHandler) {
115         if (enableShellMainThread(context)) {
116             if (mainThread == null) {
117                 // If this thread wasn't pre-emptively started, then create and start it
118                 mainThread = createShellMainThread();
119                 mainThread.start();
120             }
121             if (Build.IS_DEBUGGABLE) {
122                 mainThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
123                 mainThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
124                         MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
125             }
126             return Handler.createAsync(mainThread.getLooper());
127         }
128         return sysuiMainHandler;
129     }
130 
131     /**
132      * Provide a Shell main-thread Executor.
133      */
134     @WMSingleton
135     @Provides
136     @ShellMainThread
provideShellMainExecutor(Context context, @ShellMainThread Handler mainHandler, @ExternalMainThread ShellExecutor sysuiMainExecutor)137     public static ShellExecutor provideShellMainExecutor(Context context,
138             @ShellMainThread Handler mainHandler,
139             @ExternalMainThread ShellExecutor sysuiMainExecutor) {
140         if (enableShellMainThread(context)) {
141             return new HandlerExecutor(mainHandler);
142         }
143         return sysuiMainExecutor;
144     }
145 
146     /**
147      * Provide a Shell main-thread {@link Choreographer} with the app vsync.
148      *
149      * @param executor the executor of the shell main thread
150      */
151     @WMSingleton
152     @Provides
153     @ShellMainThread
provideShellMainChoreographer( @hellMainThread ShellExecutor executor)154     public static Choreographer provideShellMainChoreographer(
155             @ShellMainThread ShellExecutor executor) {
156         try {
157             final Choreographer[] choreographer = new Choreographer[1];
158             executor.executeBlocking(() -> choreographer[0] = Choreographer.getInstance());
159             return choreographer[0];
160         } catch (InterruptedException e) {
161             throw new RuntimeException("Failed to obtain main Choreographer.", e);
162         }
163     }
164 
165     /** Provide a Shell animation-thread Handler. */
166     @WMSingleton
167     @Provides
168     @ShellAnimationThread
provideShellAnimationHandler()169     public static Handler provideShellAnimationHandler() {
170         HandlerThread animThread = new HandlerThread("wmshell.anim", THREAD_PRIORITY_DISPLAY);
171         animThread.start();
172         if (Build.IS_DEBUGGABLE) {
173             animThread.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
174             animThread.getLooper().setSlowLogThresholdMs(MSGQ_SLOW_DISPATCH_THRESHOLD_MS,
175                     MSGQ_SLOW_DELIVERY_THRESHOLD_MS);
176         }
177         return Handler.createAsync(animThread.getLooper());
178     }
179 
180     /**
181      * Provide a Shell animation-thread Executor.
182      */
183     @WMSingleton
184     @Provides
185     @ShellAnimationThread
provideShellAnimationExecutor( @hellAnimationThread Handler animHandler )186     public static ShellExecutor provideShellAnimationExecutor(
187             @ShellAnimationThread Handler animHandler
188     ) {
189         return new HandlerExecutor(animHandler);
190     }
191 
192     /**
193      * Provides a Shell splashscreen-thread Executor
194      */
195     @WMSingleton
196     @Provides
197     @ShellSplashscreenThread
provideSplashScreenExecutor()198     public static ShellExecutor provideSplashScreenExecutor() {
199         HandlerThread shellSplashscreenThread = new HandlerThread("wmshell.splashscreen",
200                 THREAD_PRIORITY_TOP_APP_BOOST);
201         shellSplashscreenThread.start();
202         return new HandlerExecutor(shellSplashscreenThread.getThreadHandler());
203     }
204 
205     /**
206      * Provides a Shell desktop thread Executor
207      */
208     @WMSingleton
209     @Provides
210     @ShellDesktopThread
provideDesktopModeMiscExecutor()211     public static ShellExecutor provideDesktopModeMiscExecutor() {
212         HandlerThread shellDesktopThread = new HandlerThread("wmshell.desktop",
213                 THREAD_PRIORITY_TOP_APP_BOOST);
214         shellDesktopThread.start();
215         return new HandlerExecutor(shellDesktopThread.getThreadHandler());
216     }
217 
218     /**
219      * Provides a Shell background thread Handler for low priority background tasks.
220      */
221     @WMSingleton
222     @Provides
223     @ShellBackgroundThread
provideSharedBackgroundHandler()224     public static Handler provideSharedBackgroundHandler() {
225         final HandlerThread shellBackgroundThread = new HandlerThread("wmshell.background",
226                 THREAD_PRIORITY_BACKGROUND);
227         shellBackgroundThread.start();
228         return shellBackgroundThread.getThreadHandler();
229     }
230 
231     /**
232      * Provides a Shell background thread Executor for low priority background tasks.  The thread
233      * may also be boosted to THREAD_PRIORITY_FOREGROUND if necessary.
234      */
235     @WMSingleton
236     @Provides
237     @ShellBackgroundThread
provideSharedBackgroundExecutor( @hellBackgroundThread Handler handler)238     public static ShellExecutor provideSharedBackgroundExecutor(
239             @ShellBackgroundThread Handler handler) {
240         return new HandlerExecutor(handler, THREAD_PRIORITY_BACKGROUND, THREAD_PRIORITY_FOREGROUND);
241     }
242 }
243