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.launcher3.util.coroutines
18 
19 import kotlinx.coroutines.CoroutineDispatcher
20 import kotlinx.coroutines.DelicateCoroutinesApi
21 import kotlinx.coroutines.Dispatchers
22 import kotlinx.coroutines.newFixedThreadPoolContext
23 
24 interface DispatcherProvider {
25     val default: CoroutineDispatcher
26     val background: CoroutineDispatcher
27     val main: CoroutineDispatcher
28     val unconfined: CoroutineDispatcher
29 }
30 
31 object ProductionDispatchers : DispatcherProvider {
32     private val bgDispatcher = CoroutinesHelper.bgDispatcher()
33 
34     override val default: CoroutineDispatcher = Dispatchers.Default
35     override val background: CoroutineDispatcher = bgDispatcher
36     override val main: CoroutineDispatcher = Dispatchers.Main
37     override val unconfined: CoroutineDispatcher = Dispatchers.Unconfined
38 }
39 
40 private object CoroutinesHelper {
41     /**
42      * Default Coroutine dispatcher for background operations.
43      *
44      * Note that this is explicitly limiting the number of threads. In the past, we used
45      * [Dispatchers.IO]. This caused >40 threads to be spawned, and a lot of thread list lock
46      * contention between then, eventually causing jank.
47      */
48     @OptIn(DelicateCoroutinesApi::class)
bgDispatchernull49     fun bgDispatcher(): CoroutineDispatcher {
50         // Why a new ThreadPool instead of just using Dispatchers.IO with
51         // CoroutineDispatcher.limitedParallelism? Because, if we were to use Dispatchers.IO, we
52         // would share those threads with other dependencies using Dispatchers.IO.
53         // Using a dedicated thread pool we have guarantees only Launcher is able to schedule
54         // code on those.
55         return newFixedThreadPoolContext(
56             nThreads = Runtime.getRuntime().availableProcessors(),
57             name = "LauncherBg",
58         )
59     }
60 }
61