blob: 5b2b9ff68c3088d84bf5abea69e2bd42e316b38a [file] [log] [blame]
Roman Elizarovbf9509d2020-02-14 15:52:10 +03001/*
Aurimas Liutikascd3cb312021-05-12 21:56:16 +00002 * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarovbf9509d2020-02-14 15:52:10 +03003 */
4
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +03005package kotlinx.coroutines.internal
6
7import kotlinx.coroutines.*
8import java.util.*
9import kotlin.coroutines.*
10
Wojtek Kalicińskib9b7d822019-05-30 14:17:51 +020011/**
12 * Name of the boolean property that enables using of [FastServiceLoader].
13 */
14private const val FAST_SERVICE_LOADER_PROPERTY_NAME = "kotlinx.coroutines.fast.service.loader"
15
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030016// Lazy loader for the main dispatcher
17internal object MainDispatcherLoader {
Wojtek Kalicińskib9b7d822019-05-30 14:17:51 +020018
19 private val FAST_SERVICE_LOADER_ENABLED = systemProp(FAST_SERVICE_LOADER_PROPERTY_NAME, true)
20
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030021 @JvmField
22 val dispatcher: MainCoroutineDispatcher = loadMainDispatcher()
23
24 private fun loadMainDispatcher(): MainCoroutineDispatcher {
25 return try {
Wojtek Kalicińskib9b7d822019-05-30 14:17:51 +020026 val factories = if (FAST_SERVICE_LOADER_ENABLED) {
Vsevolod Tolstopyatove60ec8e2019-12-12 12:10:21 +030027 FastServiceLoader.loadMainDispatcherFactory()
Wojtek Kalicińskib9b7d822019-05-30 14:17:51 +020028 } else {
Vsevolod Tolstopyatove60ec8e2019-12-12 12:10:21 +030029 // We are explicitly using the
30 // `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
31 // form of the ServiceLoader call to enable R8 optimization when compiled on Android.
Wojtek Kalicińskib9b7d822019-05-30 14:17:51 +020032 ServiceLoader.load(
33 MainDispatcherFactory::class.java,
34 MainDispatcherFactory::class.java.classLoader
35 ).iterator().asSequence().toList()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030036 }
Roman Elizarovbf9509d2020-02-14 15:52:10 +030037 @Suppress("ConstantConditionIf")
Aurimas Liutikascd3cb312021-05-12 21:56:16 +000038 factories.maxBy { it.loadPriority }?.tryCreateDispatcher(factories)
Roman Elizarovbf9509d2020-02-14 15:52:10 +030039 ?: createMissingDispatcher()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030040 } catch (e: Throwable) {
41 // Service loader can throw an exception as well
Roman Elizarovbf9509d2020-02-14 15:52:10 +030042 createMissingDispatcher(e)
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030043 }
44 }
45}
46
47/**
48 * If anything goes wrong while trying to create main dispatcher (class not found,
49 * initialization failed, etc), then replace the main dispatcher with a special
50 * stub that throws an error message on any attempt to actually use it.
Vsevolod Tolstopyatov16166762018-12-18 19:13:35 +030051 *
52 * @suppress internal API
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030053 */
54@InternalCoroutinesApi
55public fun MainDispatcherFactory.tryCreateDispatcher(factories: List<MainDispatcherFactory>): MainCoroutineDispatcher =
56 try {
57 createDispatcher(factories)
58 } catch (cause: Throwable) {
Roman Elizarovbf9509d2020-02-14 15:52:10 +030059 createMissingDispatcher(cause, hintOnError())
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030060 }
61
62/** @suppress */
63@InternalCoroutinesApi
64public fun MainCoroutineDispatcher.isMissing(): Boolean = this is MissingMainCoroutineDispatcher
65
Roman Elizarovbf9509d2020-02-14 15:52:10 +030066// R8 optimization hook, not const on purpose to enable R8 optimizations via "assumenosideeffects"
67@Suppress("MayBeConstant")
68private val SUPPORT_MISSING = true
69
70@Suppress("ConstantConditionIf")
71private fun createMissingDispatcher(cause: Throwable? = null, errorHint: String? = null) =
72 if (SUPPORT_MISSING) MissingMainCoroutineDispatcher(cause, errorHint) else
73 cause?.let { throw it } ?: throwMissingMainDispatcherException()
74
75internal fun throwMissingMainDispatcherException(): Nothing {
76 throw IllegalStateException(
77 "Module with the Main dispatcher is missing. " +
78 "Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android' " +
79 "and ensure it has the same version as 'kotlinx-coroutines-core'"
80 )
81}
82
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030083private class MissingMainCoroutineDispatcher(
84 private val cause: Throwable?,
85 private val errorHint: String? = null
86) : MainCoroutineDispatcher(), Delay {
87
88 override val immediate: MainCoroutineDispatcher get() = this
89
Roman Elizarov20341f22020-10-09 16:40:15 +030090 override fun isDispatchNeeded(context: CoroutineContext): Boolean =
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030091 missing()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030092
Roman Elizarov20341f22020-10-09 16:40:15 +030093 override suspend fun delay(time: Long) =
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030094 missing()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030095
Roman Elizarov20341f22020-10-09 16:40:15 +030096 override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle =
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030097 missing()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +030098
99 override fun dispatch(context: CoroutineContext, block: Runnable) =
100 missing()
101
102 override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) =
103 missing()
104
105 private fun missing(): Nothing {
106 if (cause == null) {
Roman Elizarovbf9509d2020-02-14 15:52:10 +0300107 throwMissingMainDispatcherException()
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +0300108 } else {
109 val message = "Module with the Main dispatcher had failed to initialize" + (errorHint?.let { ". $it" } ?: "")
110 throw IllegalStateException(message, cause)
111 }
112 }
113
Roman Elizarovb7d65182020-07-16 19:31:13 +0300114 override fun toString(): String = "Dispatchers.Main[missing${if (cause != null) ", cause=$cause" else ""}]"
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +0300115}
116
Vsevolod Tolstopyatov89d43af2018-12-18 16:26:58 +0300117/**
118 * @suppress
119 */
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +0300120@InternalCoroutinesApi
121public object MissingMainCoroutineDispatcherFactory : MainDispatcherFactory {
122 override val loadPriority: Int
123 get() = -1
124
125 override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher {
sokolova15b63452019-01-28 11:43:44 +0300126 return MissingMainCoroutineDispatcher(null)
Vsevolod Tolstopyatov4327b212018-12-17 19:49:12 +0300127 }
Vsevolod Tolstopyatov6d1a6e32020-02-18 15:28:00 +0300128}