• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.systemui.util.kotlin
18 
19 import android.os.Handler
20 import com.android.systemui.coroutines.newTracingContext
21 import com.android.systemui.dagger.SysUISingleton
22 import com.android.systemui.dagger.qualifiers.Application
23 import com.android.systemui.dagger.qualifiers.Background
24 import com.android.systemui.dagger.qualifiers.NotifInflation
25 import com.android.systemui.dagger.qualifiers.UiBackground
26 import com.android.systemui.util.settings.SettingsSingleThreadBackground
27 import dagger.Module
28 import dagger.Provides
29 import java.util.concurrent.Executor
30 import kotlin.coroutines.CoroutineContext
31 import kotlinx.coroutines.CoroutineDispatcher
32 import kotlinx.coroutines.CoroutineScope
33 import kotlinx.coroutines.DelicateCoroutinesApi
34 import kotlinx.coroutines.Dispatchers
35 import kotlinx.coroutines.android.asCoroutineDispatcher
36 import kotlinx.coroutines.asCoroutineDispatcher
37 import kotlinx.coroutines.newFixedThreadPoolContext
38 import kotlinx.coroutines.plus
39 
40 private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true
41 
42 /** Providers for various SystemUI-specific coroutines-related constructs. */
43 @Module
44 class SysUICoroutinesModule {
45     @Provides
46     @SysUISingleton
47     @Background
bgApplicationScopenull48     fun bgApplicationScope(
49         @Application applicationScope: CoroutineScope,
50         @Background coroutineContext: CoroutineContext,
51     ): CoroutineScope = applicationScope.plus(coroutineContext)
52 
53     /**
54      * Default Coroutine dispatcher for background operations.
55      *
56      * Note that this is explicitly limiting the number of threads. In the past, we used
57      * [Dispatchers.IO]. This caused >40 threads to be spawned, and a lot of thread list lock
58      * contention between then, eventually causing jank.
59      */
60     @OptIn(DelicateCoroutinesApi::class)
61     @Provides
62     @SysUISingleton
63     @Background
64     @Deprecated(
65         "Use @Background CoroutineContext instead",
66         ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
67     )
68     fun bgDispatcher(): CoroutineDispatcher {
69         return if (LIMIT_BACKGROUND_DISPATCHER_THREADS) {
70             // Why a new ThreadPool instead of just using Dispatchers.IO with
71             // CoroutineDispatcher.limitedParallelism? Because, if we were to use Dispatchers.IO, we
72             // would share those threads with other dependencies using Dispatchers.IO.
73             // Using a dedicated thread pool we have guarantees only SystemUI is able to schedule
74             // code on those.
75             newFixedThreadPoolContext(
76                 nThreads = Runtime.getRuntime().availableProcessors(),
77                 name = "SystemUIBg",
78             )
79         } else {
80             Dispatchers.IO
81         }
82     }
83 
84     @Provides
85     @SysUISingleton
86     @SettingsSingleThreadBackground
settingsBgDispatchernull87     fun settingsBgDispatcher(@Background bgHandler: Handler): CoroutineDispatcher {
88         // Handlers are guaranteed to be sequential so we use that one for now.
89         return bgHandler.asCoroutineDispatcher("SettingsBg")
90     }
91 
92     @Provides
93     @SysUISingleton
94     @SettingsSingleThreadBackground
settingsScopenull95     fun settingsScope(@Background bgDispatcher: CoroutineDispatcher): CoroutineScope {
96         return CoroutineScope(bgDispatcher + newTracingContext("SettingsProxy"))
97     }
98 
99     @Provides
100     @Background
101     @SysUISingleton
bgCoroutineContextnull102     fun bgCoroutineContext(
103         @Background bgCoroutineDispatcher: CoroutineDispatcher
104     ): CoroutineContext {
105         return bgCoroutineDispatcher
106     }
107 
108     /** Coroutine dispatcher for background operations on for UI. */
109     @Provides
110     @SysUISingleton
111     @UiBackground
112     @Deprecated(
113         "Use @UiBackground CoroutineContext instead",
114         ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
115     )
uiBgDispatchernull116     fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher =
117         uiBgExecutor.asCoroutineDispatcher()
118 
119     @Provides
120     @UiBackground
121     @SysUISingleton
122     fun uiBgCoroutineContext(
123         @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher
124     ): CoroutineContext {
125         return uiBgCoroutineDispatcher
126     }
127 
128     /** Coroutine dispatcher for background notification inflation. */
129     @Provides
130     @NotifInflation
131     @SysUISingleton
notifInflationCoroutineDispatchernull132     fun notifInflationCoroutineDispatcher(
133         @NotifInflation notifInflationExecutor: Executor,
134         @Background bgCoroutineDispatcher: CoroutineDispatcher,
135     ): CoroutineDispatcher {
136         if (com.android.systemui.Flags.useNotifInflationThreadForFooter()) {
137             return notifInflationExecutor.asCoroutineDispatcher()
138         } else {
139             return bgCoroutineDispatcher
140         }
141     }
142 }
143