How to start another instance of my app within the app?

Sorry, I wanted to highlight that you can run more than one instance of the app, which I wasn’t sure you have tried. At this point, I just want to reiterate, nothing in the sandbox is stopping you from running more than one app process. I would suggest trying to debug what the app does when it tries to start another instance. Is it in fact calling the right executable?

1 Like

I’d add some debug code, does your app perhaps not resolve the $SNAP variable internally etc etc …

something very weird is happening. I printed the output of the $SNAP/bin/FireflyLuciferin command to understand why it doesn’t work.

if I run my java binary using your suggestion within my app I get this output:

Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a source-file program)

 Arguments following the main class, source file, -jar <jarfile>,
 -m or --module <module>/<mainclass> are passed as the arguments to
 main class.

 where options include:

    -cp <class search path of directories and zip/jar files>
    -classpath <class search path of directories and zip/jar files>
    --class-path <class search path of directories and zip/jar files>
                  A : separated list of directories, JAR archives,
                  and ZIP archives to search for class files.
    -p <module path>
    --module-path <module path>...
                  A : separated list of elements, each element is a file path
                  to a module or a directory containing modules. Each module is either
                  a modular JAR or an exploded-module directory.
    --upgrade-module-path <module path>...
                  A : separated list of elements, each element is a file path
                  to a module or a directory containing modules to replace
                  upgradeable modules in the runtime image. Each module is either
                  a modular JAR or an exploded-module directory.
    --add-modules <module name>[,<module name>...]
                  root modules to resolve in addition to the initial module.
                  <module name> can also be ALL-DEFAULT, ALL-SYSTEM,
                  ALL-MODULE-PATH.
    --enable-native-access <module name>[,<module name>...]
                  allow code in modules to access code and data outside the Java runtime.
                  <module name> can also be ALL-UNNAMED to indicate code on the class path.
    --list-modules
                  list observable modules and exit
    -d <module name>
    --describe-module <module name>
                  describe a module and exit
    --dry-run     create VM and load main class but do not execute main method.
                  The --dry-run option may be useful for validating the
                  command-line options such as the module system configuration.
    --validate-modules
                  validate all modules and exit
                  The --validate-modules option may be useful for finding
                  conflicts and other errors with modules on the module path.
    -D<name>=<value>
                  set a system property
    -verbose:[class|module|gc|jni]
                  enable verbose output for the given subsystem
    -version      print product version to the error stream and exit
    --version     print product version to the output stream and exit
    -showversion  print product version to the error stream and continue
    --show-version
                  print product version to the output stream and continue
    --show-module-resolution
                  show module resolution output during startup
    -? -h -help
                  print this help message to the error stream
    --help        print this help message to the output stream
    -X            print help on extra options to the error stream
    --help-extra  print help on extra options to the output stream
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  enable assertions with specified granularity
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  disable assertions with specified granularity
    -esa | -enablesystemassertions
                  enable system assertions
    -dsa | -disablesystemassertions
                  disable system assertions
    -agentlib:<libname>[=<options>]
                  load native agent library <libname>, e.g. -agentlib:jdwp
                  see also -agentlib:jdwp=help
    -agentpath:<pathname>[=<options>]
                  load native agent library by full pathname
    -javaagent:<jarpath>[=<options>]
                  load Java programming language agent, see java.lang.instrument
    -splash:<imagepath>
                  show splash screen with specified image
                  HiDPI scaled images are automatically supported and used
                  if available. The unscaled image filename, e.g. image.ext,
                  should always be passed as the argument to the -splash option.
                  The most appropriate scaled image provided will be picked up
                  automatically.
                  See the SplashScreen API documentation for more information
    @argument files
                  one or more argument files containing options
    --disable-@files
                  prevent further argument file expansion
    --enable-preview
                  allow classes to depend on preview features of this release
To specify an argument for a long option, you can use --<name>=<value> or
--<name> <value>.

it is printing the “java” command output. but I am simply running $SNAP/bin/FireflyLuciferin

My software works native, works with flatpak, what is the difference with snap?

my $SNAP/bin/FireflyLuciferin is a binary that doesn’t need the JDK to run because it is generated with jpackage.

Well, what did you change ? (Both our suggestions were rather broad without any specific code asks)

I was personally meaning you should add some print code that prints the environment vars in the function that would spawn the second instance so you can see if $SNAP is actually set… And I guess @mborzecki1 meant you should add something similar to print out the actual command called to see if that is the right executable…

I simply printed the output of the $SNAP/bin/FireflyLuciferin command

before running that command from my app, I resolve $SNAP variable by getting the “SNAP” system env variable. this variable is resolved in “/snap/fireflyluciferin/x1”

once I resolved that variable I call this command via java “/snap/fireflyluciferin/x1/bin/FireflyLuciferin”

with a simple Runtime.getRuntime().exec(“/snap/fireflyluciferin/x1/bin/FireflyLuciferin”)

The output of that command is completely weird. it’s the same of the output of the “java” command

I sincerely feel out of luck. I have developed a pretty complex software and I’m not able to restart it with snap, this must means something :smiley:

I would consider it a bug in snap, probably it works with other software, but it doesn’t work with software made with java jpackage

