<lambda>null1 package kotlinx.coroutines.internal
2
3 import kotlinx.coroutines.*
4 import java.util.*
5 import kotlin.coroutines.*
6
7 /**
8 * Name of the boolean property that enables using of [FastServiceLoader].
9 */
10 private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"
11
12 // Lazy loader for the main dispatcher
13 internal object MainDispatcherLoader {
14
15 private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)
16
17 @JvmField
18 val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()
19
20 private fun loadMainDispatcher(): MainCoroutineDispatcher {
21 return try {
22 val factories = if (FAST_SERVICE_LOADER_ENABLED) {
23 MainDispatcherFactory::class.java.let { clz ->
24 FastServiceLoader.load(clz, clz.classLoader)
25 }
26 } else {
27 //We are explicitly using the
28 //`ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
29 //form of the ServiceLoader call to enable R8 optimization when compiled on Android.
30 ServiceLoader.load(
31 MainDispatcherFactory::class.java,
32 MainDispatcherFactory::class.java.classLoader
33 ).iterator().asSequence().toList()
34 }
35 factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
36 ?: MissingMainCoroutineDispatcher(null)
37 } catch (e: Throwable) {
38 // Service loader can throw an exception as well
39 MissingMainCoroutineDispatcher(e)
40 }
41 }
42 }
43
44 /**
45 * If anything goes wrong while trying to create main dispatcher (class not found,
46 * initialization failed, etc), then replace the main dispatcher with a special
47 * stub that throws an error message on any attempt to actually use it.
48 *
49 * @suppress internal API
50 */
51 @InternalCoroutinesApi
tryCreateDispatchernull52 public fun MainDispatcherFactory.tryCreateDispatcher(factories: List<MainDispatcherFactory>): MainCoroutineDispatcher =
53 try {
54 createDispatcher(factories)
55 } catch (cause: Throwable) {
56 MissingMainCoroutineDispatcher(cause, hintOnError())
57 }
58
59 /** @suppress */
60 @InternalCoroutinesApi
isMissingnull61 public fun MainCoroutineDispatcher.isMissing(): Boolean = this is MissingMainCoroutineDispatcher
62
63 private class MissingMainCoroutineDispatcher(
64 private val cause: Throwable?,
65 private val errorHint: String? = null
66 ) : MainCoroutineDispatcher(), Delay {
67
68 override val immediate: MainCoroutineDispatcher get() = this
69
70 override fun isDispatchNeeded(context: CoroutineContext): Boolean {
71 missing()
72 }
73
74 override suspend fun delay(time: Long) {
75 missing()
76 }
77
78 override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
79 missing()
80 }
81
82 override fun dispatch(context: CoroutineContext, block: Runnable) =
83 missing()
84
85 override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
86 missing()
87
88 private fun missing(): Nothing {
89 if (cause == null) {
90 throw IllegalStateException(
91 "Module with the Main dispatcher is missing. " +
92 "Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android'"
93 )
94 } else {
95 val message = "Module with the Main dispatcher had failed to initialize" + (errorHint?.let { ". $it" } ?: "")
96 throw IllegalStateException(message, cause)
97 }
98 }
99
100 override fun toString(): String = "Main[missing${if (cause != null) ", cause=$cause" else ""}]"
101 }
102
103 /**
104 * @suppress
105 */
106 @InternalCoroutinesApi
107 public object MissingMainCoroutineDispatcherFactory : MainDispatcherFactory {
108 override val loadPriority: Int
109 get() = -1
110
createDispatchernull111 override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher {
112 return MissingMainCoroutineDispatcher(null)
113 }
114 }