JetBrains / skiko

Kotlin Multiplatform bindings to Skia
Apache License 2.0
1.82k stars 118 forks source link

java.io.IOException: No such file or directory error when running compose apps inside Flatpak #731

Closed MMarco94 closed 1 month ago

MMarco94 commented 1 year ago

Library.kt unpacks libskiko-linux-x64.so on the home directory.

That's not allowed when running the app on Linux inside a Flatpak container, so Skiko won't initialize.

To reproduce, you need to run the app in a Flatpak container that either:

  1. Doesn't have access to the home directory
  2. Doesn't have write access to the home directory, and libskiko-linux-x64.so hasn't been unpacked previously

An example of a stacktrace is:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at androidx.compose.ui.awt.ComposeLayer.<init>(ComposeLayer.desktop.kt:92)
    at androidx.compose.ui.awt.ComposeWindowDelegate.<init>(ComposeWindowDelegate.desktop.kt:60)
    at androidx.compose.ui.awt.ComposeWindow.<init>(ComposeWindow.desktop.kt:61)
    at androidx.compose.ui.awt.ComposeWindow.<init>(ComposeWindow.desktop.kt:59)
    at androidx.compose.ui.window.Window_desktopKt$Window$3.invoke(Window.desktop.kt:178)
    at androidx.compose.ui.window.Window_desktopKt$Window$3.invoke(Window.desktop.kt:172)
    at androidx.compose.ui.window.Window_desktopKt$Window$10$1.invoke(Window.desktop.kt:403)
    at androidx.compose.ui.window.Window_desktopKt$Window$10$1.invoke(Window.desktop.kt:402)
    at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$2.invoke(AwtWindow.desktop.kt:74)
    at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$2.invoke(AwtWindow.desktop.kt:73)
    at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
    at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1105)
    at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:820)
    at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:842)
    at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:994)
    at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:519)
    at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.io.IOException: No such file or directory
    at java.base/java.io.UnixFileSystem.createFileExclusively(Native Method)
    at java.base/java.io.File.createTempFile(File.java:2170)
    at org.jetbrains.skiko.Library.unpackIfNeeded(Library.kt:37)
    at org.jetbrains.skiko.Library.findAndLoad(Library.kt:112)
    at org.jetbrains.skiko.Library.load(Library.kt:59)
    at org.jetbrains.skiko.SkiaLayer.<clinit>(SkiaLayer.awt.kt:32)
    ... 32 more
MMarco94 commented 1 year ago

If you stumble upon this issue, I "fixed" it with this workaround: https://github.com/MMarco94/tambourine-music-player/commit/26c9ad94b3464f12c6b4424aaae9c7041f79a7c2#diff-f00c79f3c8561c247ce8bbc1d341adc99052cad33d02b7e328b8ec21d4b35329

AlexeyTsvetkov commented 1 year ago

@MMarco94 I am not sure, what's wrong with extracting skiko during packaging? Compose Gradle plugin also extracts in Compose Gradle plugin, when packaging an application. The generated launcher passes the directory, containing skiko, by adding -Dskiko.library.path=... to the JVM args.

MMarco94 commented 1 year ago

Thanks for the pointer! I'll definitely look into how to better package my application.

However, I think the bug still stands. I'm packaging the app with the packageUberJarForCurrentOS task, and I think it should still work on a read-only home directory.

What other library do is unpackage the native binary on a temporary folder instead of the home.

okushnikov commented 1 month ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.