IJPL-166 enable coroutine dump a little bit later, log error

GitOrigin-RevId: 214a83e6855634ecc47c6cf8b17f4920336f729a
This commit is contained in:
Vladimir Krivosheev
2024-01-25 15:23:24 +01:00
committed by intellij-monorepo-bot
parent 082d393a4b
commit b6bbebcdae
5 changed files with 255 additions and 191 deletions

View File

@@ -4,7 +4,10 @@
@file:Suppress("RAW_RUN_BLOCKING") @file:Suppress("RAW_RUN_BLOCKING")
package com.intellij.platform.ide.bootstrap package com.intellij.platform.ide.bootstrap
import com.intellij.diagnostic.COROUTINE_DUMP_HEADER
import com.intellij.diagnostic.LoadingState import com.intellij.diagnostic.LoadingState
import com.intellij.diagnostic.dumpCoroutines
import com.intellij.diagnostic.enableCoroutineDump
import com.intellij.ide.* import com.intellij.ide.*
import com.intellij.ide.bootstrap.InitAppContext import com.intellij.ide.bootstrap.InitAppContext
import com.intellij.ide.gdpr.EndUserAgreement import com.intellij.ide.gdpr.EndUserAgreement
@@ -47,6 +50,7 @@ import com.intellij.util.PlatformUtils
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import com.intellij.util.io.createDirectories import com.intellij.util.io.createDirectories
import com.intellij.util.lang.ZipFilePool import com.intellij.util.lang.ZipFilePool
import com.jetbrains.JBR
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.VisibleForTesting import org.jetbrains.annotations.VisibleForTesting
@@ -178,13 +182,23 @@ internal suspend fun loadApp(app: ApplicationImpl,
} }
} }
val coroutineDebugJob = launch(CoroutineName("coroutine debug probes init")) {
enableCoroutineDump().onFailure { e ->
LOG.error("Cannot enable coroutine debug dump", e)
}
enableJstack()
}
asyncScope.launch { asyncScope.launch {
launch(CoroutineName("checkThirdPartyPluginsAllowed")) { // do not use launch here - don't overload CPU, let some room for JIT and other CPU-intensive tasks during start-up
coroutineDebugJob.join()
span("checkThirdPartyPluginsAllowed") {
checkThirdPartyPluginsAllowed() checkThirdPartyPluginsAllowed()
} }
// doesn't block app start-up // doesn't block app start-up
launch(CoroutineName("post app init tasks")) { span("post app init tasks") {
runPostAppInitTasks() runPostAppInitTasks()
} }
@@ -197,6 +211,17 @@ internal suspend fun loadApp(app: ApplicationImpl,
} }
} }
private suspend fun enableJstack() {
span("coroutine jstack configuration") {
JBR.getJstack()?.includeInfoFrom {
"""
$COROUTINE_DUMP_HEADER
${dumpCoroutines(stripDump = false)}
"""
}
}
}
private suspend fun preInitApp(app: ApplicationImpl, private suspend fun preInitApp(app: ApplicationImpl,
asyncScope: CoroutineScope, asyncScope: CoroutineScope,
initLafJob: Job, initLafJob: Job,

View File

@@ -26,9 +26,9 @@ private val LOG: Logger
get() = logger<IdeStartupWizard>() get() = logger<IdeStartupWizard>()
val isIdeStartupWizardEnabled: Boolean val isIdeStartupWizardEnabled: Boolean
get() = !ApplicationManagerEx.isInIntegrationTest() get() = !ApplicationManagerEx.isInIntegrationTest() &&
&& System.getProperty ("intellij.startup.wizard", "true").toBoolean() System.getProperty ("intellij.startup.wizard", "true").toBoolean() &&
&& IdeStartupExperiment.isExperimentEnabled() IdeStartupExperiment.isExperimentEnabled()
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
internal suspend fun runStartupWizard(isInitialStart: Job, app: Application) { internal suspend fun runStartupWizard(isInitialStart: Job, app: Application) {
@@ -174,9 +174,9 @@ private object IdeStartupExperiment {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private fun getGroupKind(group: Int) = when { private fun getGroupKind(group: Int) = when {
PlatformUtils.isIdeaUltimate() || PlatformUtils.isPyCharmPro() -> when { PlatformUtils.isIdeaUltimate() || PlatformUtils.isPyCharmPro() -> when (group) {
group in 0..7 -> GroupKind.Experimental in 0..7 -> GroupKind.Experimental
group == 8 || group == 9 -> GroupKind.Control 8, 9 -> GroupKind.Control
else -> GroupKind.Undefined else -> GroupKind.Undefined
} }
else -> when (group) { else -> when (group) {
@@ -186,12 +186,13 @@ private object IdeStartupExperiment {
} }
} }
private fun String.asBucket() = MathUtil.nonNegativeAbs(this.hashCode()) % 256 private fun asBucket(s: String) = MathUtil.nonNegativeAbs(s.hashCode()) % 256
private fun getBucket(): Int { private fun getBucket(): Int {
val deviceId = LOG.runAndLogException { val deviceId = LOG.runAndLogException {
DeviceIdManager.getOrGenerateId(object : DeviceIdManager.DeviceIdToken {}, "FUS") DeviceIdManager.getOrGenerateId(object : DeviceIdManager.DeviceIdToken {}, "FUS")
} ?: return 0 } ?: return 0
return deviceId.asBucket() return asBucket(deviceId)
} }
val experimentGroup by lazy { val experimentGroup by lazy {
@@ -204,7 +205,7 @@ private object IdeStartupExperiment {
experimentGroup experimentGroup
} }
val experimentGroupKind by lazy { val experimentGroupKind: GroupKind by lazy {
getGroupKind(experimentGroup) getGroupKind(experimentGroup)
} }

View File

@@ -0,0 +1,160 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ide.bootstrap
import com.intellij.accessibility.enableScreenReaderSupportIfNecessary
import com.intellij.ide.gdpr.EndUserAgreement
import com.intellij.idea.AppMode
import com.intellij.openapi.application.ConfigImportHelper
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.application.impl.RawSwingDispatcher
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.util.registry.EarlyAccessRegistryManager
import com.intellij.platform.diagnostic.telemetry.impl.span
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.withContext
import java.nio.file.Path
import java.util.concurrent.CancellationException
internal suspend fun importConfigIfNeeded(isHeadless: Boolean,
configImportNeededDeferred: Deferred<Boolean>,
lockSystemDirsJob: Job,
logDeferred: Deferred<Logger>,
args: List<String>,
targetDirectoryToImportConfig: Path?,
appStarterDeferred: Deferred<AppStarter>,
euaDocumentDeferred: Deferred<EndUserAgreement.Document?>,
initLafJob: Job): Job? {
if (isHeadless) {
importConfigHeadless(configImportNeededDeferred = configImportNeededDeferred,
lockSystemDirsJob = lockSystemDirsJob,
logDeferred = logDeferred,
args = args,
targetDirectoryToImportConfig = targetDirectoryToImportConfig,
appStarterDeferred = appStarterDeferred,
euaDocumentDeferred = euaDocumentDeferred)
return null
}
if (AppMode.isRemoteDevHost() || !configImportNeededDeferred.await()) {
return null
}
initLafJob.join()
val log = logDeferred.await()
importConfig(
args = args,
targetDirectoryToImportConfig = targetDirectoryToImportConfig ?: PathManager.getConfigDir(),
log = log,
appStarter = appStarterDeferred.await(),
euaDocumentDeferred = euaDocumentDeferred,
)
if (ConfigImportHelper.isNewUser()) {
enableNewUi(logDeferred)
if (isIdeStartupWizardEnabled) {
log.info("Will enter initial app wizard flow.")
val result = CompletableDeferred<Boolean>()
isInitialStart = result
return result
}
else {
return null
}
}
else {
return null
}
}
private suspend fun importConfig(args: List<String>,
targetDirectoryToImportConfig: Path,
log: Logger,
appStarter: AppStarter,
euaDocumentDeferred: Deferred<EndUserAgreement.Document?>,
headlessAutoImport: Boolean = false) {
if (headlessAutoImport) {
// headless AppStarters are not notified about config import
val veryFirstStartOnThisComputer = euaDocumentDeferred.await() != null
withContext(RawSwingDispatcher) {
try {
ConfigImportHelper.importConfigsTo(veryFirstStartOnThisComputer, targetDirectoryToImportConfig, args, log, true)
log.info("Automatic config import completed")
}
catch (e: UnsupportedOperationException) {
log.info("Automatic config import is not possible", e)
}
}
EarlyAccessRegistryManager.invalidate()
IconLoader.clearCache()
return
}
span("screen reader checking") {
runCatching {
enableScreenReaderSupportIfNecessary()
}.getOrLogException(log)
}
span("config importing") {
appStarter.beforeImportConfigs()
val veryFirstStartOnThisComputer = euaDocumentDeferred.await() != null
withContext(RawSwingDispatcher) {
ConfigImportHelper.importConfigsTo(veryFirstStartOnThisComputer, targetDirectoryToImportConfig, args, log)
}
appStarter.importFinished(targetDirectoryToImportConfig)
EarlyAccessRegistryManager.invalidate()
IconLoader.clearCache()
}
}
private suspend fun enableNewUi(logDeferred: Deferred<Logger>) {
if (System.getProperty("ide.experimental.ui") == null) {
try {
EarlyAccessRegistryManager.setAndFlush(mapOf("ide.experimental.ui" to "true"))
}
catch (e: CancellationException) {
throw e
}
catch (e: Throwable) {
logDeferred.await().error(e)
}
}
}
private suspend fun importConfigHeadless(configImportNeededDeferred: Deferred<Boolean>,
lockSystemDirsJob: Job,
logDeferred: Deferred<Logger>,
args: List<String>,
targetDirectoryToImportConfig: Path?,
appStarterDeferred: Deferred<AppStarter>,
euaDocumentDeferred: Deferred<EndUserAgreement.Document?>) {
if (!configImportNeededDeferred.await()) {
return
}
// make sure we lock the dir before writing
lockSystemDirsJob.join()
if (!ConfigImportHelper.isHeadlessAutomaticConfigImportAllowed()) {
enableNewUi(logDeferred)
}
else {
val log = logDeferred.await()
importConfig(
args = args,
targetDirectoryToImportConfig = targetDirectoryToImportConfig ?: PathManager.getConfigDir(),
log = log,
appStarter = appStarterDeferred.await(),
euaDocumentDeferred = euaDocumentDeferred,
headlessAutoImport = true
)
if (ConfigImportHelper.isNewUser()) {
enableNewUi(logDeferred)
}
}
}

View File

@@ -5,11 +5,9 @@
package com.intellij.platform.ide.bootstrap package com.intellij.platform.ide.bootstrap
import com.intellij.BundleBase import com.intellij.BundleBase
import com.intellij.accessibility.enableScreenReaderSupportIfNecessary
import com.intellij.diagnostic.* import com.intellij.diagnostic.*
import com.intellij.ide.* import com.intellij.ide.*
import com.intellij.ide.bootstrap.* import com.intellij.ide.bootstrap.*
import com.intellij.ide.gdpr.EndUserAgreement
import com.intellij.ide.instrument.WriteIntentLockInstrumenter import com.intellij.ide.instrument.WriteIntentLockInstrumenter
import com.intellij.ide.plugins.PluginManagerCore import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.idea.* import com.intellij.idea.*
@@ -22,10 +20,8 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.getOrLogException import com.intellij.openapi.diagnostic.getOrLogException
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.util.ShutDownTracker import com.intellij.openapi.util.ShutDownTracker
import com.intellij.openapi.util.SystemInfoRt import com.intellij.openapi.util.SystemInfoRt
import com.intellij.openapi.util.registry.EarlyAccessRegistryManager
import com.intellij.platform.diagnostic.telemetry.impl.OpenTelemetryConfigurator import com.intellij.platform.diagnostic.telemetry.impl.OpenTelemetryConfigurator
import com.intellij.platform.diagnostic.telemetry.impl.TelemetryManagerImpl import com.intellij.platform.diagnostic.telemetry.impl.TelemetryManagerImpl
import com.intellij.platform.diagnostic.telemetry.impl.span import com.intellij.platform.diagnostic.telemetry.impl.span
@@ -41,7 +37,6 @@ import com.intellij.util.lang.ZipFilePool
import com.jetbrains.JBR import com.jetbrains.JBR
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder import io.opentelemetry.sdk.OpenTelemetrySdkBuilder
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.CancellationException
import org.jetbrains.annotations.ApiStatus.Internal import org.jetbrains.annotations.ApiStatus.Internal
import java.awt.Toolkit import java.awt.Toolkit
import java.lang.invoke.MethodHandles import java.lang.invoke.MethodHandles
@@ -58,7 +53,6 @@ import java.util.function.BiConsumer
import java.util.function.BiFunction import java.util.function.BiFunction
import java.util.logging.ConsoleHandler import java.util.logging.ConsoleHandler
import java.util.logging.Level import java.util.logging.Level
import kotlin.concurrent.Volatile
import kotlin.system.exitProcess import kotlin.system.exitProcess
internal const val IDE_STARTED: String = "------------------------------------------------------ IDE STARTED ------------------------------------------------------" internal const val IDE_STARTED: String = "------------------------------------------------------ IDE STARTED ------------------------------------------------------"
@@ -89,6 +83,10 @@ private val commandProcessor: AtomicReference<(List<String>) -> Deferred<CliResu
internal var shellEnvDeferred: Deferred<Boolean?>? = null internal var shellEnvDeferred: Deferred<Boolean?>? = null
private set private set
@Volatile
@JvmField
internal var isInitialStart: CompletableDeferred<Boolean>? = null
// the main thread's dispatcher is sequential - use it with care // the main thread's dispatcher is sequential - use it with care
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
fun CoroutineScope.startApplication(args: List<String>, fun CoroutineScope.startApplication(args: List<String>,
@@ -133,6 +131,7 @@ fun CoroutineScope.startApplication(args: List<String>,
val initBaseLafJob = launch { val initBaseLafJob = launch {
initUi(initAwtToolkitJob = initAwtToolkitJob, isHeadless = isHeadless, asyncScope = this@startApplication) initUi(initAwtToolkitJob = initAwtToolkitJob, isHeadless = isHeadless, asyncScope = this@startApplication)
} }
if (!isHeadless) { if (!isHeadless) {
val initUiScale = launch { val initUiScale = launch {
if (SystemInfoRt.isMac) { if (SystemInfoRt.isMac) {
@@ -147,7 +146,9 @@ fun CoroutineScope.startApplication(args: List<String>,
} }
} }
scheduleShowSplashIfNeeded(lockSystemDirsJob = lockSystemDirsJob, initUiScale = initUiScale, appInfoDeferred = appInfoDeferred, scheduleShowSplashIfNeeded(lockSystemDirsJob = lockSystemDirsJob,
initUiScale = initUiScale,
appInfoDeferred = appInfoDeferred,
args = args) args = args)
scheduleUpdateFrameClassAndWindowIconAndPreloadSystemFonts(initAwtToolkitJob = initAwtToolkitJob, scheduleUpdateFrameClassAndWindowIconAndPreloadSystemFonts(initAwtToolkitJob = initAwtToolkitJob,
initUiScale = initUiScale, initUiScale = initUiScale,
@@ -201,67 +202,24 @@ fun CoroutineScope.startApplication(args: List<String>,
} }
} }
scheduleLoadSystemLibsAndLogInfoAndInitMacApp(logDeferred, appInfoDeferred, initLafJob, args, mainScope) scheduleLoadSystemLibsAndLogInfoAndInitMacApp(logDeferred = logDeferred,
appInfoDeferred = appInfoDeferred,
initUiDeferred = initLafJob,
args = args,
mainScope = mainScope)
val euaDocumentDeferred = async { loadEuaDocument(appInfoDeferred) } val euaDocumentDeferred = async { loadEuaDocument(appInfoDeferred) }
val configImportDeferred: Deferred<Job?> = async { val configImportDeferred: Deferred<Job?> = async {
if (isHeadless) { importConfigIfNeeded(isHeadless = isHeadless,
if (!configImportNeededDeferred.await()) { configImportNeededDeferred = configImportNeededDeferred,
return@async null lockSystemDirsJob = lockSystemDirsJob,
} logDeferred = logDeferred,
// make sure we lock the dir before writing
lockSystemDirsJob.join()
if (!ConfigImportHelper.isHeadlessAutomaticConfigImportAllowed()) {
enableNewUi(logDeferred)
}
else {
val log = logDeferred.await()
importConfig(
args = args, args = args,
targetDirectoryToImportConfig = targetDirectoryToImportConfig ?: PathManager.getConfigDir(), targetDirectoryToImportConfig = targetDirectoryToImportConfig,
log = log, appStarterDeferred = appStarterDeferred,
appStarter = appStarterDeferred.await(),
euaDocumentDeferred = euaDocumentDeferred, euaDocumentDeferred = euaDocumentDeferred,
headlessAutoImport = true initLafJob =initLafJob)
)
if (ConfigImportHelper.isNewUser()) {
enableNewUi(logDeferred)
}
}
return@async null
}
if (AppMode.isRemoteDevHost() || !configImportNeededDeferred.await()) {
return@async null
}
initLafJob.join()
val log = logDeferred.await()
importConfig(
args = args,
targetDirectoryToImportConfig = targetDirectoryToImportConfig ?: PathManager.getConfigDir(),
log = log,
appStarter = appStarterDeferred.await(),
euaDocumentDeferred = euaDocumentDeferred,
)
if (ConfigImportHelper.isNewUser()) {
enableNewUi(logDeferred)
if (isIdeStartupWizardEnabled) {
log.info("Will enter initial app wizard flow.")
val result = CompletableDeferred<Boolean>()
isInitialStart = result
result
}
else {
null
}
}
else {
null
}
} }
val pluginSetDeferred = async { val pluginSetDeferred = async {
@@ -295,7 +253,7 @@ fun CoroutineScope.startApplication(args: List<String>,
Class.forName(OpenTelemetrySdkBuilder::class.java.name, true, classLoader) Class.forName(OpenTelemetrySdkBuilder::class.java.name, true, classLoader)
} }
val appLoaded = launch { val appLoaded = async {
val initEventQueueJob = scheduleInitIdeEventQueue(initAwtToolkit = initAwtToolkitJob, isHeadless = isHeadless) val initEventQueueJob = scheduleInitIdeEventQueue(initAwtToolkit = initAwtToolkitJob, isHeadless = isHeadless)
checkSystemDirJob.join() checkSystemDirJob.join()
@@ -312,7 +270,7 @@ fun CoroutineScope.startApplication(args: List<String>,
ApplicationImpl(CoroutineScope(mainScope.coroutineContext.job).namedChildScope("Application"), isInternal) ApplicationImpl(CoroutineScope(mainScope.coroutineContext.job).namedChildScope("Application"), isInternal)
} }
val starter = loadApp(app = app, loadApp(app = app,
initAwtToolkitAndEventQueueJob = initEventQueueJob, initAwtToolkitAndEventQueueJob = initEventQueueJob,
pluginSetDeferred = pluginSetDeferred, pluginSetDeferred = pluginSetDeferred,
appInfoDeferred = appInfoDeferred, appInfoDeferred = appInfoDeferred,
@@ -322,25 +280,7 @@ fun CoroutineScope.startApplication(args: List<String>,
logDeferred = logDeferred, logDeferred = logDeferred,
appRegisteredJob = appRegisteredJob, appRegisteredJob = appRegisteredJob,
args = args.filterNot { CommandLineArgs.isKnownArgument(it) }) args = args.filterNot { CommandLineArgs.isKnownArgument(it) })
// out of appLoaded scope
this@startApplication.launch {
val isInitialStart = configImportDeferred.await()
// appLoaded not only provides starter, but also loads app, that's why it is here
IdeStartupWizardCollector.logExperimentState()
if (isInitialStart != null) {
LoadingState.compareAndSetCurrentState(LoadingState.COMPONENTS_LOADED, LoadingState.APP_READY)
val log = logDeferred.await()
runCatching {
span("startup wizard run") {
runStartupWizard(isInitialStart = isInitialStart, app = ApplicationManager.getApplication())
} }
}.getOrLogException(log)
}
executeApplicationStarter(starter = starter, args = args)
}
}
scheduleEnableCoroutineDumpAndJstack()
launch { launch {
// required for appStarter.prepareStart // required for appStarter.prepareStart
@@ -362,52 +302,31 @@ fun CoroutineScope.startApplication(args: List<String>,
appStarter.start(InitAppContext(appRegistered = appRegisteredJob, appLoaded = appLoaded)) appStarter.start(InitAppContext(appRegistered = appRegisteredJob, appLoaded = appLoaded))
} }
} }
}
private suspend fun enableNewUi(logDeferred: Deferred<Logger>) {
if (System.getProperty("ide.experimental.ui") == null) {
try {
EarlyAccessRegistryManager.setAndFlush(mapOf("ide.experimental.ui" to "true"))
}
catch (e: CancellationException) {
throw e
}
catch (e: Throwable) {
logDeferred.await().error(e)
}
}
}
@Volatile
@JvmField
internal var isInitialStart: CompletableDeferred<Boolean>? = null
private fun CoroutineScope.scheduleEnableCoroutineDumpAndJstack() {
if (!System.getProperty("idea.enable.coroutine.dump", "true").toBoolean()) {
return
}
// out of appLoaded scope
launch { launch {
span("coroutine debug probes init") { // starter is used later, but we need to wait for appLoaded completion
try { val starter = appLoaded.await()
enableCoroutineDump()
} val isInitialStart = configImportDeferred.await()
catch (ignore: NoClassDefFoundError) { // appLoaded not only provides starter, but also loads app, that's why it is here
// if for some reason, the class loader has ByteBuddy in the classpath launch {
// (it is an error, and should be fixed - our dev mode and production behaves correctly) if (ConfigImportHelper.isFirstSession()) {
} IdeStartupWizardCollector.logExperimentState()
catch (e: Exception) {
e.printStackTrace()
} }
} }
span("coroutine jstack configuration") {
JBR.getJstack()?.includeInfoFrom { if (isInitialStart != null) {
""" LoadingState.compareAndSetCurrentState(LoadingState.COMPONENTS_LOADED, LoadingState.APP_READY)
$COROUTINE_DUMP_HEADER val log = logDeferred.await()
${dumpCoroutines(stripDump = false)} runCatching {
""" span("startup wizard run") {
runStartupWizard(isInitialStart = isInitialStart, app = ApplicationManager.getApplication())
} }
}.getOrLogException(log)
} }
executeApplicationStarter(starter = starter, args = args)
} }
} }
@@ -474,8 +393,9 @@ private fun CoroutineScope.scheduleLoadSystemLibsAndLogInfoAndInitMacApp(logDefe
} }
} }
fun processWindowsLauncherCommandLine(currentDirectory: String, args: Array<String>): Int = fun processWindowsLauncherCommandLine(currentDirectory: String, args: Array<String>): Int {
EXTERNAL_LISTENER.apply(currentDirectory, args) return EXTERNAL_LISTENER.apply(currentDirectory, args)
}
@get:Internal @get:Internal
val isImplicitReadOnEDTDisabled: Boolean val isImplicitReadOnEDTDisabled: Boolean
@@ -504,48 +424,6 @@ private suspend fun runPreAppClass(args: List<String>, classBeforeAppProperty: S
} }
} }
private suspend fun importConfig(args: List<String>,
targetDirectoryToImportConfig: Path,
log: Logger,
appStarter: AppStarter,
euaDocumentDeferred: Deferred<EndUserAgreement.Document?>,
headlessAutoImport: Boolean = false) {
if (headlessAutoImport) {
// headless AppStarters are not notified about config import
val veryFirstStartOnThisComputer = euaDocumentDeferred.await() != null
withContext(RawSwingDispatcher) {
try {
ConfigImportHelper.importConfigsTo(veryFirstStartOnThisComputer, targetDirectoryToImportConfig, args, log, true)
log.info("Automatic config import completed")
}
catch (e: UnsupportedOperationException) {
log.info("Automatic config import is not possible", e)
}
}
EarlyAccessRegistryManager.invalidate()
IconLoader.clearCache()
return
}
span("screen reader checking") {
runCatching {
enableScreenReaderSupportIfNecessary()
}.getOrLogException(log)
}
span("config importing") {
appStarter.beforeImportConfigs()
val veryFirstStartOnThisComputer = euaDocumentDeferred.await() != null
withContext(RawSwingDispatcher) {
ConfigImportHelper.importConfigsTo(veryFirstStartOnThisComputer, targetDirectoryToImportConfig, args, log)
}
appStarter.importFinished(targetDirectoryToImportConfig)
EarlyAccessRegistryManager.invalidate()
IconLoader.clearCache()
}
}
private fun CoroutineScope.configureJavaUtilLogging(): Job { private fun CoroutineScope.configureJavaUtilLogging(): Job {
return launch(CoroutineName("console logger configuration")) { return launch(CoroutineName("console logger configuration")) {
val rootLogger = java.util.logging.Logger.getLogger("") val rootLogger = java.util.logging.Logger.getLogger("")

View File

@@ -29,8 +29,8 @@ fun isCoroutineDumpHeader(line: String): Boolean {
return line == COROUTINE_DUMP_HEADER || line == COROUTINE_DUMP_HEADER_STRIPPED return line == COROUTINE_DUMP_HEADER || line == COROUTINE_DUMP_HEADER_STRIPPED
} }
fun enableCoroutineDump() { fun enableCoroutineDump(): Result<Unit> {
runCatching { return runCatching {
DebugProbes.enableCreationStackTraces = false DebugProbes.enableCreationStackTraces = false
DebugProbes.install() DebugProbes.install()
} }