PackageKit does not ask the user questions when the transaction is running. It also supports a fire-and-forget method invocation, which means that transactions will have one calling method, and have many signals going back to the caller.
Each transaction is a new path on the
service, and to create a path you have to call
CreateTransaction on the base
interface which creates the new DBUS path, and returns the new path for you to connect to.
In the libpackagekit binding,
PkControl handles the base interface,
PkClient handles all the transaction interface stuff.
org.freedesktop.PackageKit.Transaction interface can be used
on the newly created path, but only used once.
New methods require a new transaction path (i.e. another call to
which is synchronous and thus very fast.
A typical successful transaction would emit many signals such as
These are used to inform the client application of the current state,
so widgets such as icons or description text can be updated.
These different signals are needed for a few different reasons:
::StatusChanged(): The global state of the
transaction, which will be useful for some GUIs.
Examples include downloading or installing, and this is designed
to be a 40,000ft view of what is happening.
::Package(): Used to either return a result
(e.g. returning results of the
or to return progress about a _specific_ package.
For instance, when doing
::Package(downloading) and then
::Package(installing) for each package as processed
in the transaction allows a GUI to position the cursor on the worked
on package and show the correct icon for that package.
::ErrorCode(): to show an error to the user about
the transaction, which can be cleaned up before sending
::Finished(): to show the transaction has
finished, and others can be scheduled.
This is the typical transaction failure case when there is no network available. The user is not given the chance to requeue the transaction as it is a fatal error.
In this non-trivial example, a local file install is being attempted.
InstallFile is called with the
This will fail if the package does not have a valid GPG key, and ordinarily the transaction
would fail. What the client can do, e.g. using
to re-request the
This will use a different PolicyKit authentication, and allow the file to succeed.
So why do we bother calling
only_trusted in the first place?
Well, the only_trusted PolicyKit role can be saved in the gnome-keyring, or could be
set to the users password as the GPG key is already only_trusted by the user.
non-trusted action would likely ask for the administrator password,
and not allowed to be saved. This gives the user the benifit of installing only_trusted local
files without a password (common case) but requiring something stronger for untrusted or
SimulateInstallFile is used then the client
may receive a
This is used to inform the client that the action would require
the untrusted authentication type, which means the client does
not attempt to do
and only does
This ensures the user has to only authenticate once for the
transaction as the
may also require a password.
If the package is signed, and a valid GPG signature is available, then we need to ask the user to import the key, and re-run the transaction. This is done as three transactions, as other transactions may be queued and have a higher priority, and to make sure that the transaction object is not reused.
Keep in mind that PackageKit can only be running one transaction at any one time. If we had designed the PackageKit API to block and wait for user input, then no other transactions could be run whilst we are waiting for the user.
This is best explained using an example:
User clicks "install vmware" followed by "confirm".
User walks away from the computer and takes a nap
System upgrade is scheduled (300Mb of updates)
The vmware package is downloaded, but cannot be installed until a EULA is agreed to. If we pause the transaction then we never apply the updates automatically and the computer is not kept up to date. The user would have to wait a substantial amount of time waiting for the updates to download when returning from his nap after clicking "I agree" to the vmware EULA.
In the current system where transactions cannot block, the first transaction downloads vmware, and then it finishes, and puts up a UI for the user to click. In the meantime the second transaction (the update) is scheduled, downloaded and installed, and then finishes. The user returns, clicks "okay" and a third transaction is created that accepts the eula, and a forth that actually installs vmware.
It seems complicated, but it's essential to make sure none of the callbacks block and stop other transactions from happening.
DownloadPackages() method is called on a number
of packages, then these are downloaded by the daemon into a temporary
This directory can only be written by the
user (usually root) but can be read by all users.
The files are not downloaded into any specific directory, instead a
random one is created in
The reason for this intermediate step is that the
DownloadPackages() method does not take a destination
directory as the dameon is running as a different user to the user,
and in a different SELinux context.
To preserve the SELinux attributes and the correct user and group ownership
of the newly created files, the client (running in the user session) has
to copy the files from the temporary directory into the chosen destination
NOTE: this copy step is optional but recommended, as the files will remain in
the temporary directory until the daemon is times out and is restarted.
As the client does not know (intentionally) the temporary directory or the
filenames of the packages that are created, the
signal is emitted with the full path of the downloaded files.
It is expected the
package_id parameter of
::Files() will be blank, although this is not mandated.
::Files() signals can be sent by the dameon,
as the download operation may be pipelined, and the client should honour
every signal by copying each file.
The PackageKit backend may support native localisation, which we should support if the
In the prior examples the
SetLocale() method has been left out for brevity.
If you are using the raw DBUS methods to access PackageKit, you will also need to make
a call to
SetLocale() so the daemon knows what locale to assign the
If you are using libpackagekit to schedule transactions, then the locale will be set
automatically in the
PkControl GObject, and you do not need to call
If the package management system is damaged, a repair may be required. This is not automatically done befor each transaction as the user may have to verify destructive package actions or make manual changes to configuration files.
This transaction sequence is not common and is not supported on many backends. It may be completely implemented in the frontend or not at all.