Just out of curiosity, what happens if you open the file with Nano. Is it actually an executable image, or is it potentially replaced with a shellscript or similar?

I double checked it, it’s a binary.

Well, my theory is that the bundled java interpreter shipped inside your binary likely drops the environment before execution of the bundled jar, this is why I asked to change the actual function you use to open the second instance (I highly doubt it has anything to do with snaps but rather with the java packaging, note that there are many java apps in the store (though typically they simply ship the jar and just use the java runtime to execute it))

Shipping the jar is considered the old way of releasing java apps. It’s stil preferable for some server apps, but it’s certainly not preferable for end users desktop apps.

This thing breaks a lot of features on my app.

Do you have other ideas on possible alternatives that may fix it?

I sincerely don’t think that it’s a java problem because this thing does not happen elsewhere if not inside the snap ecosystem.

You mean beyond actually researching the reason by adding a few prints to the function? Not really, I think we have reached the limit of guessing based on the data we have, further research requires some more information at least…

What do you mean for adding print to the function? :slight_smile: I have printed the input, I have printed the output of the function, what else can I print to help in debugging it?

I can’t print inside the Runtime.getRuntime().exec(“/snap/fireflyluciferin/x1/bin/FireflyLuciferin”) function. That’s a java one and recompiling java is a bit tedious.

My app is not spawned because I have a “starting” log in the very beginning of the app and that lot is never printed. So Runtime.getRuntime().exec(“/snap/fireflyluciferin/x1/bin/FireflyLuciferin”) fails to start the app.

Does snap block apps that is named differently from the appid?

My appid is fireflyluciferin but the binary is FireflyLuciferin. This isn’t a problem for snap right?

No, you can launch any binary within the constraints of the selected interface plugs (which should be fine since your main app runs with the selected ones already).

And as seen above you can run the app twice from the sandbox when you start it from a snap run --shell session, i.e. the snap system is not in your way here, it must be something with the way your app launches it… If you want to be really sure, you can run the snappy-debug tool (from the same named snap) in a second terminal to see if there are any denials the moment you click the launch button in your main app…

this is recorded when I click the spawn button on my app:

I don’t know if this helps, it doesn’t help me :confused: the comm=“FireflyLuciferi” seems weird too…

My app is called FireflyLuciferin why snappy debug prints FireflyLuciferi?

It processes the systemd journal, if systemd decides to cut off the name in the log, this is what snappy-debug sees, so the cut off name is nothing to worry about…

The denials do not look fatal, I assume you get the same ones when starting the app (and not spawning a new instance) normally…

The command name is probably truncated.

The denials looks like noise. I see them as well when simply starting the app:

[67888.387453] audit: type=1400 audit(1733217134.451:5761): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/proc/cgroups" pid=286752 comm="FireflyLuciferi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[67888.387506] audit: type=1400 audit(1733217134.451:5762): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/sys/kernel/mm/hugepages/" pid=286752 comm="FireflyLuciferi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[67888.387548] audit: type=1400 audit(1733217134.451:5763): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/sys/kernel/mm/transparent_hugepage/shmem_enabled" pid=286752 comm="FireflyLuciferi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[67888.387772] audit: type=1400 audit(1733217134.451:5764): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/proc/286752/coredump_filter" pid=286752 comm="FireflyLuciferi" requested_mask="wr" denied_mask="wr" fsuid=1000 ouid=1000
[67888.387775] audit: type=1400 audit(1733217134.451:5765): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/proc/286752/coredump_filter" pid=286752 comm="FireflyLuciferi" requested_mask="wr" denied_mask="wr" fsuid=1000 ouid=1000
[67888.388946] audit: type=1400 audit(1733217134.451:5766): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/proc/sys/vm/max_map_count" pid=286752 comm="FireflyLuciferi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[67888.477920] audit: type=1400 audit(1733217134.541:5767): apparmor="DENIED" operation="open" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/proc/286752/net/if_inet6" pid=286752 comm="FireflyLuciferi" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
[67888.693524] audit: type=1400 audit(1733217134.758:5768): apparmor="DENIED" operation="mkdir" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/home/maciek/.openjfx/" pid=286752 comm="QuantumRenderer" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
[67888.693531] audit: type=1400 audit(1733217134.758:5769): apparmor="DENIED" operation="mkdir" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/home/maciek/.openjfx/" pid=286752 comm="QuantumRenderer" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
[67888.776445] audit: type=1400 audit(1733217134.841:5770): apparmor="DENIED" operation="mkdir" class="file" profile="snap.fireflyluciferin.fireflyluciferin" name="/home/maciek/.openjfx/" pid=286752 comm="QuantumRenderer" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000

In any case, if it is possible to start the application directly more than once from the shell but not when invoked from your app, perhaps some part of the ‘runtime’ has been modified by jpackage. Maybe it sets some environment variables that are carried through exec.

1 Like

double checked it and I can confirm.

This is a very good point. It’s possible that jpackage adds something but I sincerely don’t know what can produce this kind of error because my app does not start at all… my app starts even with a simple java -jar jarname

You can try running with strace, capture execve syscalls:

sudo snap run --strace='-vf -e execve -u <youruser>' <your-snap-app>