• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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 }