Overview of the PPS Service

The services layer of the QNX CAR application platform is built on the QNX Persistent Publish/Subscribe (PPS) service, a simple filesystem-based facility that provides persistence across reboots. Small and extensible, PPS allows interfacing from almost any higher-level language that can support open, read, write, and close operations on files.
Note: For a more in-depth description of PPS, see the QNX Persistent Publish/Subscribe Developer's Guide.

Key concepts

Objects
Objects are implemented as files under the /pps directory. Your applications use objects to communicate with each other. There can be many objects in the system, but never more than one instance of the same object.

Applications often use a control object for sending commands and a corresponding status object for publishing responses.

Applications can read a single special object (.all) to get notifications of changes to all the objects in a directory. Apps can use the special .notify object to get changes for a certain set of objects.

Attributes
Objects contain attributes or properties that apps can modify. Each attribute appears on a single line in the object file.
Publishers
As publishers, apps can modify objects and their attributes so that other interested apps can receive updates. Publishing is asynchronous—apps don't have to wait for the publisher.

To publish to an object, the publisher calls open() for that object and then write() to modify it. Multiple publishers can publish to the same object. When a publisher changes an object, the PPS service informs all subscribers of the change.

Subscribers
As subscribers, apps receive updates for objects and attributes that publishers have modified. To get updates for an object, a subscriber calls open() for that object and then read() to query it. Note that reads are nonblocking by default. Multiple subscribers can subscribe to the same object.
Note: The same app can be a publisher, a subscriber, or both.
Full subscription mode
In full mode (the default), the subscriber gets a "snapshot" of the entire object as it exists when the request is made. Note that if a publisher changes the object many times, the subscriber may miss some of the changes. Full mode is useful, for instance, for high-bandwidth objects that have numerous and frequent changes.
Delta subscription mode
In delta mode, the subscriber gets only the changes made to an object. On first read, the subscriber will get all the object's attributes (because the subscriber knows nothing yet about the object's state); subsequent reads will return only the changes since the previous read. Delta mode is useful, for instance, when you want to receive all the warnings or error messages that might be published to an object.
Persistence
PPS maintains objects in memory while it's running and can save them to persistent storage (either at shutdown or on demand) on any reliable filesystem, such as flash or hard disk. Objects can be restored immediately on startup or on first access.
Server objects
A publisher can designate itself as a server for a particular object. When an app writes to a server object, only the publisher will get the message. PPS appends a unique identifier to the object name so that the publisher knows which client app is sending the message.

Command-line options for the PPS service

pps [-b][-C][-l argument][-m mount][-p dir][-t period][-T tolerance]
    [-U uid:gid][-v]
-b
Don't run in the background (useful for debugging).
-C
Convert between -U and non-U persistence formats.
-l argument
Set load behavior:
  • 0 — load directory names and objects on demand (default).
  • 1 — load directories at startup, but objects on demand.
  • 2 — load directories and objects at startup.
-m mount
Specify the mountpoint for PPS (default is /pps).
-p dir
Specify the directory for persistent storage (default is /var/pps).
-t period
Set the time period (in milliseconds) for writing to persistent storage (default is off).
-T tolerance
Set the tolerance (in milliseconds) for writing to persistent storage (default is off).
-U uid:gid
Downgrade from root to the specified UID and GID.
-v
Run in verbose mode (use multiple v's to increase verbosity).
Note: You can also use SIGUSR1 to increase verbosity.

Pathname options

PPS lets you use various pathname options when opening objects. An option must follow a question mark (?). Use a comma to separate multiple options. For example, opening the playlist object like this:

/pps/media/playlist?wait,delta

will open the object with the wait and delta options.

cred
Output the credentials for this object.
critical
Designate the publisher as critical to the object.
crypt
Set the crypto domain for this object.
delta
Open the object in delta mode.
deltadir
Return the names of all objects in the .all object in a directory.
f=<attrspec>{+<attrspec>}...
Filter notifications based on changes to the names and/or values of specified attributes, where attrspec can be either an attribute's name or an expression specifying an attribute's value. Here's the syntax for a value expression:

<attr_name><operator><value>

  • Operators for integers (which must be in the range of a long long) are: <, <=, >, >=, =, ==, and !=
  • Operators for strings are: =, ==, and != (you can use + if escaped with \)
nopersist
Make the object nonpersistent.
notify=id:value
Associate the object with the notification group specified by id:value, where:
  • id is the string returned by the first read from the .notify object
  • value is any arbitrary string
opens
Update an _opens::rd,wr attribute when the open count changes.
reflect
Reflect attribute changes made on this object back to itself.
server
Designate the publisher as a server for the object.
wait
Clear the O_NONBLOCK flag so that read() calls will wait until the object changes or a delta appears.

Object format

Objects appear as files and directories in the PPS filesystem. For example, to view the contents of an object called AA:BA:19:B2:AA:70 (in this case the filename is a device's MAC address) under the /pps/services/bluetooth/remote_devices/ directory, you can simply use cat at the command line:

cat /pps/services/bluetooth/remote_devices/AA:BA:19:B2:AA:70

The object's contents might look like this:

@AA:BA:19:B2:AA:70
[n]cod::0x007a020c
[n]name::My mobile
[n]paired:b:false
[n]rssi::0x00

The first line always begins with an at sign (@), immediately followed by the object's name. Each line after that can begin with a qualifier, followed by an attribute name, followed by its encoding, followed by its value. For example, this line:

[n]paired:b:false

means that the nonpersistence qualifier ([n]) has been set and that the attribute paired has the Boolean value of false.
Note: For details on encodings and on qualifiers, see these sections in the QNX Persistent Publish/Subscribe Developer's Guide:

Format for messages to server objects

msg::command_string\nid::ID_number\ndat:json:{JSON_data}

where:
command_string
Name of the command being sent to the object.
ID_number
Any ID that identifies this instance of the message. The server always reflects the ID back in the response.
JSON_data
The dat is usually JSON encoded, because it may contain more than a simple string.

Format for responses

Responses always reflect the command_string and ID_number that were sent in the message, along with any errors:

res::command_string\nid::ID_number\ndat:json:{JSON_data}\nerr::errno_number\nerrstr::error_description

Changing the directory for persistent storage

The root PPS object tree (/pps by default) may look something like this:

# pwd
/pps
# ls -1F
accounts/
applications/
qnx/
qnxcar/
services/
system/
#

PPS populates its root object tree from the persistence tree (/var/pps by default), where the objects and attributes that you want to persist are stored.

To specify a different directory for persistent storage:
  1. Create your own persistence directory (e.g., mkdir /myobjects).
  2. Start the PPS service from a different mountpoint (e.g., /fs/pps) and specify your new persistence directory:

    pps -m /fs/pps -p /myobjects

Note: You may want to run PPS with the -t option, which lets you specify the time period (in milliseconds) that the service will use to write to persistent storage. Without the -t, you won't see any changes in your persistence directory until PPS exits.