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 com.android.systemui.dagger.SysUISingleton 20 import com.android.systemui.dagger.qualifiers.Application 21 import com.android.systemui.dagger.qualifiers.Background 22 import com.android.systemui.dagger.qualifiers.Tracing 23 import dagger.Module 24 import dagger.Provides 25 import kotlin.coroutines.CoroutineContext 26 import kotlinx.coroutines.CoroutineDispatcher 27 import kotlinx.coroutines.CoroutineScope 28 import kotlinx.coroutines.DelicateCoroutinesApi 29 import kotlinx.coroutines.Dispatchers 30 import kotlinx.coroutines.newFixedThreadPoolContext 31 import kotlinx.coroutines.plus 32 33 private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true 34 35 /** Providers for various SystemUI-specific coroutines-related constructs. */ 36 @Module 37 class SysUICoroutinesModule { 38 @Provides 39 @SysUISingleton 40 @Background bgApplicationScopenull41 fun bgApplicationScope( 42 @Application applicationScope: CoroutineScope, 43 @Background coroutineContext: CoroutineContext, 44 ): CoroutineScope = applicationScope.plus(coroutineContext) 45 46 /** 47 * Default Coroutine dispatcher for background operations. 48 * 49 * Note that this is explicitly limiting the number of threads. In the past, we used 50 * [Dispatchers.IO]. This caused >40 threads to be spawned, and a lot of thread list lock 51 * contention between then, eventually causing jank. 52 */ 53 @OptIn(DelicateCoroutinesApi::class) 54 @Provides 55 @SysUISingleton 56 @Background 57 @Deprecated( 58 "Use @Background CoroutineContext instead", 59 ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext") 60 ) 61 fun bgDispatcher(): CoroutineDispatcher { 62 return if (LIMIT_BACKGROUND_DISPATCHER_THREADS) { 63 // Why a new ThreadPool instead of just using Dispatchers.IO with 64 // CoroutineDispatcher.limitedParallelism? Because, if we were to use Dispatchers.IO, we 65 // would share those threads with other dependencies using Dispatchers.IO. 66 // Using a dedicated thread pool we have guarantees only SystemUI is able to schedule 67 // code on those. 68 newFixedThreadPoolContext( 69 nThreads = Runtime.getRuntime().availableProcessors(), 70 name = "SystemUIBg" 71 ) 72 } else { 73 Dispatchers.IO 74 } 75 } 76 77 @Provides 78 @Background 79 @SysUISingleton bgCoroutineContextnull80 fun bgCoroutineContext( 81 @Tracing tracingCoroutineContext: CoroutineContext, 82 @Background bgCoroutineDispatcher: CoroutineDispatcher, 83 ): CoroutineContext { 84 return bgCoroutineDispatcher + tracingCoroutineContext 85 } 86 } 87