.adef files can contain these sections:
Bindings allow client-side IPC API interfaces (listed in the requires sections of Component.cdef files) to be bound to server-side interfaces (listed in the provides sections of Component.cdef files).
This gives direct control over how IPC interfaces are interconnected so reusable components and/or apps can be bound (wired) together to form a working system.
Bindings can be between two interfaces inside the same app (internal binding), or can be between a client-side interface in an app and a server-side interface provided by another app (or non-app user).
Interface instances inside the app use the executable name, component name, and the service instance name separated by a period (‘.’).
The client interface always appears first with an arrow ( -> ) to separate the client interface from the server interface.
bindings: section must be listed in the .adef file after the Executables section.Here's a code sample binding clientExe.clientComponent.clientInterface to serverExe.serverComponent.serverInterface:
bindings:
{
clientExe.clientComponent.clientInterface -> serverExe.serverComponent.serverInterface
}
External services provided by other apps use the app name and the service name, separated by a period ('.'):
bindings:
{
clientExe.clientComponent.clientInterface -> otherApp.serverInterface
}
To bind to a service provided by a non-app user, the app name is replaced by a user name inside angle brackets:
bindings:
{
clientExe.clientComponent.clientInterface -> <root>.serverInterface
}
If client-side code was built using the ifgen tool or mkcomp or mkexe with requires or bundles sections, the tool reading your .adef file won't know about the client-side interface. Use a special work-around to bind those interfaces:
bindings:
{
*.le_data -> dataConnectionService.le_data
}
This would bind any unknown client-side le_data interfaces in the current app to the le_data server-side interface on the dataConnectionService app.
Lists additional files or directories to be copied from the build host into the app so they’re available to the app at runtime (e.g., audio files, web pages, executable scripts or programs built using some external build system).
bundles:
{
file:
{
// Include the web server executable (built using some other build tool) in the app's /bin.
[x] 3rdParty/webServer/bin/wwwServ /bin/
// Put the company logo into the app's /var/www/ for read-only access by the web server.
images/abcCorpLogo.jpg /var/www/
// Make the appropriate welcome page for the product appear at /var/www/index.html.
webContent/$PRODUCT_ID/welcome.html /var/www/index.html
// Create a file to record persistent custom audio messages into.
[w] audio/defaultMessage.wav /usr/share/sounds/customMessage.wav
}
dir:
{
// Recursively bundle the directory containing all the audio files into the app.
// It will appear to the app read-only under /usr/share/sounds/.
audio /usr/share/sounds
}
}
Three things need to be specified for each file or directory:
Access permissions - any combination of one or more of the following letters, enclosed in square brackets:
If permissions values are not specified, then read-only ([r]) is the default.
Directories always have executable permission set so they can be traversed. Setting the [x] permission in the dir: subsection causes the files under the directory to be made executable.
Setting [w] in the dir: subsection causes all files under that directory to be writeable, but the directory itself will not be writeable.
bin directory on the target gets rx permission, all other files get r, and directories get rx.Build system path - file system path on the build PC where the file is located at build time.
The path can be relative to the directory where the .adef file is located.
Target path - file system path on the target where the file will appear at runtime.
It's an absolute path inside the app's sandbox file system.
If the path ends with '/', it means the directory path where the source object (file or directory) will be copied. The destination object will have the same name as the source object.
If the path doesn't end in a '/', it's a full destination object path. The destination object could have a different name than the source object.
/opt/legato/apps/xxxx, where xxxx is replaced by the app name.Quoting Paths
File paths can be enclosed in quotation marks (either single ' or double "). This is required when the file path contains spaces or comment start sequences
"//" or "/*"
File Ownership and Set-UID Bits
When the app is installed on a target:
root on all files in the app.setuid bit is cleared on everything in the app.Specifies the relative cpu share for an app.
Cpu share calculates the cpu percentage for a process relative to all other processes in the system. New cgroups and processes default value of 1024 if not otherwise configured. The actual percentage of the cpu allocated to a process is calculated like this:
(share value of process) / (sum of shares from all processes contending for the cpu)
All processes within a cgroup share the available cpu percentage share for that cgroup like this:
This assumes all processes in cgroupA, cgroupB and cgroupC are running and not blocked waiting for an I/O or timer event, and another system process is also running.
Sum of all shares (including the one system process) is 1024 + 512 + 2048 + 1024 = 4608
The process in cgroupA will get 1024/4608 = 22% of the cpu. The two processes in cgroupB will share 512/4608 = 11% of the cpu, each process getting 5.5%. The process in cgroupC will get 2048/4608 = 44% of the cpu. The system process will get 1024/4608 = 22% of the cpu.
cpuShare: 512
Lists executables to be constructed and moved to the bin directory inside the app.
An executable’s content is specified inside parentheses after the name, and can be one of these:
excutable: section must be listed in the .adef file before the bindings: section.executables:
{
myexe1 = ( file1.c libgoodstuff.so )
myexe2 = ( foobar toto )
}
Components included in an executable will be built and linked into the executable, and its COMPONENT_INIT function will be run at process start-up. The component’s runtime files (shared libraries, source code, etc.) will be packaged inside the app to be installed on the target.
Source files included in an executable will be searched for by the build tools in the file system based on the source search path. If found, it'll be compiled (if written in a compiled language) and linked into the executable. All source files specified for an executable together are considered a component, which will have the same name as the executable. One of the source files will be expected to implement a COMPONENT_INIT function, called at start-up.
If a library is included in an executable, it's expected to be found in the requires or bundles section of the app’s .adef file or the Component.cdef file included in the app. When the executable is linked, it'll be linked with these libraries in the order listed. You can list the same library more than once; sometimes it's necessary in order to satisfy all unresolved symbols, due to the single-pass nature of the linker.
The mechanism use to construct both executables and components depend on the type of content and the target device.
C and C++ files will be compiled and linked using the appropriate compiler tool chain based on the target.
Java code will be compiled to Java bytecode. Interpreted code, such as Python code will be simply copied into the app.
Add an app's user to groups on the target system.
groups:
{
www-data
modem
}
Specifies the maximum amount of RAM that can be consumed by an app's temporary (volatile) file system at runtime.
Default is 128K
maxFileSystemBytes: 120K
maxMemoryBytes limit.Specifies the maximum amount of memory (in bytes) that all processes in an app can share. Default is 40960K (40MB).
maxMemoryBytes: 1000K
Specifies the maximum number of bytes that can be allocated for POSIX MQueues. Default is 512.
maxMQueueBytes: 16K
Specifies the maximum number of signals that can be waiting for delivery to processes in the app.
This limit will only be enforced when using sigqueue() to send a signal. Signals sent using kill() are limited to at most one of each type of signal anyway.
Default is 100.
maxQueuedSignals: 200
Specifies the maximum number of threads allowed to run at one time: an integer number.
main() function) counts as one thread.If fork() calls or pthread_create() calls start failing with error code EAGAIN (seen in strace output as clone() system calls), then you are probably running into this limit.
Default is 20.
maxThreads: 4
A processes section specifies processes to run when the app is started including environment variables, command-line arguments, limits, and fault handling actions.
The processes section is divided into subsections. If different processes have different variables, they must be in separate processes: sections.
processes:
{
// Start up these processes when the app starts
run:
{
myProc1 = ( myExe --foo -b 43 )
myProc2 = ( myExe –bar --b 92 )
( myExe2 "Hello, world." ) // If no proc name is specified, uses the exe name by default.
}
// Env var settings (name = value) for all processes in this section.
envVars:
{
LE_LOG_LEVEL = DEBUG
}
priority: medium // Starting (and maximum) scheduling priority.
// Process can only lower its priority from here.
maxCoreDumpFileBytes: 100K // Maximum size of core dump files.
maxFileBytes: 50K // Files are not allowed to grow bigger than this.
maxLockedMemoryBytes: 32K // Can't mlock() more than this many bytes.
maxFileDescriptors: 20 // Can't have more than this number of FDs open at the same time.
}
processes:
{
run:
{
( realTimeExe )
}
priority: rt10 // Allow real-time scheduling (max priority 10) for processes in this section.
/*-- Exception handling policy for processes in this section. --*/
faultAction: restart // Restart the process if it fails.
}
Names a process to be started by the Supervisor when the app is started. Also specifies executable and command-line arguments.
Process name and command-line arguments are optional.
If the process name is not specified, then the process will be given the same name as the executable it's running (e.g. myexe)
A given executable can be launched multiple times.
Command-line arguments passed to the process when started can appear after the executable name.
Executable names can be the ones listed in the app’s executables: section. They can also be the names of files that are bundled into the app with [x] (executable) permission.
Quotation marks (either single ' or double ") can be used if white-space (spaces, tabs, //, etc.) is needed inside a command-line argument, or if an empty argument is needed ("").
Environment variables appear as name = value pairs. First is the environment variable name and second is the variable value.
Enclose the value in quotation marks (either single ' or double ") if white-space is required:
Specifies the action the Supervisor should take when the process terminates with a non-zero exit code or because of an un-caught signal (e.g., SIGSEGV, SIGBUS, SIGKILL).
Possible values are:
ignore - Supervisor just logs a warning message; no further action taken.restart - log a critical message and restart the process.restartApp - log a critical message and restart the entire app.stopApp - log a critical message and terminate the entire app (send all processes the SIGTERM signal, followed shortly by SIGKILL).reboot - log an emergency message and reboot the system.Default is ignore.
Specifies the starting (and maximum) scheduling priority. A running app process can only lower its priority from this point. Once it has lowered its priority, it can't raise it again (e.g., if the process starts at medium priority and reduces to low priority, it can't go back to medium priority). The default is medium.
Values:
Specifies the maximum size (in bytes) of core dump files that can be generated by processes.
Default is 8K
Specifies the maximum size processes can make files. The K suffix permits specifying in kilobytes (multiples of 1024 bytes).
Default is 88K
Exceeding this limit results in a SIGXFSZ signal sent to the process. By default, this kills the process, but it can be blocked or caught to receive an error with errno set to EFBIG.
Specifies the maximum number of file descriptors a process can have open at one time.
Default is 256
Specifies the maximum bytes of memory the process can lock into physical RAM (e.g., using mlock() ).
Can't be higher than maxMemoryBytes.
Default is 8K
shmctl().Specifies the action the Supervisor should take when a process subscribed to the watchdog service fails to kick the watchdog before it expires. Possible values are the same as in Fault Action as well as:
stop - Supervisor terminates the process if it's still running. If a watchdog action has not been supplied, the default action will restart the process.
Specifies the timeout length (in milliseconds) for watchdogs called by processes in the enclosing processes section.
Once a process has called le_wdog_Kick(), it's registered with the software watchdog service. If it then fails to call le_wdog_Kick() within the given timeoutout, the Supervisor is notified will take the action specified in Watchdog Action
The provides: section is used to specify things the app provides to other apps (or non-app processes) in its runtime environment.
For now, only api: subsections are supported.
Declares that a server-side IPC API interface is available for other apps (or non-app users) to use via Bindings.
This code sample declares the temperature interface on the thermistor component in the sensor executable should be made into a bindable external interface called spaceTemp:
provides:
{
api:
{
spaceTemp = sensor.thermistor.temperature
}
}
If the app was called thermometer, then other apps could bind their client-side interfaces to thermometer.spaceTemp to receive temperature readings from this sensor app.
Internal interface instances are identified by the executable, component, and component's interface names. The different interface instance identifier parts are separated by a period (‘.’).
The requires: section specifies things the app needs from its runtime environment.
It can contain various subsections.
Declares a client-side IPC API interface on an executable inside the app needs to be bound to a service provided by something outside the app.
Interfaces inside the app are identified by the executable, component, and component's interface names (separated by a period ‘.’).
This code sample declares that the temperature interface on the tempInput component in the controller executable should be made into a bindable external interface:
requires:
{
api:
{
controller.tempInput.temperature
}
}
Outside the app, this client-side interface will be called temperature (hiding from other apps the details of what executable and component implements the interface).
To have other apps to see an interface with a different name, add alias = differentname in front of the interface specification:
requires:
{
api:
{
airTemp = controller.tempInput.temperature
}
}
If this app were called thermostat, then in a .sdef file, the interface would be called thermostat.airTemp.
Declares the app requires access to a specified configuration tree. Each app has its own configuration tree named after the app. There's also a system configuration tree that contains privileged system data.
By default, an app only has read access to its own configuration tree.
Apps can be granted read access or both read and write access to trees using an optional access permission specifier:
[r] - grant read-only access[w] - grant read and write accessIf access is granted to a tree, but the access mode ([r] or [w]) is not specified, only read permission will be granted.
A special tree name "." can be used to refer to the app's own configuration data tree.
requires:
{
configTree:
{
[w] . // I need write access to my configuration data.
otherApp // I need read access to another app's configuration data.
}
}
system tree; untrusted
apps should never be given direct access to the system tree.Used to declare that certain directories that reside on the target device outside of the app are to be made accessible to the app.
The location inside the app's sandbox at which the directory will appear is also specified.
Things listed here are expected to be found on the target at runtime. They are not copied into the app at build time; they are made accessible to the app inside of its sandbox at runtime.
Each entry consists of two file system paths:
Paths can be enclosed in quotation marks (either single ' or double "). This is required when it contains spaces or character sequences that would start comments.
If the second path ends in a '/', then it's specifying the directory into which the object will appear, and the object will have the same name inside the sandbox as it has outside the sandbox.
requires:
{
dir:
{
// I need access to /proc for debugging.
/proc /
// For now, I want access to all executables and libraries in /bin and /lib.
// Later I'll remove this and replace with just the files I really need in the field.
// Also, I don't want to hide the stuff that the tools automatically bundle into my app's
// /bin and /lib for me, so I'll make the root file system's /bin and /lib accessible as
// my app's /usr/bin and /usr/lib.
/bin /usr/bin
/lib /usr/lib
}
}
/bin to appear at /usr/bin, you can't then bundle a file into /usr/bin or require something to appear in /usr/bin; that would have an effect on the contents of the /bin directory outside of the app.Declares:
Things listed in requires are expected to be found on the target at runtime. They're not copied into the app at build time; they are made accessible to the app inside of its sandbox at runtime.
Each entry consists of two file system paths:
A file path can be enclosed in quotation marks (either single ' or double "). This is required when it contains spaces or character sequences that would start comments.
The first path can't end in a '/'.
If the second path ends in a '/', then it's specifying the directory where the object appears, and the object has the same name inside the sandbox as it has outside the sandbox.
requires:
{
file:
{
// I get character stream input from outside via a named pipe (read-only)
/var/run/someNamedPipe /var/run/
// I need read and write access to UART2.
/dev/ttyS1 /dev/
// I need to be able to play back audio files installed in /usr/local/share/audio.
"/usr/local/share/audio/error message.wav" /usr/share/audio/
'/usr/local/share/audio/success message.wav' /usr/share/audio/
}
}
It's also possible to give the object a different names inside and outside of the sandbox by adding a name to the end of the second path.
requires:
{
file:
{
/dev/ttyS0 /dev/port1 // Program uses /dev/port1, but UART0 is called /dev/ttyS0.
}
}
Specifies if the app will be launched inside a sandbox.
Permitted content in this section is:
The default is true.
If an app is unsandboxed (app is not inside of a sandbox), it can see the target device's real root file system. A sandboxed app can't see the target's real root file system; a sandboxed app has a separate root file system, which it can't leave.
Each app has its own user and primary group IDs. The app's user name and primary group name are both appxxxx", where the xxxx is the name of the app.
User and/or group will be automatically created if missing for the specified app, but only users and groups of sandboxed apps will automatically be deleted when those apps are uninstalled.
sandboxed: false
Specifies if the app should start automatically at start-up:
start: auto
Optional field that specifies a string to use as the app's version string.
version: 0.3a
–append-to-version option to mkapp can be used to add to the app's version string.app foo version can be run on-target to get the version string of the app called "foo".The watchdogAction section sets the recovery action to take if a process in this app expires its watchdog. This value will be used if there is no value set in the processes section for a given process. See Watchdog Action in the processes section.
The watchdogTimeout section sets the default timeout in milliseconds for processes in this app. Will be used if there's no value set in the processes section for a given process. See Watchdog Timeout in the processes section.
Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.