I'm working on some small application on Symbian-Belle platform. Everything was doing well until I've hit a place where I had to parse a few JSON files. I've found a QJson library, which seemed very relevant and easy to use (although it seems to return everything as QVariantMap, which probably is not that lightweight..).
This library is however not provided in a precompiled form. It is source-only, but the source is openly available at http://gitorious.org/qjson/qjson/. Fortunatelly, it is prepared to compile under QtCreator's Symbian projects.
Initial project setups
After fetching the library from Git, I've tried compiling it and it went well. I wanted the lib to compile along with the main project. I've created a top-level SUBDIRS project and put QJson underneath, and also I added there the project with my application. I've set all inter-project dependencies and corrected the build and run configuration to actually run my application (SUBDIRS top-level project does not set it by default, it has to be manually corrected).
I've chosen the simulator configuration, pressed Run, compilation passed, but linking did not:
Error: file 'qjsond.lib' was not found
The default QtCreator's dependency management added the lines:
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjson
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjsond
else:symbian: LIBS += -lqjson
else:unix: LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjson
and the QJson library has generated only 'qjson' binary. I am running on Windows, so building for the Simulator looked for the 'qjsond' symbol, just as the second line clearly states. BTW. this is the defacto standard way of naming debug versions of libraries on win32 introduced by Microsoft's VisualStudio series.. Anyways, here's not relevant. The QJson, even in debug-mode, builds only without the -d prefix, so I removed it:
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjson
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjson
else:symbian: LIBS += -lqjson
else:unix: LIBS += -L$$OUT_PWD/../QJson/lib/ -lqjson
Everything compiled well, linked well, so I run it in the Simulator. And it run! yay.
And on the device..
So, the next part was to run it on the real device - and here another class of problems began. After building, linking, deploying and installing, the IDE told me:
Launch failed: Command answer [command error], 1 values(s) to request: 'C|4|Processes|start|""|"MyApp.exe"|[""]|[]|true'
#0 {"Code":-46,Format="Failed to create the process (verify that the executable and all required DLLs have been transferred and that the process is not already running) (permission denied)"}
Error: 'Failed to create the process (verify that the executable and all required DLLs have been transferred and that the process is not already running) (permission denied)' Code: -46
and the launch process instantly was aborted. Of course the application was launching properly back when the json-related code and library was not yet added to the project..
I've checked and the QJson library was indeed properly installed on the device, so it was not about missing files. Also, the application it self has been properly installed too. Anyways, in the parentheses there's a note permission denied
which was quite suspicious. When I tried to run the application manually on the device, I've got:
Dostęp do aplikacji został zablokowany przez administratora
in english, I'd be something like:
Access to the application has been blocked by the administrator
actually, on devices with english language set, the message is:
Unable to execute file for security reasons
Well, this was not what I expected when adding a DLL. I expected a crash, SIGSEGV, Kernel-Panic-#32 etc, but not some security/administrative restrictions. I've searched a bit on Nokia'a documentation and I've found a page that mentioned that DLL projects also can have Capabilities specified, just like normal .EXE applications.
QJson's DLL Capabilities and UID3
Actually, bad Capability definitions could have caused that error, so I've checked the .pro files from the library project. In 'src.pro' I've found lines:
#TARGET.UID3 =
TARGET.CAPABILITY = ReadDeviceData WriteDeviceData
From elsewhere I knew that those capabilities require the application to pass the Symbian-Signed process. Currently my app was just self-signed, as this is the QtCreator's default setting. I didn't want to setup the full signing process yet and my application does not require those capabilities at all, so I commented-out them, rebuild, and it didn't help at all :)
Even worse, after next few attempts, I started getting the same error as in here http://stackoverflow.com/questions/12705282/use-qjson-in-my-qt-symbain-app:
error: Installation failed: 'Failed to overwrite file owned by another package: c:\sys\bin\qjson.dll in (....)
Then I remembered that near those capabs in the qjson library's project file, there was a UID3 commented out! So, probably the build process has been using some temporary or random one, and it has changed! The installer cannot verify that I am in fact updating an old version, and thinks that some new incoming .sis file tries to overwrite a file that does not belong to it.
I've manually uninstalled the old package, updated the qjson project with
TARGET.UID3 = 0xE0123456
then rebuild and the installation succeeded. However, still it could not launch due to the security error, even with the spurious capabilities removed.
DLL Capability explanation
Here's an article that is a must-read if you are ever going to use DLLs on the newest versions of Symbian platform. You see, when I last touched the subject, there was no such thing as 'capabilities' on Symbian, and the other platforms like WP7 define them a bit differently. Anyways, the article is http://www.developer.nokia.com/Community/Wiki/Shared_Library_DLLs_on_Qt_for_Symbian
Inside there's a small section named http://www.developer.nokia.com/Community/Wiki/Shared_Library_DLLs_on_Qt_for_Symbian#Capabilities Set platform security capabilities. In this section a very important phrase is seen:
Capabilities are treated slightly differently for EXES and DLLs. In essence, while an EXE must be granted the capabilities required to call the APIs that it uses (or which are used by its loaded DLLs), a DLL must be given all the capabilities of all the EXEs that might need to load it. For a DLL used by a single application exe this would be the same as the application's capabilities. If however the DLL is to be used by arbitrary clients, you will need to give it as many capabilities as possible.
and also, far later:
Note that the application .pro file should also specify all the capabilities that the EXE needs to use any protected API that it calls or the DLL calls - the DLL should have all the capabilities specified in the EXE (and it may have more).
What does it mean? In EXEs the Capabilities are specifying what that EXE is allowed to try to use. If an EXE tries to read the device IDs, it needs ReadDeviceData, or else an error will be rised. The DLLs in turn are always using the capabs that the calling EXE provides - otherwise it would be dumb or useless in terms of security. Thus, specifying Capabilities on a DLL project does not provide any access rights to the DLL. If a DLL reads device IDs, then the calling EXE must have the Capabilities specified..
However, the Capabilities are also used in DLLs projects, but their meaning is drastically changed: now they specify in what contexts the DLL is safe to be used. They are a means of describing the DLL safety. For example, if a DLL is marked by Capability ReadDeviceData, it could mean for example that it has been checked to not peek some user-critical data and send them over the internet, and therefore this DLL is safe to be used by applications that have ReadDeviceData flag..
All those facts taken together create a simple security rule:
If your application has some Capabilities specified, then all DLLs that are loaded by the application must have at least all those Capabilities.
In the example of my project, my application had specified 'NetworkServices', and the QJson library by default has 'ReadDeviceData WriteDeviceData'. It is a complete mismatch, and when the OS tried to run my application, it discovered that my "network-related application" tried to load a DLL that is "not safe" in terms of networking, so it halted the process..
Solution
The solution is very simple. I've just had to leave my application project as it was, with no changes, and only add the network capability to the QJson's project (to mark it as safe-to-use-with-network):
TARGET.UID3 = 0xE0123456
TARGET.CAPABILITY = ReadDeviceData WriteDeviceData NetworkServices
Please note that I even did not have to remove the *DeviceData capabilities: my application does not have them.
Better fix?
According to the Nokia's document and to simple reasoning, the DLLs should have the widest possible Capabilities assigned, especially if they are to be by different projects for different applications.
Thus, I cannot fanthom why the QJson library comes only with *DeviceData capabilities. Actually, JSON format is heavily related to networking, so it is quite obvious that the application that use this library will have NetworkServices capability!
I'll file a patch to the project with more capabilities added. In the meantime, please remember that if you use a DLL project, you must ensure that the DLL capabs are at least as wide as your EXE's.