Extension Manager Rework
The Extension Manager uses two extension layers, the user and the shared layer. Extensions installed in the shared layer can be used by all users whereas those in the user layer can only be used by the user who installed them. An extension can be installed in either layer or both.
This system was developed many years ago. Since then new features were added, such as extension versioning, online update, bundled extensions, etc. During that time it became obvious that there are some problems with the original design. This document tries to explain them.
The idea of layers is that extensions in the top layer hide the same extensions in the layer below. In other words, the extension in the highest layer will be given preference, when resources from the extension are requested. Because the user layer is the top layer, a shared extension is only used when the same extension does not exist in the user layer. The version of the extension has no influence.
This, however, is only a simplified model. An extension is never used as a whole. Instead clients access the particular contents, such as components, configuration data, etc. And it is also these contents which obscure the same content in a lower layer. For example, an extension contains a UNO service, which is installed in both layers. When the client instantiates it then the one from the top layer is used.
There are situations where contents of the shared extensions are still used, although they should be hidden and therefore not usable. Assuming there are version 1 and version 2 of an extension. Then the different versions may have different content. For example, version 1 may contain a service foo which is not contained in version 2. If now version 1 is installed in the shared layer and version 2 in the user layer then foo is still around and can be instantiated. Foo may access resources which are also delivered with this extension and are also available in version 2 which is in the user layer. Resources in version 2, which hide those from version 1 (same node in xcu or same service), can be incompatible, so that foo fails.
A service may also need files which are part of the same extension and which are only directly accessible. That is there is no API, such as the registry or service manager, which can provide the content. A "running" service does not know from which layer it comes from. To get the install location it can use the PackageInformationProvider. This service will first look into user layer and if the extension cannot be found, then it will look into the shared layer. If now the service from the shared layer needs some file from its extension, then it may accidentally use the one from a different version of the extension in the user layer. This file can be incompatible or not even exist and make the service fail.
Another example can be constructed using registry values, which are contained in xcu files. Let's assume that version 1 of an extension adds a menu foo and version 2 adds menu bar. If one extension is installed in the share and the other in the user layer, then both menus appear. This is because the nodes of the configuration files are merged into the configuration and not the xcu files itself. That is, if the extensions contain an xcu file with the same name, then the xcu file of the last installed extension will NOT replace the one from the other extension. The second xcu file can, however, change the values for nodes which have been defined by the first xcu.
These examples prove that the layering (in terms of hiding the items from the layer below) on extension level does not work, although it does for the respective deployment items. And it may be safe to say, that this goes against the user's expectation.
It may be unclear to users how the behavior is when the same extension is installed as user and shared extension. If there is a shared extension and the same extension is installed as user extension, then the user should be informed that the currently installed extension will become 'inactive'. Then, when the user extension is uninstalled, the user should be informed that the shared extension will become 'active' again.
As already observed, the version of an extension has no influence on the decision if the extension from the user or the shared layer is used. At the time of developing the extension framework there was no support for versioned extensions, so one did not have to care about them. Later, we recognized that an extension version is useful for users. For example, if one has an extension installed and is installing the same extension again, then one is being informed about what extension has the later version (so one can decide which is the best for them).
I think the general expectation is that the latest version is the best. Therefore it should be natural that OOo uses always that one. However, this is not the case and users may unintentionally prevent, that they use the latest extension. For example, OOo comes with a bundled English dictionary. Now a user installs, intentionally or not, the same extension and forgets about it. The administrator updates OOo regularly, which also updates the dictionary with the latest version. But the user would still use the old dictionary, because that is the one from the user layer which hides the one from the shared layer.
One could think now of a notification for the user but there are some questions:
- when does OOo check for this situation?
- how can this be explained to the user?
The first question, is easily answered: At every start-up.
The second question is more difficult.Think about a message, such as: "Dear user. You cannot use the latest version of the french dictionary, which is installed in the shared/bundled layer. Instead the dictionary which you installed earlier is used. You need to uninstall it, if you want the new version ...." Many users would probably not understand this. So the easiest and natural way is simply to use the latest version of the extension indepedent of what layer it is installed in. The term layer should then be replaced, by repository, indicating that the location does not include a preference – just think about the picture of one layer above the other compared to repositories which are arranged in one row.
The shared layer is located within the OOo installation. The benefit is that normal users cannot modify it. The layer will be modified after installation of OOo when an extensions is added, deleted, enabled or disabled. Depending on the operation system, this may be against the system guidelines. For example, it would be not allowed on Windows Vista/ 7. However, to allow “legacy application” to work Microsoft invented the virtual store.
Modification of the shared layer will also prevent the clean uninstallation of OOo. This is because the native installer does not “own” the files/folder which were added by the extension manager. For example, on Linux the path /opt/openoffice.org3/share/uno_packages will remain on the system. On OpenSolaris the shared extensions (with the same directory structure) will be copied to /var/lost+found on uninstallation.
The rule is, whatever a user installed should not be removed by OOo. This is also valid for shared extensions. Today a bundled extension is nothing else than a shared extension and therefore can be modified by users, provided they have sufficient file access rights. They can install the same extension as one, which was installed as bundled extension, in the shared layer. This means that the original bundled extension is replaced by the recently installed shared extension. This can happen in two scenarios. The first one is during an online update of the extension and the second is when the extension is “manually” installed. In these cases users intentionally choose to replace the original extension. Therefore this extension may not be deleted when uninstalling OOo. This, however, requires to know that the bundled extension was replaced, but there is currently no way to recognize this.
Selection of extensions in setup
Like many other features, bundled extensions should be selectable in the dialog of the installer. The installer can also be invoked later to add or remove particular features. The problem is, that the extensions which the installer “sees” are not the same as “seen” by the extension manager. The setup copies an oxt file to ../share/extension/install and then invokes a post-install script (Unix) or a custom action (Windows) which runs unopkg to install the extension properly. The extension is then unzipped to ../share/uno_packages/cache/uno_packages and some data are added to the extension manager database. The installer only knows the file that it copied to the ../share/extension/install folder. If it is there then it is regarded as installed – otherwise not.
For an extension to show up in the dialog of the extension manager, there are two conditions which need to be met. First, it must be unpacked in the uno_packages folder. And second, there must be an appropriate entry in the extension manager database, indicating that it is installed. Therefore it would be possible that the installer displayed an extension as being installed but the extension manager did not. This may of course happen the other way round as well.
Even if the installer would copy the uncompressed extension directly to ../share/uno_packages/cache/uno_packages, both dialogs could show a different status. One could assume that the installer and extension manager regard an extension as installed if the the respective folder exists. But this does not work, because the extension manager does not remove immediately the extension when it is being uninstalled. The reason is, that files from the extension can still be in use in the process. Only after restarting OOo and the extension manager, the extension's folder will be finally removed.
Code execution during installation
Copying extensions into the office installation during setup is not sufficient to make them usable. Only after the extension manager has processed them, OOo can make use of them. Therefore the installer invokes the extension manager after an extension has been copied. Unfortunately this requires different solutions for different platforms. RPM (Linux) and PKG (Solaris) use post-install/pre-install scripts which are executed after the copying step. But there are installation scenarios on Solaris, where code execution is not allowed during the setup. For example, the installer is running on Solaris Sparc and installs OOo on a Solaris Intel Machine machine. Therefore OOo uses a “postrun” service which invokes the extension manager when the system is rebooted. OpenSolaris prohibits code execution completely. The setup needs to install an SMF service which is triggered after the setup. Windows needs a 'custom action' which is compiled native code. The Mac dmg file already contains the processed extensions. That is, the extension manager processes the extension while building the dmg file.
It is obvious that the current situation is complex and one understands why testing and bug finding are rather difficult.
Extension Manager database
The database is created when the extension manager is started for the first time. The database contains different files and folders which are completely unknown to the installer. Therefore the installer will not remove them. This is another reason why the OpenOffice.org folder remains on the system after uninstalling OOo.
Only the one who installs the extension can see the license.
|Content on this page is licensed under the Public Documentation License (PDL).|