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