InkBox GUI user apps - Quill-OS/quill GitHub Wiki
This page describes the internals of InkBox GUI's user applications
feature.
This GUI feature permits the user to run digitally signed external Qt/FB
applications available at
https://github.com/Kobo-InkBox/user-applications or
http://pkgs-inkbox.duckdns.org:25560/applications.
User applications in are executed in their own chroot jail as an
unpriviledged user, to prevent external access to parts of the
filesystem and increase security. They are also mounted read-only, with
some exceptions.
Just extract the application to where you mounted the ereader via USB in the .apps
folder. Your .apps
folder should look like:
-
.apps.json
- optional, should generate itself after uploading your first app -
koreader
- folder that you extracted, inside it are-
koreader
- folder in which should be nothing when you attach it as a usb device. Don't put things in here -
app.json
- file that contains data about the app -
koreader.isa
- compressed app package -
koreader.isa.dgst
- signed key for the app
-
This is how it should look. Check it if your program extracted it in that way
App packages have the .isa
extension. Signature files (digests) have
the .isa.dgst
extension. A standard application package layout will
look like this:
.
├── app-bin
│ └── SampleApp
│ └── SampleApp.sh
├── app-data
├── app-lib
│ └── libzip.so
├── app-misc
│ └── SampleApp.png
├── app-temp
├── dev
├── etc
├── mnt
├── proc
├── usr
├── sys
├── system-bin
├── system-lib
└── system-onboard
This directory contains the application's binaries.
Note: The application's main binary must have the same name as
the application's name, matching case. For example, if your app is
called SampleApp
, the main binary must be called SampleApp
.
Applications can access this location at /app-bin
.
This directory contains the only read-write part of the extension
package. It is actually a bind mount of the related path
.apps-data/
in the exported USB mass storage. Applications
can store their user data, such as preferences, files and statistics,
there.
Applications can access this location at /app-data
.
This directory contains the libraries the application needs to have to
function properly. If it is based on Qt, there is no need to bundle it
in there, as it will be provided in the system-lib
directory. In this
example, the application requires libzip.so
, so it has been put there.
LD_LIBRARY_PATH
environment variable is automatically adjusted by the
main launch script.
Applications can access this location at /app-lib
.
This directory contains miscellanous data about the application, such as its icon.
This directory contains a mounted tmpfs
filesystem that the
application can use to store temporary data, such as files, sockets or
cache. Please note that the maximum storage space in this directory is
32 MiB, considering the low RAM amount the devices InkBox OS runs on
generally have.
This directory contains a mounted sysfs
filesystem used by the chroot.
This directory contains a mounted devtmpfs
filesystem used by the
chroot.
This directory contains a mounted proc
filesystem used by the chroot.
This directory contains a mounted tmpfs
filesystem used by the chroot.
This directory contains a mounted tmpfs
filesystem used by the chroot,
namely for printing to the framebuffer.
This directory contains a mounted tmpfs
. It's needed because of time
zones.
This directory contains a mounted tmpfs
. Only needed if additional
input devices are needed (udev).
This directory contains the system's Qt libs and are made available so
that the application can launch.
Applications can access this location at /system-lib
.
This directory contains the system's binaries made available to the
application (e.g. BusyBox).
Applications can access this location at /system-bin
.
The main Qt GUI will launch the application in the chroot jail as an
unpriviledged user, based on its JSON file's ExecPath
property. Once
the program has finished running, the GUI will restart itself.
The app.json
file, located outside of the main application package but
extracted in the same folder, contains information about the
application, how to run it and what system features it requires that
will be parsed by the GUI. A sample app.json
may look like this:
{
"app": {
"Author": "John Doe",
"AuthorContact": "[email protected]",
"Enabled": true,
"ExecPath": "/app-bin/SampleApp",
"IconPath": "/app-misc/SampleApp.png",
"Name": "SampleApp",
"SupportedDevices": [ "all" ],
"RequiredFeatures": [ 1 ],
"Version": "0.1-testing"
}
}
Property containing the application author's name.
Property containing the application author's contact e-mail address or the application's issue tracker link.
Property containing the application's current status in the main GUI. A
standard application package's JSON descriptor file's Enabled
property
should always be set to true
. The main GUI will take care of changing
this value based on user interaction.
Property containing the path to the main application's launch script.
The recommended location for it is at /app-bin/SampleApp.sh
. See the
related section below for more
details.
Note: This path must be an absolute path, that is, the path used
in the chroot to launch the app.
Property containing the path to the main application's icon.
Property containing the name of the main application. It can be a full string with spaces.
Property containing an array of the application's supported devices.
This can be, for example, [ "n236", "n437", "n306" ]
. If the
application aims to support every device InkBox OS has been ported to,
this property must contain the following array: [ "all" ]
.
Property containing an array of the application's required features. Features are functions of InkBox OS that are not always available based on user interaction (e.g. Wi-Fi connection). Below is a list of features that this property supports.
Feature identifier |
Description |
0 |
Wi-Fi connection required |
1 |
Rooted kernel required |
2 |
Pseudoterminal support
( |
3 |
Support for more input devices |
4 |
Brightness control access |
5 |
Screen rotation control access |
6 |
Debug file system access (for experimental features, like USB host mode) |
7 |
System onboard storage access (exported at
|
8 |
Enable audio daemon communication for the
user app |
9 |
System onboard storage access (exported at
|
A simple array for this property may be, for example, [ 0, 1 ]
. If the
application requires no OS features, the array must be empty: [ ]
.
This file is the script that will be run (as an unpriviledged user) by
the main GUI when the application is launched. It will be interpreted by
busybox ash
, thus, no bash
-style extensions like arrays are
supported.
This script, to ensure the application will launch and run properly,
needs to meet the following requirements:
- Its shebang (first line of the script) needs to be
#!/system-bin/sh
. - The dynamic linker (
/system-lib/lib/ld-linux-armhf.so.3
) must be invoked first instead of directly executing the application's binary, otherwise it might not run.
Below are sample launch scripts you can use to set up your own GUI user application.
- For a Qt application:
#!/system-bin/sh
env -i DEVICE="${DEVICE}" DEVICE_CODENAME="${DEVICE_CODENAME}" QT_FONT_DPI=${QT_FONT_DPI} PATH="/app-bin:/system-bin" LD_LIBRARY_PATH="/system-lib/lib:/system-lib/qt/lib:/app-lib" QT_QPA_PLATFORM="kobo" /system-lib/lib/ld-linux-armhf.so.3 /app-bin/SampleApp
- For a non-Qt application:
#!/system-bin/sh
env -i DEVICE="${DEVICE}" PATH="/app-bin:/system-bin" LD_LIBRARY_PATH="/system-lib/lib:/app-lib" /system-lib/lib/ld-linux-armhf.so.3 /app-bin/SampleApp
The service gui_apps
in the main root filesystem manages the setup of
user applications.
Enter the chroot
env DEVICE="$(cat /opt/inkbox_device)" DEVICE_CODENAME="$(/bin/kobo_config.sh)" LD_LIBRARY_PATH="/lib:system/lib" PATH="/system-bin:/app-bin" system/bin/unshare -p -P /mnt/onboard/onboard/.apps/feathernotes/feathernotes/proc -- system/lib/ld-musl-armhf.so.1 system/bin/chroot --userspec=user:user /mnt/onboard/onboard/.apps/feathernotes/feathernotes/ /system-bin/sh
Regular launch
env PATH="/app-bin:/system-bin" LD_LIBRARY_PATH="/system-lib/lib:/system-lib/qt/lib:/app-lib" QT_QPA_PLATFORM="kobo:debug:mouse" QT_PLUGIN_PATH="/system-lib/qt/plugins/" QT_LOGGING_RULES=qt.qpa.*=true QT_DEBUG_PLUGINS=1 /system-lib/lib/ld-linux-armhf.so.3 /app-bin/feathernotes.bin
Launch with strace and all Qt debug informations:
env PATH="/app-bin:/system-bin" LD_LIBRARY_PATH="/system-lib/lib:/system-lib/qt/lib:/app-lib" QT_QPA_PLATFORM="kobo:debug:mouse" QT_PLUGIN_PATH="/system-lib/qt/plugins/" QT_LOGGING_RULES=qt.qpa.input=true QT_DEBUG_PLUGINS=1 /app-bin/resources/strace -o /app-data/strace.txt /system-lib/lib/ld-linux-armhf.so.3 /app-bin/feathernotes.bin