diff --git a/crowpi/crowpi.sh b/crowpi/crowpi.sh index 9aad2da..7a19deb 100644 --- a/crowpi/crowpi.sh +++ b/crowpi/crowpi.sh @@ -97,6 +97,7 @@ install -Dm 0644 /tmp/resources/wallpaper/wallpaper-static.jpg /opt/fhnw/wallpap # Deploy java-kiosk helper script for JavaFX apps sudo install -Dm 0755 /tmp/resources/java/java-kiosk.py /usr/local/bin/java-kiosk +sudo install -Dm 0755 /tmp/resources/java/java-last-kiosk.py /usr/local/bin/java-last-kiosk # Deploy a music sample sudo install -Dm 0644 /tmp/resources/music/StarTrekTheme.mp3 /home/pi/Music/StarTrekTheme.mp3 diff --git a/crowpi/resources/java/java-kiosk.py b/crowpi/resources/java/java-kiosk.py index 69a7bff..0e15f95 100644 --- a/crowpi/resources/java/java-kiosk.py +++ b/crowpi/resources/java/java-kiosk.py @@ -1,13 +1,15 @@ #!/usr/bin/env python3 import argparse +import json import logging import os import shutil import signal import subprocess +import sys import time -# Absolute path to Gluon JavaFX directory +# Hardcoded configuration values SYSTEM_INIT_BIN = "/usr/sbin/init" DETECT_PRIMARY_CARD_BIN = "/usr/local/bin/detect-primary-card" GLUON_JAVAFX_PATH = "/opt/javafx-sdk" @@ -37,7 +39,7 @@ def run(self): # Launch JVM with patched options self._logger.debug('Launching JVM with previously determined arguments...') - self._logger.debug(' '.join(self._args)) + self._logger.debug(' '.join(*self._args)) self._run_process(*self._args, **self._kwargs) # JVM has exited, proceed with shutdown @@ -117,7 +119,7 @@ def jvm_property(data): # Parse known arguments and preserve others -parser = argparse.ArgumentParser(description='Gluon JavaFX Kiosk Launcher', allow_abbrev=False) +parser = argparse.ArgumentParser(description='JavaFX Kiosk Launcher', allow_abbrev=False) parser.add_argument('--add-modules', default='') parser.add_argument('-p', '--module-path', default='') args, unknown_args = parser.parse_known_args() @@ -223,6 +225,22 @@ def jvm_property(data): jvm_args.extend(unknown_args) logger.debug('Final JVM arguments: %s', jvm_args) +# Attempt to store arguments of current java-kiosk invocation for java-last-kiosk +try: + if not os.environ.get('JAVA_KIOSK_VOLATILE'): + persistence_path = os.path.join(os.path.expanduser('~'), '.java-last-kiosk') + logger.debug('Determined path to last-java-kiosk persistence file: %s', persistence_path) + with open(persistence_path, 'w') as persistence_file: + json.dump({ + 'cwd': os.getcwd(), + 'args': sys.argv, + }, persistence_file) + logger.debug('Successfully persisted current invocation for last-java-kiosk') + else: + logger.debug('Skipping update of last-java-kiosk persistence file due to volatile mode') +except Exception as exc: + logger.warning('Could not store current java-kiosk invocation for java-last-kiosk: %s', exc) + # Run application in kiosk mode runner = Runner([jvm_path] + jvm_args, env=jvm_env, logger=logger) runner.run() diff --git a/crowpi/resources/java/java-last-kiosk.py b/crowpi/resources/java/java-last-kiosk.py new file mode 100644 index 0000000..29b62c9 --- /dev/null +++ b/crowpi/resources/java/java-last-kiosk.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +import argparse +import json +import logging +import os +import shlex +import shutil +import sys + +# Hardcoded configuration values +JAVA_LAST_KIOSK_LOG = "/tmp/java-last-kiosk.log" + +# Parse CLI arguments +parser = argparse.ArgumentParser(description='JavaFX Last Kiosk Launcher', allow_abbrev=False) +parser.add_argument('-d', '--debug', action='store_true', help='Enable debug logging') +parser.add_argument('-n', '--dry-run', action='store_true', help='Only output command, do not execute') +args = parser.parse_args() + +# Ensure we are running as root +if os.geteuid() != 0: + parser.error("Unable to execute 'java-kiosk' without running as root") + +# Initialize formatter for unified debug logs +formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') + +# Initialize stream handler for logging, only visible when debug argument was given +streamHandler = logging.StreamHandler() +streamHandler.setFormatter(formatter) +streamHandler.setLevel(logging.DEBUG if args.debug else logging.INFO) + +# Initialize file handler for logging, always active +fileHandler = logging.FileHandler(JAVA_LAST_KIOSK_LOG, mode='w') +fileHandler.setFormatter(formatter) +fileHandler.setLevel(logging.DEBUG) + +# Initialize logging +logger = logging.getLogger('java-kiosk') +logger.addHandler(streamHandler) +logger.addHandler(fileHandler) +logger.setLevel(logging.DEBUG) + +# Search for absolute path of java-kiosk +java_kiosk_path = shutil.which('java-kiosk') +if java_kiosk_path is None: + parser.error("Unable to find 'java-kiosk' binary in current PATH") +logger.debug("Found path to 'java-kiosk' helper script: %s", java_kiosk_path) + +# Determine path to persistence file +persistence_path = os.path.join(os.path.expanduser('~'), '.java-last-kiosk') +logger.debug('Determined path to last-java-kiosk persistence file: %s', persistence_path) + +# Parse persistence file as JSON to determine arguments +try: + with open(persistence_path, 'r') as persistence_file: + java_kiosk_data = json.load(persistence_file) +except Exception as exc: + logger.error("Unable to open persistence file: %s", exc) + logger.error("Please ensure that 'java-kiosk' was executed successfully before") + parser.error("Unable to continue, arguments for previous 'java-kiosk' invocation are missing") + +# Log previously used java-kiosk arguments +logger.debug("Determined previous 'java-kiosk' working directory: %s", java_kiosk_data['cwd']) +logger.debug("Determined previous 'java-kiosk' arguments: %s", java_kiosk_data['args']) + +# Either execute java-kiosk or output final command +if not args.dry_run: + # Adjust working directory + logger.debug('Switching work directory to previous location: %s', java_kiosk_data['cwd']) + os.chdir(java_kiosk_data['cwd']) + + # Modify environment for java-kiosk to skip persistence update and optionally enable debug + java_kiosk_env = os.environ.copy() + java_kiosk_env['JAVA_KIOSK_VOLATILE'] = 'true' + java_kiosk_env['JAVA_KIOSK_DEBUG'] = 'true' if args.debug else '' + logger.debug("Patched environment for 'java-kiosk': %s", java_kiosk_env) + + # Use execve() to replace current process with java-kiosk + exec_binary, exec_argv = java_kiosk_data['args'][0], java_kiosk_data['args'] + logger.debug("Executing into [%s] using previous argv: %s", exec_binary, exec_argv) + os.execve(exec_binary, exec_argv, java_kiosk_env) +else: + print(' '.join(map(lambda arg: shlex.quote(arg), java_kiosk_data['args'])))