Difference between revisions of "InkBox GUI user apps"

From InkBox
Jump to navigation Jump to search
 
(26 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:InkBox]]This page describes the internals of InkBox GUI's user applications feature.
[[Category:InkBox]][[Category:Applications]][[Category:User applications]]
 
[[File:QtFrotz on Kobo Libra.png|thumb|[https://github.com/Kobo-InkBox/QtFrotz QtFrotz] user application running on a Kobo Libra H2O]]
This page describes the internals of InkBox GUI's user applications feature.
== Description ==
== Description ==
This GUI feature permits the user to run digitally signed external Qt/FB applications available at https://23.163.0.39/bundles/inkbox/apps.<br>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.
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.<br>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.
 
See [https://inkbox.ddns.net/wiki/index.php?title=Category:User_applications Category:User applications] for a detailed presentation of some user applications.
== Application package ==
== Application package ==
=== Contents ===
=== Contents ===
Line 7: Line 12:
├── app-bin
├── app-bin
│  └── SampleApp
│  └── SampleApp
│  └── SampleApp.bin
│  └── SampleApp.sh
├── app-data
├── app-data
├── app.json
├── app-lib
├── app-lib
│   └── libzip.so
│&nbsp;&nbsp; └── libzip.so
├── app-misc
├── app-misc
│  └── SampleApp.png
│  └── SampleApp.png
├── app-temp
├── dev
├── dev
├── etc
├── etc
│   └── passwd
├── mnt
├── proc
├── proc
├── usr
├── sys
├── sys
├── system-bin
├── system-bin
└── system-lib</pre>
├── system-lib
==== <code>app.json</code> ====
└── system-onboard</pre>
This file contains a description of the application in the JSON format that will be parsed by the GUI. A sample <code>app.json</code> may look like this:<pre>{
==== <code>app-bin</code> ====
  "app": {
This directory contains the application's binaries.<br><b>Note:</b> The application's main binary must have the same name as the application's name, matching case. For example, if your app is called <code>SampleApp</code>, the main binary must be called <code>SampleApp</code>.<br>Applications can access this location at <code>/app-bin</code>.
    "Author": "John Doe",
    "AuthorContact": "johndoe@johndoe.com",
    "Enabled": true,
    "ExecPath": "/app-bin/SampleApp",
    "IconPath": "/app-misc/SampleApp.png",
    "Name": "SampleApp",
    "SupportedDevices": "all",
    "RequiredFeatures": [ 1 ],
    "Version": "0.1-testing"
  }
}</pre>For more details on this file and its contents, please consult the [[#JSON app descriptor file|related section below]].
==== <code>app-data</code> ====
==== <code>app-data</code> ====
This directory contains the only read-write part of the extension package. It is actually a bind mount of the related path <code>.apps-data/<app-name></code> in the exported USB mass storage. Applications can store their user data, such as preferences, files and statistics, there.<br>Applications can access this location at <code>/app-data</code>.
This directory contains the only read-write part of the extension package. It is actually a bind mount of the related path <code>.apps-data/<app-name></code> in the exported USB mass storage. Applications can store their user data, such as preferences, files and statistics, there.<br>Applications can access this location at <code>/app-data</code>.
==== <code>app-bin</code> ====
This directory contains the application's binaries.<br>Applications can access this location at <code>/app-bin</code>
==== <code>app-lib</code> ====
==== <code>app-lib</code> ====
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 <b>system-lib</b> directory. In this example, the application requires <code>libzip.so</code>, so it has been put there. <code>LD_LIBRARY_PATH</code> environment variable is automatically adjusted by the main launch script.<br>Applications can access this location at <code>/app-lib</code>.
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 <code>system-lib</code> directory. In this example, the application requires <code>libzip.so</code>, so it has been put there. <code>LD_LIBRARY_PATH</code> environment variable is automatically adjusted by the main launch script.<br>Applications can access this location at <code>/app-lib</code>.
==== <code>app-misc</code> ====
This directory contains miscellanous data about the application, such as its icon.
==== <code>app-temp</code> ====
This directory contains a mounted <code>tmpfs</code> 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.
==== <code>sys</code> ====
==== <code>sys</code> ====
This directory contains a mounted <code>sysfs</code> filesystem used by the chroot.
This directory contains a mounted <code>sysfs</code> filesystem used by the chroot.
Line 49: Line 46:
==== <code>etc</code> ====
==== <code>etc</code> ====
This directory contains a mounted <code>tmpfs</code> filesystem used by the chroot.
This directory contains a mounted <code>tmpfs</code> filesystem used by the chroot.
==== <code>mnt</code> ====
This directory contains a mounted <code>tmpfs</code> filesystem used by the chroot, namely for printing to the framebuffer.
==== <code>usr</code> ====
This directory contains a mounted <code>tmpfs</code>. It's needed because of time zones.
==== <code>run</code> ====
This directory contains a mounted <code>tmpfs</code>. Only needed if additional input devices are needed (udev).
==== <code>system-lib</code> ====
==== <code>system-lib</code> ====
This directory contains the system's Qt libs and are made available so that the application can launch.<br>Applications can access this location at <code>/system-lib</code>.
This directory contains the system's Qt libs and are made available so that the application can launch.<br>Applications can access this location at <code>/system-lib</code>.
==== <code>system-bin</code> ====
==== <code>system-bin</code> ====
This directory contains the system's binaries made available to the application (e.g. BusyBox).<br>Applications can access this location at <code>/system-bin</code>.
This directory contains the system's binaries made available to the application (e.g. BusyBox).<br>Applications can access this location at <code>/system-bin</code>.
==== Other files ====
Those may include an application icon that will be read by the GUI.
=== GUI launch process ===
=== GUI launch process ===
The main Qt GUI will launch the application in the chroot jail as an unpriviledged user, based on its JSON file's <code>ExecPath</code> property. Once the program has finished running, the GUI will restart itself.
The main Qt GUI will launch the application in the chroot jail as an unpriviledged user, based on its JSON file's <code>ExecPath</code> property. Once the program has finished running, the GUI will restart itself.
== JSON app descriptor ==
== JSON application descriptor file ==
The <code>app.json</code> file contains information about the application, how to run it and what system features it requires.
The <code>app.json</code> 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 <code>app.json</code> may look like this:<pre>{
  "app": {
    "Author": "John Doe",
    "AuthorContact": "johndoe@johndoe.com",
    "Enabled": true,
    "ExecPath": "/app-bin/SampleApp",
    "IconPath": "/app-misc/SampleApp.png",
    "Name": "SampleApp",
    "SupportedDevices": [ "all" ],
    "RequiredFeatures": [ 1 ],
    "Version": "0.1-testing"
  }
}</pre>
=== Properties ===
=== Properties ===
==== <code>Author</code> ====
==== <code>Author</code> ====
Property containing the application author's name.
Property containing the application author's name.
==== <code>AuthorContact</code> ====
==== <code>AuthorContact</code> ====
Property containing the application author's contact e-mail address.
Property containing the application author's contact e-mail address or the application's issue tracker link.
==== <code>Enabled</code> ====
==== <code>Enabled</code> ====
TODO
Property containing the application's current status in the main GUI. A standard application package's JSON descriptor file's <code>Enabled</code> property should always be set to <code>true</code>. The main GUI will take care of changing this value based on user interaction.
==== <code>ExecPath</code> ====
==== <code>ExecPath</code> ====
Property containing the path to the main application's executable. The recommended location is at <code>/app-bin/SampleApp</code>.
Property containing the path to the main application's launch script. The recommended location for it is at <code>/app-bin/SampleApp.sh</code>. See the [[#Application launch script|related section below]] for more details.<br><b>Note:</b> This path must be an absolute path, that is, the path used in the chroot to launch the app.
==== <code>IconPath</code> ====
==== <code>IconPath</code> ====
Property containing the path to the main application's icon.
Property containing the path to the main application's icon.
Line 73: Line 86:
Property containing the name of the main application. It can be a full string with spaces.
Property containing the name of the main application. It can be a full string with spaces.
==== <code>SupportedDevices</code> ====
==== <code>SupportedDevices</code> ====
Property containing an array of the application's supported devices. This can be, for example, <code>[ "n236", "n437", "n306" ]</code>. If the application aims to support every device, this property must contain the <code>"all"</code> string instead.
Property containing an array of the application's supported devices. This can be, for example, <code>[ "n236", "n437", "n306" ]</code>. If the application aims to support every device InkBox OS has been ported to, this property must contain the following array: <code>[ "all" ]</code>.
==== <code>RequiredFeatures</code> ====
==== <code>RequiredFeatures</code> ====
Property containing an array of the application's required features. <i>Features</i> 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.
Property containing an array of the application's required features. <i>Features</i> 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.
{| class="wikitable"
{| class="wikitable" style="height: 164px;"
|-
|-  
| '''Feature identifier'''
| style="width: 139px;" | '''Feature identifier'''
| '''Description'''
| style="width: 505px;" | '''Description'''
|-
|-  
|'''0'''
| style="width: 139px;" | '''0'''
|Wi-Fi connection required
| style="width: 505px;" | Wi-Fi connection required
|-
|-  
|'''1'''
| style="width: 139px;" | '''1'''
|Rooted kernel required
| style="width: 505px;" | Rooted kernel required
|-
|-  
| style="width: 139px;" | '''2'''
| style="width: 505px;" | Pseudoterminal support (<code>/dev/ptmx</code>, <code>/dev/pts</code>) required
|-
| style="width: 139px;" | '''3'''
| style="width: 505px;" | Support for more input devices
|-
| style="width: 139px;" | '''4'''
| style="width: 505px;" | Brightness control access
|-
| style="width: 139px;" | '''5'''
| style="width: 505px;" | Screen rotation control access
|-
| style="width: 139px;" | '''6'''
| style="width: 505px;" | Debug file system access (for experimental features, like USB host mode)
|-
| style="width: 139px;" | '''7'''
| style="width: 505px;" | System onboard storage access (exported at <code>/system-onboard</code>)
|-
| style="width: 139px;" | '''8<br>'''
| style="width: 505px;" | Enable audio daemon communication for the user app<br>
|-
| style="width: 139px;" | '''9<br>'''
| style="width: 505px;" | System onboard storage access (exported at <code>/system-onboard</code>) but with access to other user apps. Don't use this option with 7<br>
|}
|}
A simple array for this property may be, for example, <code>[ 0, 1 ]</code>.
A simple array for this property may be, for example, <code>[ 0, 1 ]</code>. If the application requires no OS features, the array must be empty: <code>[ ]</code>.
 
== Application launch script ==
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 <code>busybox ash</code>, thus, no <code>bash</code>-style extensions like arrays are supported.<br>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 <code>#!/system-bin/sh</code>.
* The dynamic linker (<code>/system-lib/lib/ld-linux-armhf.so.3</code>) 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:
<pre>#!/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</pre>
* For a non-Qt application:
<pre>#!/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</pre>
== Backend setup ==
== Backend setup ==
The service <code>gui_apps</code> in the main root filesystem manages the setup of user applications.
The service <code>gui_apps</code> in the main root filesystem manages the setup of user applications.
== Example debugging commands  ==
Enter the chroot
<pre>
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
</pre>
Regular launch
<pre>
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
</pre>
Launch with strace and all Qt debug informations:
<pre>
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
</pre>

Latest revision as of 09:57, 22 January 2024


QtFrotz user application running on a Kobo Libra H2O

This page describes the internals of InkBox GUI's user applications feature.

Description

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.

See Category:User applications for a detailed presentation of some user applications.

Application package

Contents

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

app-bin

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.

app-data

This directory contains the only read-write part of the extension package. It is actually a bind mount of the related path .apps-data/<app-name> 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.

app-lib

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.

app-misc

This directory contains miscellanous data about the application, such as its icon.

app-temp

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.

sys

This directory contains a mounted sysfs filesystem used by the chroot.

dev

This directory contains a mounted devtmpfs filesystem used by the chroot.

proc

This directory contains a mounted proc filesystem used by the chroot.

etc

This directory contains a mounted tmpfs filesystem used by the chroot.

mnt

This directory contains a mounted tmpfs filesystem used by the chroot, namely for printing to the framebuffer.

usr

This directory contains a mounted tmpfs. It's needed because of time zones.

run

This directory contains a mounted tmpfs. Only needed if additional input devices are needed (udev).

system-lib

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.

system-bin

This directory contains the system's binaries made available to the application (e.g. BusyBox).
Applications can access this location at /system-bin.

GUI launch process

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.

JSON application descriptor file

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": "johndoe@johndoe.com",
    "Enabled": true,
    "ExecPath": "/app-bin/SampleApp",
    "IconPath": "/app-misc/SampleApp.png",
    "Name": "SampleApp",
    "SupportedDevices": [ "all" ],
    "RequiredFeatures": [ 1 ],
    "Version": "0.1-testing"
  }
}

Properties

Author

Property containing the application author's name.

AuthorContact

Property containing the application author's contact e-mail address or the application's issue tracker link.

Enabled

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.

ExecPath

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.

IconPath

Property containing the path to the main application's icon.

Name

Property containing the name of the main application. It can be a full string with spaces.

SupportedDevices

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" ].

RequiredFeatures

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 (/dev/ptmx, /dev/pts) required
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 /system-onboard)
8
Enable audio daemon communication for the user app
9
System onboard storage access (exported at /system-onboard) but with access to other user apps. Don't use this option with 7

A simple array for this property may be, for example, [ 0, 1 ]. If the application requires no OS features, the array must be empty: [ ].

Application launch script

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

Backend setup

The service gui_apps in the main root filesystem manages the setup of user applications.

Example debugging commands

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