Date post: | 14-Oct-2014 |
Category: |
Documents |
Upload: | eduardo-gorio |
View: | 76 times |
Download: | 0 times |
Qt for Maemo Developer's Guide v0.5 Beta
Maemo for Mobile Developers
CHAPTER 1: INTRODUCTION
1 WHAT IS MAEMO AND QT? ........................................................................................................ 8
2 MAEMO COMMUNITY................................................................................................................... 9
3 WHAT MAEMO CAN DO? ...........................................................................................................10
4 WHAT’S NEW IN MAEMO 5 (FREMANTLE)? .......................................................................11
CHAPTER 2: GETTING STARTED
1 MAEMO SDK CONCEPTS ............................................................................................................14
2 INSTALL DEVELOPMENT ENVIRONMENT...........................................................................15
2.1 INSTALL VMWARE (WINDOWS OS / MAC OS)........................................................................15 2.2 INSTALL SCRATCHBOX..................................................................................................................16 2.3 INSTALL MAEMO SDK AND NOKIA BINARIES .............................................................................16 2.4 INSTALL QT ON SCRATCHBOX......................................................................................................17
3 CREATE A QT PROJECT..............................................................................................................18
4 COMPILE THE APPLICATION...................................................................................................18
5 RUN THE APPLICATION ON THE EMULATOR....................................................................19
5.1 START THE SDK UI ......................................................................................................................19 5.2 RUN THE APPLICATION.................................................................................................................20 5.3 CLOSE THE SDK UI.......................................................................................................................20
6 TEST THE APPLICATION ON A DEVICE ................................................................................21
6.1 T PA ......................................................................................................21LOY APPLICATION TO THE DEVICE USING
INSTALL Q CKAGES ........... 6.2 EP SSH.....................................................................226.2.1 INSTALL SSH ON THE DEVICE.................................................................................................................226.2.2 TRANSFER THE APPLICATION TO THE DEVICE............................
D
.........................................................236.3 DEPLOY THE APPLICATION USING PCCONNECTIVITY........... ERROR! BOOKMARK NOT DEFINED. 6.4 RUN THE APPLICATION ON DEVICE ..............................................................................................23
7 CREATE A DEBIAN INSTALLATION PACKAGE ...................................................................24
7.1 EDIT THE RULES FILE ....................................................................................................................25 7.2 EDIT THE CONTROL FILE...............................................................................................................26 7.3 EDIT THE CHANGELOG FILE ..........................................................................................................27 7.4 MAKE THE APPLICATION VISIBLE IN THE MENU WITH A .DESKTOP FILE ..................................27 7.5 CHANGE THE .PRO FILE .................................................................................................................28 7.6 BUILD THE PACKAGE.....................................................................................................................29
Maemo for Mobile Developers
7.7 INSTALL THE PACKAGE ON DEVICE...............................................................................................30
CHAPTER 3: USING ESBOX IDE
1 PREREQUISITES ...........................................................................................................................31
2 INSTALL AND SETUP ESBOX ON WINDOWS.......................................................................32
2.1 INSTALL SSH SERVER.....................................................................................................................35
3 INSTALL AND SETUP ESBOX ON LINUX ...............................................................................35
4 COMPILE THE APPLICATION ON ESBOX..............................................................................36
4.1 RUN THE APPLICATION ON ESBOX ............................................................................................39
5 CREATE A DEBIAN INSTALLATION FILE..............................................................................41
6 DEPLOY THE APPLICATION TO THE DEVICE.....................................................................43
CHAPTER 4 QT FOR MAEMO IMPLEMENTATION NOTES
1 PLATFORM SPECIFIC CHANGES..............................................................................................45
2 PORTING A QT APPLICATION TO MAEMO..........................................................................48
3 UPLOADING THE APPLICATION TO GARAGE ....................................................................49
4 LINKS ...............................................................................................................................................49
CHAPTER 5: USING MAEMO APIS IN QT APPLICATIONS
1 LIBLOCATION................................................................................................................................50
1.1 A ES AND DS.....................................................................................................501.1.1 LOCATIONGPSDEVICE.............................................................................................................................501.1.2 LOCATIONGPSDCONTROL .....................................................................................................................52
M IN CLASS METHO
1.2 LOCATIONDISTANCEUTILS .........................................................................................................53 1.3 LIBLOCATION EXAMPLE ...............................................................................................................53 1.4 LINKS .............................................................................................................................................59
2 LIBCITYINFO .................................................................................................................................59
2.1 EXAMPLE .......................................................................................................................................59
3 MCEDEV.........................................................................................................................................62
3.1 MCE HEADERS FILES.....................................................................................................................63 3.2 QT MCEDEV EXAMPLE..................................................................................................................64
Maemo for Mobile Developers
4 CALENDARBACKEND ................................................................................................................66
4.1 MAIN CLASSES AND METHODS.....................................................................................................67 4.2 EXAMPLE .......................................................................................................................................68 4.3 LINKS .............................................................................................................................................74
5 ICD2..................................................................................................................................................75
5.1 INTRODUCTION .............................................................................................................................75 5.2 ARCHITECTURE .............................................................................................................................75 5.3 A ...... ..........................................................................765.4 XAMPLE .......................................................................................................................................78
TERNET CONNECTION DA N 2 EXAMPLE ..................................................................................78
M IN CLASSES AND METHODS....... .............. E
5.4.1 IN EMO
5.5 INKS .............................................................................................................................................83 OCUMENTATION/MAEMO 5 DEVELOPER GUON
L 5.5.1 D IDE/USING CONNECTIVITY
NTS/MAEMO
COMP E CONNECTIVITY ..............................................................................................................835.5.2 INTERNET CONNECTIVITY DAEMON VERSION 2..................................................................................845.5.3 BIBLIOGRAPHY..........................................................................................................................................84
6 A GUI EXAMPLE............................................................................................................................84
6.1 INTRODUCTION .............................................................................................................................84 6.2 AI D METHODS......................................................................................................85
M N CLASSES AN 6.3 XAMPLE .......................................................................................................................................856.3.1 MAIN WINDOW .........................................................................................................................................876.3.2 TABLE.........................................................................................................................................................91
E
6.4 LINKS .............................................................................................................................................95
7 WHACAMOLE GAME EXAMPLE ............................................................................................95
7.1 ..................................................................................................................95MPLE ........
INTRODUCTION............ 7.2 XA ...............................................................................................................................96
AME MAIN WIND
E 7.2.1 G OW ..............................................................................................................................96
AIN SCREEN...........
7.2.2 M .................................................................................................................................97ECORDS SCREEN ............
7.2.3 R .........................................................................................................................98
ME CONT
7.2.4 GA ROLLER .............................................................................................................................. 1007.2.5 GRAPHICS VIEW WIDGET...................................................................................................................... 1017.2.6 MOLE ITEM ............................................................................................................................................. 103 7.3 LINKS ..........................................................................................................................................104
8 CAPTURING KEY EVENTS....................................................................................................... 105
8.1 EXAMPLE .................................................................................................................................... 105
CHAPTER 6: ADDITIONAL MAEMO TOOLS
1 MISCELLANEOUS....................................................................................................................... 107
1.1 SCREENSHOTTOOL....................................................................................................................107 1.2 HOMEIP...................................................................................................................................... 107 1.3 DPKG AND APT...........................................................................................................................108
Maemo for Mobile Developers
2 NETWORKING............................................................................................................................ 109
2.1 IPUTILS ....................................................................................................................................... 109 2.2 NETCAT....................................................................................................................................... 111 2.3 TCPDUMP.................................................................................................................................... 113 2.4 TRACEROUTE..............................................................................................................................113 2.5 NSLOOKUP .................................................................................................................................. 114 2.6 WGET..........................................................................................................................................114
3 WIRELESS TOOLS ..................................................................................................................... 114
3.1 BLUETOOTH TOOLS....................................................................................................................114 3.2 WIRELESSTOOLS.......................................................................................................................115
4 TEST AUTOMATION................................................................................................................. 116
4.1 SPTESTS..................................................................................................................................... 116 4.2 XNEE............................................................................................................................................117 4.3 XRESPONSE................................................................................................................................. 117
5 RESOURCE USAGE..................................................................................................................... 117
5.1 HTOP...........................................................................................................................................117 5.2 SPMEMUSAGE............................................................................................................................118 5.3 SPSMAPSMEASURE ..................................................................................................................122 5.4 SPSMAPSVISUALIZE.................................................................................................................123 5.5 XRESTOP..................................................................................................................................... 123
CHAPTER 7: DEBUGGING AND PROFILING
1 DEBUGGING ................................................................................................................................124
1.1 LS.........................................................................................................................125MAEM ‐DEBUG‐SCRI
G ENERAL TOO
1.1.1 O PTS...................................................................................................................... 125NATIVE‐GDB .... ........
1.1.2 .. ............................................................................................................................. 1261.1.3 DEBUG‐DEP‐INSTALL ............................................................................................................................ 126
IST‐MMAPPED‐LIBS .................. 1.1.4 L ........................................................................................................... 127B.................................... ..... ...... ....................
1.2 D .. ... ................................................................... 127
STALLING AND TESTING GDB ......
G . 1.2.1 IN ..................................................................................................... 128
EBUGGING WITH
1.2.2 D NATIVE‐GDB ON SCRATCHBOX ........................................................................... 129
EBUGGING WITH GDB
1.2.3 D ON DEVICE ..................................................................................................... 134
ORE DU
1.2.4 C MP FILES.................................................................................................................................. 1381.2.5 SP‐ERROR‐VISUALIZER ......................................................................................................................... 1431.2.6 SYSLOG .................................................................................................................................................... 143
2 PROFILING ..................................................................................................................................143
2.1 A ...... ... ................................................................................. 144ROFILE ..... ................. ................ ..........
V LGRIND..... ................. ................... 2.2 P ...... .. ... ........................................................................ 1492.2.1 INSTALLING OPROFILE ON SCRATCHBOX.......................................................................................... 1492.2.2 INSTALLING OPROFILE ON INTERNET TABLET................................................................................ 149
O
Maemo for Mobile Developers
2.2.3 FILE................................................................................................................................... 1512.2.4 OPROFILE WITH CALLGRAPH .............................................................................................................. 1552.2.5 OPROFILEUI ............................................................................................................................................ 157
USING OPRO
2.3 STRACE ....................................................................................................................................... 158 2.4 LTRACE ....................................................................................................................................... 162
Maemo for Mobile Developers
Maemo for Mobile Developers
Chapter 1 Introduction This document is targeted for developers interested in developing and porting Qt applications
for Maemo. Qt application development environment is currently relying on the underlying
Maemo toolchain. This document provides step‐by‐step instructions how to set up
development environment, and how to create, compile, and run a simple Qt project on the
emulator and on target. It also covers Maemo‐specific considerations and presents how to use
Maemo APIs in Qt applications. Debugging, profiling, and additional Maemo development
tools are also covered.
1 What is Maemo and Qt? Maemo is an open source development platform originally use in Internet Tablets (Nokia 770,
Nokia N800 and Nokia N810). The Maemo platform itself is the set of software components
used to develop and test software for Nokia Maemo devices. It is built from large parts of open
source projects.
The Maemo operating system is based on Debian GNU/Linux
(http://www.debian.org/index.en.html). As it was designed for resource constrained devices, a
lot of changes and new features where required to make it best fit to the target characteristics
such as smaller screens, battery powered, multiple input methods, etc. One of the most
important is the Hildon UI application framework. Hildon was designed by Nokia to provide
mobile device oriented functionality (ex.: finger‐friendly interface), but also provides
functionalities common to desktop environments such as task navigator, control panel, status
bar, etc. Hildon is based on GTK+ and makes part of the GNOME project.
The Maemo SDK contains tools required to create, build, test and port applications to
Maemo platform. The base programming language is C, but it also supports C++ and Python
through bindings and Qt. One important concept brought by the SDK is the Scratchbox.
Scratchbox (http://www.scratchbox.org/) is a cross‐compilation toolkit designed to make
easier the embedded Linux application development. The main task of Scratchbox is to enable
compilation to ARM processors which are used in Internet Tablets. To do this Scratchbox uses
a cross compiler that is able to create binaries to a platform different from the one that makes
the compilation (ex.: create binaries for ARM from an X86 machine).
Qt is a cross‐platform application and UI framework. Using Qt, you can write applications
once and deploy them across desktop, mobile and embedded operating systems without
rewriting the source code. Qt features intuitive C++ class library, portability across desktop and
embedded operating systems, integrated development tools with cross‐platform IDE (in
officially supported platforms), and high runtime performance and small footprint on
embedded. Qt 4.5 is adapted to Maemo/Hildon and currently provided as a community port
for Diablo and Fremantle (the 4.5.3 version of this is used in the in the Getting Started
instructions in this document). Qt 4.6 will be officially supported in Maemo in Harmattan
Maemo for Mobile Developers
where all applications are built on top of Qt. In October 2009 Nokia also announced that it will
officially support Qt 4.6 already in Fremantle as a technology preview, available at
http://qt.nokia.com/developer/qt‐for‐maemo‐developers.
2 Maemo community The Maemo open community has over 16.000 registered members that contribute to
more than 700 development projects. It works with open source tools and processes. The
community members are able to develop new software for both the platform itself and on top
of the platform. Applications developed with the Maemo SDK are used today by thousands of
consumers.
The community has a wide number of tools and services to easier the development
process and keep close with the community needs. The most important are:
Garage (https://garage.maemo.org/) which is meant for hosting software
projects related to the Maemo development platform. Any developer can host
Maemo‐related projects in garage. Don’t have an account? Create one here:
https://garage.maemo.org/account/register.php.
Planet Maemo (http://maemo.org/news/planet‐maemo/) which is a blog hub
for Maemo developers. If can create your own blog and aggregate to this hub.
Aggregate now! (http://maemo.org/news/planet‐
maemo/aggregate_your_blog/)
Maemo bug report (http://maemo.org/development/bugs/) enables
developers to report problems with the Maemo platform.
Maemo Feature Request
(https://garage.maemo.org/tracker/?func=browse&group_id=29&atid=188)
shows that Maemo is close to the community and wish to receive its
contribution and opinion.
Maemo extras repository (http://maemo.org/community/application‐
catalog/extras_repository/) allows developers to host applications to be
distributed to the Maemo users directly on their devices with no cost for the
developer.
#maemo freenode
(http://irc.netsplit.de/channels/details.php?room=%23maemo&net=freenode)
is the Maemo IRC channel for developers to free talk about the platform,
consult friends, share opinions, etc.
Maemo Mailing lists (http://wiki.maemo.org/Community_mailing_lists) allows
users, developers, community to discuss about Maemo platform. The following
lists are available:
o maemo‐announce (https://lists.maemo.org/mailman/listinfo/maemo‐
announce) News and updates about maemo.org and Maemo
o maemo‐users (https://lists.maemo.org/mailman/listinfo/maemo‐
users) For Maemo users
Maemo for Mobile Developers
o maemo‐developers
(https://lists.maemo.org/mailman/listinfo/maemo‐developers) For
Maemo developers and hackers
o maemo‐
community (https://lists.maemo.org/mailman/listinfo/maemo‐
community) For maemo.org web and community‐process related
discussions
o maemo‐commits (https://lists.maemo.org/mailman/listinfo/maemo‐
commits) For following Maemo svn commit activity
The picture below shows the most important projects related to the Maemo platform.
3 What Maemo can do? Maemo platform provides support for development that targets all the important
technologies categories required for mobile devices. The most important components for each
category are given below:
Maemo for Mobile Developers
4 What’s new in Maemo 5 (Fremantle)? Maemo 5 aka Fremantle is the new version of the Maemo platform. It brings a lot of
new features. The most noticeable are given below:
Hardware
o Accelerated graphics with OpenGL ES 2.0
o OMAP3 architecture
o HSPA ( High Speed Packet Access / Cellular 3G connectivity )
o High resolution camera
o Acceleration sensor
Base services
o A2DP (Advanced Audio Distribution Profile) and AVRCP (Audio/Video
Remote Control Profile) for an improved Bluetooth interactions
o Compositing window manager
Application framework
o Suport to Qt 4.5 (a community port from Forum Nokia)
UI
o New UI style
o Animated UI technologies
New API's
o Clutter: advanced and easy to use graphical API
o Location API: methods to build location‐aware applications.
Maemo for Mobile Developers
o City Information: methods to obtain information about cities, including
city name, country name, and country code.
o Time management: an interface for handling time change notifications
and collect relevant time and time zone information.
o Vibration service: methods for triggering and controlling vibrations.
o Device orientation: respond to changes in orientation and discover
current orientation
o Alarm service
Top framework level changes from Diablo
o Removal of left side Task Navigator and plug‐ins
o Removal of stylus keyboard
o New design for task switching and task handling
o Renewal of Home and Status bar
o New design for incoming event previews and indications
o Widgets and application space renewal
o UI style changes. E.g.: Navigation logic in applications, visual style of
dialogs, menus etc
Desktop changes o In home screen there is only application menu button and applets
o Applications are now in applications menu o Bigger icons
New file chooser
Maemo for Mobile Developers
o Kinetic scroll
Maemo for Mobile Developers
Chapter 2 Getting started with Qt development on Maemo
1 Maemo SDK concepts
The Maemo hardware architecture is different from PC or Mac architecture, as it is based on
an ARM processor. Thus, to create Maemo executable codes using a PC or Mac machine, we
need a compiler that runs on these machines and compiles codes for the ARM architecture.
Compilers that do this work are called cross‐compilers.
The Maemo Software Development Kit (Maemo SDK) contains Scratchbox. It is the
base of Maemo SDK a toolkit, containing a cross‐compiler and other tools, which creates a
complete Maemo development environment. The Maemo SDK emulates the operating system
on the device, but with development tools added.
The Maemo SDK is officially supported only on Debian and Ubuntu Linux distributions,
but installing Maemo SDK is also possible for other distributions. On other operating systems
such as Windows, a Virtual Machine can be used to provide a working Linux environment.
Virtual Machines are software containers that can emulate a real machine and run one
operating system as if it was in a physical computer. Thus, to develop for Maemo in a Windows
or Mac machine, it is possible to use a Virtual Machine running Linux with Maemo SDK.
Developing software using the Maemo SDK is quite similar to using a Symbian OS SDK.
You write, compile, and run the code, usually using an Integrated Development Environment
(for example, Carbide.c++ for S60, Visual Studio for Windows Mobile, or ESbox + Eclipse for the
Maemo platform). The Symbian OS SDKs include a phone simulator, which is a Windows
executable capable to run Symbian OS software on an x86 workstation. The Windows Mobile
SDK kit also includes similar phone emulators and is capable of running .NET Compact
Framework software.
The Maemo SDK provides an emulator in a similar way, so it is possible to run Maemo
applications inside it. The Maemo SDK is quite accurate in emulating the environment in a real
device, but it isn't identical. Especially applications that make use of the device's special
hardware can behave differently on the device than on Maemo SDK. They even may not work
at all. Fortunately, testing the software on device is quite straightforward using either SSH, SCP
or a tool called sbrsh. These tools are capable to quickly copy and run your application on the
device during the development.
Qt is a cross‐platform application and UI framework, which can be used on the Maemo
platform together with Scratchbox, Maemo SDK, and Eclipse IDE (EsBox). The following
Maemo for Mobile Developers
sections describe the steps that you need to do in order to setup a Qt for Maemo development
environment.
2 Install development environment
2.1 Install VMWare (Windows OS / MAC OS)
If you are working on a machine with the Microsoft Windows Operating System, you can emulate a Linux environment to be able to work with the Maemo SDK. In principle virtual machine is not needed if you use Linux as the native OS but even then it is possible to use the Maemo virtual image if you do not want to change your system installing the Maemo SDK packages. To emulate a Linux environment you need to setup a virtual machine where you will install and run the Maemo SDK. The Linux environment emulated can be a virtual image pre‐configured containing Maemo SDK with all files and tools installed. These images, available at http://maemovmware.garage.maemo.org/, will help us to get a full development environment easily. The basic difference between Windows and Mac is the virtual machine emulator that you will use. On Windows the virtual machine emulator recommended is the VMWare player
(http://www.vmware.com/products/player/). On Mac the virtual machine emulator recommended is the VMWare fusion (http://www.vmware.com/products/fusion/). Another alternative is Virtual Box (http://www.virtualbox.org/).
To setup VMware image:
1. Download and install the latest version of the virtual machine suitable for your operating system (VMWare player, VMWare fusion or Virtual Box);
2. Once you have installed the virtual machine program, go to Maemo SDK VMware Appliance and download the Maemo SDK virtual image. These virtual images come with all files and applications needed to develop for Maemo. If you get an image which comes in two parts (for example maemosdk_desktop_intrepid‐10‐08.zip.001 and maemosdk_desktop_intrepid‐10‐08.zip.002), decompress it using 7-zip. To decompress on Windows, just right click over the file with “.001” extension and select 7‐zip ‐> Extract files. On Linux, navigate to the folder where the .7z file(s) are located (type "cd /path/to/folder" for example without quotes) and run the following command:
$7z x FileName.001
3. Start the installed virtual machine program; 4. Click Open button on the virtual machine program, navigate to the directory
where the VMWare SDK package is, and choose the <maemoxxxx>*.vmx file; 5. Click OK to launch the Linux virtual machine containing the Maemo SDK
environment; 6. Once the Virtual Machine starts up, if required, log in with (username/password):
maemo/maemo. 7. Once the Virtual Machine starts up, you should open a terminal and run the
command:
$/scratchbox/login
Maemo for Mobile Developers
8. Now that you are logged in the Scratchbox, you can compile and run programs for Maemo.
2.2 Install Scratchbox
The Maemo SDK can be installed on operating systems considered native environments
directly. For Linux operating system, the Maemo SDK installation is quite easy. It comes with
two installation scripts:
Scratchbox installer (http://repository.maemo.org/unstable/5.0beta/maemo‐scratchbox‐install_5.0beta.sh) script which downloads and installs the required version of Scratchbox onto your host machine;
Maemo SDK installer (http://repository.maemo.org/unstable/5.0beta/maemo‐sdk‐install_5.0beta.sh) which installs the SDK packages and sets up two targets (arm architecture and x86 architecture) inside Scratchbox.
Maemo SDK also provides essential Nokia proprietary binary packages needed for Maemo development from an authenticated repository. In order to have access to this repository, you will need to accept the End User License Agreement (EULA).
To install Scratchbox follow the steps below:
1. Get Scratchbox installation script from:
http://repository.maemo.org/unstable/5.0beta/maemo‐scratchbox‐install_5.0beta.sh
2. Open a console; 3. Run the following command with root permission:
$sh maemo-scratchbox-install_5.0beta.sh
4. The installation script adds the current user to “sbox” user group. For the group membership to be effective in the current terminal session, run the command:
$newgrp sbox
5. Add a username to scratchbox by executing the command:
$/scratchbox/sbin/sbox_adduser <username>
6. Add the group sbox to the user by executing the command:
$groupadd sbox
2.3 Install Maemo SDK and Nokia binaries
After Scratchbox installation you can install Maemo SDK. To do this, follow the steps below:
Maemo for Mobile Developers
1. Get Maemo SDK Fremantle installer from:
"http://repository.maemo.org/unstable/5.0beta/maemo‐sdk‐install_5.0beta.sh"
2. Open a console; 3. Run the command:
$sh maemo-sdk-install_5.0beta.sh
Maemo SDK needs an X11 server to provide a device screen for the developer on the host machine. The X11 server used to do this work is the Xephyr X11 server software. On Debian based linux systems, Xephyr can be installed outside scratchbox environment using apt with root permission. To install, just run following command:
$sudo apt-get install xserver-xephyr
Now you are able to login to Scratchbox by executing /scratchbox/login. After login, install
Nokia binaries that are essential for the complete functionality of the Maemo SDK.
4. Open this webpage (http://tablets-dev.nokia.com/eula/index.php) in your preferred browser and accept the EULA;
5. Follow the instructions in the next page to add one line to the file /etc/apt/sources.list inside Scratchbox for both x86 and ARMEL targets;
6. To install the nokia‐binaries packages, execute these commands inside Scratchbox:
$apt-get update
$fakeroot apt-get install nokia-binaries
7. This will install nokia‐binaries just for one target. To install on the other target run the command sb‐menu inside Scratchbox to change the target and run the commands above.
8. The Maemo SDK is now prepared to provide all tools to develop with C language. If you want to develop with C++ language, complete the installation by running the following command inside Scratchbox:
$fakeroot apt-get install libhildonmm-dev libhildonmm maemo-cplusplus-env libossomm-dev
Now you would be able to compile and run C/C++ programs for Maemo (for more info, check this this website (http://maemo.org/development/sdks/maemo_5‐0_installation/)). However, we continue with the installation of Qt in next sections.
2.4 Install Qt on Scratchbox
Now that we have installed Scratchbox and Maemo SDK, we can install Qt. We will use the
community port based on Qt 4.5.3.
1. To install Qt on Scratchbox follow the steps below:
Maemo for Mobile Developers
Open a terminal and run the command:
$/scratchbox/login
2. Now edit the file /etc/apt/sources.list. At the moment of writing, the Qt for Maemo libraries were in the extras‐devel repository. To get it visible, add the Fremantle extra‐devel by adding the following line:
deb http://repository.maemo.org/extras-devel/ fremantle free non-free
3. Run the following command to update the apt cache:
$apt-get update
4. To install the Qt binaries, run:
$fakeroot apt-get install libqt4-gui
5. To install the development packages, run:
$fakeroot apt-get install libqt4-dev
The above command installs some basic UI packages. To install other Qt modules, for example Webkit or OpenGL (ES 2.0), you have to run:
$fakeroot apt-get install libqt4-webkit libqt4-opengl
3 Create a Qt project
This application creates a label on the Maemo screen displaying the “Hello World” string. The
following code shows the content of hello.cpp:
#include <QApplication> #include <QLabel> int main(int argc, char* argv[]) { QApplication app(argc,argv); QLabel *label = new QLabel("Hello World!"); label->show(); return app.exec(); }
4 Compile the application
In order to compile your Qt Hello World application you need to login in the
Scratchbox using the following command:
$ /scratchbox/login
Maemo for Mobile Developers
Then, create a folder to hold the Hello World application. To do this you may run the
following command:
$ mkdir /home/maemo/workspaceqt/hello
Copy the hello.cpp to the created folder and run the following commands to build
the application:
$ qmake -project
$ qmake hello.pro
$ make
The first command creates the file hello.pro that defines a Qt project. It contains
the files to be compiled, libraries to link with, etc. For more information about Qt project files
go to qt projects file (http://doc.trolltech.com/4.1/qmake‐project‐files.html#project‐
templates) page. The second command creates the Makefile file which contains directives
to compile the project. The last command compiles the project using the Makefile file
creating the hello file which is the executable. The .pro file of the “Hello World” project
is shown below (Notice that the TARGET entry is not automatically filled by the qmake –
project command):
# hello.pro TEMPLATE = app TARGET = hello DEPENDPATH += . INCLUDEPATH += . # Input SOURCES += hello.cpp
5 Run the application on the emulator
5.1 Start the SDK UI
Follow these steps to start the Maemo SDK:
1. Run Xephyr outside Scratchbox environment:
$ Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac -kb &
2. Inside Scratchbox, set the DISPLAY variable to match the display setting given for the
Xephyr server above, so the SDK can find the X server window
$ export DISPLAY=:2
3. Inside Scratchbox, initiate the UI framework (NOTE: a script o can be created on
Linux to run these commands easily. Take a look at How to Create a First Shell Script (http://www.linfo.org/create_shell_1.html))
$ af-sb-init.sh start
Maemo for Mobile Developers
You will see the following screen on your Xephyr window:
5.2 Run the application
With the Maemo SDK running, execute the Hello World application with the following
command.
$ run-standalone.sh ./hello
After that, the Hello World application will start on the Xephyr window.
5.3 Close the SDK UI When you finish the development, you can stop the Maemo SDK running:
$ af-sb-init.sh stop
Maemo for Mobile Developers
6 Test the application on a device To run the application or install debian packages on device it is necessary to copy them to
it. There is at least two ways to do that. The first way, consists of using PC‐connectivity project
to configure a connection from PC to the tablet through USB, Bluetooth or WLAN connections.
The second way consists in connecting manually the PC and tablet through WLAN interface of
the Internet tablet. First, you however need to install the Qt packages on the device.
6.1 Install Qt packages
Before run Qt applications on devices, the installation of some Qt packages is required. At the moment of writing , Qt libraries were in the extras‐devel repository. To install packages, follow the steps below:
1. Open the Application Manager in the device and make sure Extras‐devel is enabled (go
to menu > Application Catalogue). If there is no Extras‐devel catalogue in the list you
can create one. Inside Applications Catalogue window press the New button and fill
out the dialog box that appear with the following information:
Catalogue name: Extras‐devel
Web address: http://repository.maemo.org/extras‐devel
Distribution: fremantle
Components: free non‐free
2. After this, press “Save” button; 3. Open an ssh session with the device:
PC_$> ssh root@DEVICE-IP
Maemo for Mobile Developers
4. To install the Qt binaries, run:
#apt-get install libqt4-gui
5. To install other Qt modules, for example Webkit, DBus or OpenGL (ES 2.0), you have to run:
#apt-get install libqt4-webkit libqt4-opengl libqt4-dbus
NOTE: The Qt 4.5.3 packages are expected to be moved under Extras repository in near
future.
6.2 Deploy application to the device
6.2.1 Install SSH on the device
To communicate with a device, which allows install and run applications, the
installation of an SSH (http://wiki.maemo.org/SSH) server in the tablet is required. To do this,
open the Application Manager in the device and make sure Extras is enabled (go to menu >
Application Catalogue). If there is no Extras catalogue in the list you can create one. Inside
Applications Catalogue window press the New button and fill out the dialog box that appear
with the following information:
Catalogue name: Extras
Web address: http://repository.maemo.org/extras
Distribution: fremantle
Components: free
Maemo for Mobile Developers
After this, press Save button and then search for the package openssh‐server. Install
the packaging selecting it from the list.
6.2.2 Install PCConnectivity The PC‐Connectivity project provides tools to easily setup the connection between PC
and the Internet Tablet. The connection can be done through USB, WLAN and Bluetooth.
Installation instructions of PC‐connectivity can be found http://pc‐
connectivity.garage.maemo.org/installation.html. Detailed user guide can be found http://pc‐
connectivity.garage.maemo.org/documentation.html. Note when installing the PC‐
Connectivity also the openssh‐server package will be installed on the device.
6.2.3 Copy the application to the device
Now you can copy the application from the PC to the folder /home/user in the tablet. If
you use Linux or Mac, the developer can use the scp command as shown below:
PC_$> scp filename root@DEVICE-IP:/home/user
If you use Windows you can use Winscp (http://www.winscp.net/). More information
about how to configure Winscp, how to transfer files and how to execute commands can be
found here: http://winscp.net/eng/docs/guides.
6.3 Run the application on device We can now run the application on the device. To execute the application run the
following commands in the shell. The first command opens a ssh session with the device. The
next two commands gains privileges of super user and runs the application. If you are using
Maemo for Mobile Developers
Winscp you need to open a terminal (select Commands > Open terminal) and run the last two
commands.
PC_$> ssh root@DEVICE-IP tablet_#> su - user tablet_$> run-standalone.sh ./hello
Note that testing an application on a device without a Debian installation package does
not detect any dependencies to libraries. Also the application cannot be then run on from the
application shell.
7 Create a Debian installation package
In the Section 6.3,"Run the application on device" we already tested the compiled project
on the device. However, it is required to create a Debian installation package to enable
installation and uninstallation with dependency handling and version control, and to create an
application hierarchy (to, for example, copy data files into correct directories). Also you can
define application icon and name so that users can launch the application from the application
shell.
The first step to create the debian package for a Qt application is to change the folder
name of your project. This is required by the dh_make tool to create the basic structure of the
package. The naming convention accepted by dh_make tool is (if dh_make is not installed, run
“apt‐get install dh_make”):
<project>-<version>
Change the Hello World project folder to helloworld-1.0. After this, run the
following dh_make command inside the project folder to create a basic package structure (run
“man dh_make” for more information):
dh_make --createorig --single -e [email protected] -c gpl
This command makes a copy of the original source archive (--createorig), sets the
package class to single application (--single), sets the maintainer e‐mail address to the given
e‐mail (-e <e-mail>) and sets the license (-c). dh_make creates the folder debian/ inside
the project folder with the files needed to generate the debian package. The most important
files are:
debian/rules
debian/control
debian/copyright
debian/compat
debian/changelog
The following sections show how to do the modifications needed in the files inside the
debian/ folder. Also, it shows the .desktop file, which contains application information such as
name, icon, etc. that are used to show the application in Maemo UI. Next, the changes needed
Maemo for Mobile Developers
in the .pro file to copy the.desktop file and icon files to Maemo are explained. At the end,
the commands to build and install the package are shown.
7.1 Edit the rules file This file is a Makefile which effectively run the commands to build the package,
including the sources compilation. The default file generated by dh_make doesn’t know how
to build Qt applications, so the file has to be updated to do this. The following code contains
the adaptations to the rules file needed to build a Qt package. The only change you need to do
is the entry APPNAME. In the case of the Hello World application package the file used is the
following.
#!/usr/bin/make -f APPNAME := Hello builddir: mkdir -p builddir builddir/Makefile: builddir cd builddir && qmake-qt4 PREFIX=/usr ../$(APPNAME).pro build: build-stamp build-stamp: builddir/Makefile dh_testdir # Add here commands to compile the package. cd builddir && $(MAKE) touch $@ clean: dh_testdir dh_testroot rm -f build-stamp # Add here commands to clean up after the build process. rm -rf builddir dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/your_appname cd builddir && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/$(APPNAME) install # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here.
NOTE: The empty space of each line should begin with TAB characters instead of
multiple space characters. If you copy this chunk, you most probably get spaces
instead of tabs and the file will not be correct. So, change spaces into TAB characters.
Maemo for Mobile Developers
binary-arch: build install dh_testdir dh_testroot dh_installdocs dh_installexamples dh_installman dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure
7.2 Edit the control file This file specifies package data like name, dependencies and description for both
source and binary packages. To generate the package for Maemo, the following entries are
important:
Section: this entry is used by the Maemo Application Manager to select which
packages it will show. By default the Application Manager shows only packages that
belong to the user segment. As a result, the Section entry should assume the following
form:
Section: user/SUBSECTION
where SUBSECTION, may assume one of the values from the table below.
Subsection Keyword
Accessories user/accessories
Communication user/communication
Games user/games
Multimedia user/multimedia
Office user/Office
Other user/other
Programming user/programming
Support user/support
Themes user/themes
Tools user/tools
Maintainer: This field MUST be changed if the upstream package has been modified.
XB‐Maemo‐Icon‐26: It contains the PNG icon encoded in base64 visible in the
Application Manager. To encode such file from Scratchbox do the following:
apt-get update
Maemo for Mobile Developers
apt-get install sharutils uuencode -m <name of 26x26 image> > <name of 26x26 image>.base64
The control file to the Hello World application is shown below. Notice that there is a space in
the beginning of each new line of the sections Description and XB-Maemo-Icon-26.
Source: my-application Section: user/valid_subsection Priority: optional Maintainer: name surname <[email protected]> XSBC-Original-Maintainer: name surname <[email protected]> Build-Depends: debhelper (>= 5), libqt4-dev, OTHERS_BUILD DEPENDECIES Standards-Version: 3.7.3 Package: my-application Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: A simple test application A very simple application with a short description. Which spans multiple lines actually. XB-Maemo-Icon-26: iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABmJLR0QA/wD/AP+g vaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1gURDQoYya0JlwAAAU9J REFUSMftlL1KA0EUhb/NZl/ggnHQxsJUxt5CUucVJCCkDfgyKdIGG5/A0s5HEBtJ EdDAQGBgmw0YJmMzgXXYza5CtNkDW9zZw5z7c+ZCgwb/Ai3i9sVl/Bq8RIs4LRK1 gJDsKvJyNXmJMuYTsMoY1zpgozaABdYArQNPZQ1kfyGU7SpqVwxzAMwABWhgpIwp 4vWBB+AUWAI3ypjnfEXtPU4bLKx9vErTeCeiRSYF+fTn1j5dp2myE9EiU+DSi3wX ymeqRQAmZ3EcA5E/fgO6BULT8zhOcrwXoJdrXRa2Lgps2y2odAUcBUIXQdz78YyC SldAp8b7+bXrIv91qjZBietqCc2DjbAt4b2WxJkyZljVujlwp0U0cPxuLcAIuC+4 dKxFlsDJarvdAGP/b6hFnDImYs+uG3hbO2AB3Jbsur63tQM+fFx3bzZocEB8AdV2 gJBZgKTwAAAAAElFTkSuQmCC
7.3 Edit the changelog file This file describes the changes made in each package version. It is important because it
sets the version number to be used when the current package is to be generated.
If an upstream package is modified for Maemo, the Maemo revision string should be
appended to the upstream revision. For instance, if in Debian distribution the package name
was something like "Myapp‐0.4‐2", in Maemo this package could be called "Myapp‐0.4‐
2maemo1". The number after the "maemo" string is a progressive number.
7.4 Make the application visible in the menu with a .desktop file To make an application visible in Maemo menu, a Desktop file is needed for the application. If you don’t want to do this you can skip this session and go straight to Section 7.6,"Build the package". This file contains all the essential information needed to show the application entry in the menu, such as name, icon logical name, application binary file name, etc. The name of the file should be [application-name].desktop. The location in Maemo filesystem should be /usr/share/applications/hildon/. The desktop file is not generated by any tool, so it is necessary to create one. The
following example can be used. Just copy and paste the following content to the src/ folder
of your Qt project. If you don’t have a src/ folder, create one and copy the source code to
there.
Maemo for Mobile Developers
[Desktop Entry] Encoding=UTF-8 Version=0.1 Type=Application Name=myapp Exec=/usr/bin/myapp Icon=myapp X-HildonDesk-ShowInToolbar=true X-Osso-Type=application/x-executable
7.5 Change the .pro file At this point the project folder of your Qt application should be similar to this:
helloworld-1.0/ src/ hello.cpp hello.desktop hello.pro
It is necessary to make some modifications to the hello.pro file. They will copy the
.desktop file and the icon file to the right place in Maemo when installing the application. To
do this you just need to append some lines to the end of your .pro file. These lines will check
the right place to put the .desktop and the icons file. As it can be seen, the .desktop file goes to
the applications/hildon and the icon goes to pixmap and icons/hicolor folder. The
resultant hello.pro file is shown below.
# hello.pro TEMPLATE = app TARGET = hello DEPENDPATH += . INCLUDEPATH += . # Input SOURCES += hello.cpp # ----------------------------------------------------------------- # Added section # ----------------------------------------------------------------- unix { #VARIABLES isEmpty(PREFIX) { PREFIX = /usr/local } BINDIR = $$PREFIX/bin DATADIR =$$PREFIX/share DEFINES += DATADIR=\"$$DATADIR\" PKGDATADIR=\"$$PKGDATADIR\" #MAKE INSTALL INSTALLS += target desktop iconxpm icon26 icon40 icon64 target.path =$$BINDIR desktop.path = $$DATADIR/applications/hildon desktop.files += $${TARGET}.desktop
Maemo for Mobile Developers
iconxpm.path = $$DATADIR/pixmap iconxpm.files += ../data/maemo/$${TARGET}.xpm icon26.path = $$DATADIR/icons/hicolor/26x26/apps icon26.files += ../data/26x26/$${TARGET}.png icon40.path = $$DATADIR/icons/hicolor/40x40/apps icon40.files += ../data/40x40/$${TARGET}.png icon64.path = $$DATADIR/icons/hicolor/64x64/apps icon64.files += ../data/64x64/$${TARGET}.png }
It is also advised to verify the Qt version. You can do this moving the hello.pro file to the src
folder and renaming it to src.pro. The following command does this.
mv src/hello.pro src/src.pro
Then create a new hello.pro file in the project root folder.
# hello.pro QMAKEVERSION = $$[QMAKE_VERSION] ISQT4 = $$find(QMAKEVERSION, ^[2-9]) isEmpty( ISQT4 ) { error("Use the qmake include with Qt4.4 or greater, on Debian that is qmake-qt4"); } TEMPLATE = subdirs SUBDIRS = src
7.6 Build the package
Run the following command in the project root folder to generate the package. The
generated file will be created in the folder before the project root folder. Make sure you are
compiling in FREMANTLE_ARMEL target to generate the package suitable for the device.
$ dpkg-buildpackage -rfakeroot -b
Maemo for Mobile Developers
7.7 Install the package on device To install the generated debian package to a device, copy it to device like described in the
section 6,"Test the application on a device". Connect with the device using ssh an then install
the debian package by running the following command as root:
$ssh root@DEVICE‐IP
#dpkg ‐i filename.deb
If the desktop was created (as described in 7.4,"Make the application visible in the menu
with a .desktop file") the application will appear in the menu.
Maemo for Mobile Developers
Chapter 3 Using ESBox IDE Instead of using command line (shown in Chapter 2, Getting Started), it is possible to
create Qt applications for Maemo platform with an Eclipse‐Ganymede‐based IDE, ESBox (http://esbox.garage.maemo.org/beta1/installation_update_site.html).
ESBOX supports C/C++ and Python programming languages with source editing, code completion, build, launch, debug, profiling, and packaging generation.
ESBox may be used on all major platforms (Linux, Win32, Mac OS X). On non‐Linux systems, it is possible to use a Virtual Machine or a remote Linux system to host the Maemo SDK. ESbox will translate all IDE UI commands to SDK commands behind the scenes.
1 Prerequisites
Here, you will learn how to prepare the environment to use ESBox. The environment needs some prerequisites, which are listed below:
Java 1.5 or newer (http://java.com/en/download/manual.jsp)
Cygwin (http://www.cygwin.com/) (only for windows)
PC Connectivity (http://pc‐connectivity.garage.maemo.org/beta1/documentation_usbnet.html)
A Virtual Machine like QEMU, VirtualBox or VMWare (http://www.vmware.com/) (only for windows)
A Maemo SDK virtual image (http://maemovmware.garage.maemo.org/)
The Java will be used to host Eclipse. The Cygwin will be used to create an ssh server under Windows environment. The PC Connectivity will be used to easily configure of Cygwin ssh server and to deploy applications to device. The virtual machine will be used to run the image of linux containing the Maemo SDK.
There are two ways to install ESBox. The first way is to get the Full Product Archive of ESBox. The second way is to use Eclipse Update Site.
We will use the first way. If you want to install ESBox using Eclipse Update Site, see instructions at http://esbox.garage.maemo.org/beta1/installation_update_site.html.
The Full Product Archive consists of two parts: one common archive containing the bulk of the installation and an OS‐specific archive. The first step is to get these two archives from https://garage.maemo.org/frs/?group_id=192. In our case, we will get the common file and the win32 file. Then, create an empty directory and unzip both files into that. After, just run esbox.exe from the created directory.
Maemo for Mobile Developers
2 Install and setup ESBox on Windows
Now, we need a Linux virtual machine containing the Maemo SDK to allow ESBox to properly build the applications for Maemo. First get the VMware player from here: http://www.vmware.com/. Then, get a Maemo SDK virtual image from here: http://maemovmware.garage.maemo.org/. There are several Maemo SDK virtual images available. Some of them do not have Scratchbox and others need files installed. You can
download one of those images and use the instructions in the section 2.2, "Install Scratchbox" or get an image that already has these applications and files installed. Now, follow the steps below:
1. Open the ESBox; 2. Go to Window ‐> Preferences ‐> ESBox ‐> Build Machines;
3. Select VMware Linux Build Machine as build machine; 4. Browse the VMware player executable and browse the Maemo SDK virtual image;
Maemo for Mobile Developers
5. Go to Machine Access tab;
6. You need to edit the address and port settings depending on your networking configuration. Use the Autoselect Network Settings button to tell ESBox to guess the networking settings from current virtual machine settings and the host machine's network interfaces. Check the log message shown to see if any error happened;
Maemo for Mobile Developers
7. Note, when configuring a virtual machine using Bridged networking, it's impossible to guess the actual address the machine will have. By default, ESbox selects the network address (*.0) and warns you to update it. To discover the ip address of Virtual Machine, just open a console and type ifconfig;
8. Go to Shared Folders tab to select a folder shared for host and target;
9. Here we can see that we will need a windows shared folder. It is required to be visible to both the ESBox and the Virtual Machine, so all projects need to be stored on a path shared from the host and mapped to the Virtual Machine.
10. Go to the Windows environment and share a folder of your choice; 11. In the ESBox, put the shared folder path in all Shared path field; 12. Leave all others fields as they are.
Maemo for Mobile Developers
If you click on Apply and Validate Machine or Apply buttons you will probably get an error. This is due to communication error. The ESBox and the Maemo SDK virtual image communicates among themselves using SSH. Usually, Windows don’t come with any SSH server, then, the installation of an ssh server is necessary.
2.1 Install ssh server
We will use Cygwin to create an ssh server on Windows. To use it, follow the steps described below:
1. Get Cygwin installation file from “http://www.cygwin.com/” ; 2. In addition to the default Cygwin installation packages, install the latest versions for:
cygrunsrv, nfs‐server, openssh, xinit; 3. Get PC Connectivity from “http://pc‐
connectivity.garage.maemo.org/beta1/documentation_usbnet.html] and install”.
The installation process will configure and initiate Cygwin ssh server properly. Now you can back to ESBox Window ‐> Preferences ‐> ESBox ‐> Build Machines and click on Apply and Validate Machine. If all run ok, it will pass clean and silent. If no, probably the target address is wrong. To solve this problem, go to virtual machine, open a console a type ifconfig to get the correct net address. Back to ESBox and change target address.
For troubleshooting, see “http://pc‐connectivity.garage.maemo.org/beta1/documentation_usbnet.html”.
3 Install and setup ESBox on Linux To run ESBox on Linux the following prerequisites are needed:
Maemo for Mobile Developers
Java 1.5 or newer;
Scratchbox and Maemo SDK.
To install Scratchbox and Maemo SDK you can use the instructions on the section 2.2, "Install Scratchbox". The installation using ESBox is quite easy. To do this, first install ESBox.
Here, there are also two ways to install ESBox. The first way is to get the Full Product Archive
of ESBox. The second way is to use Eclipse Update Site.
We will use the first way. If you want to install ESBox using Eclipse Update Site, see these
instructions (http://esbox.garage.maemo.org/beta1/installation_update_site.html).
The Full Product Archive consists of two parts: one common archive containing the bulk of the
installation and an OS‐specific archive. The first step is to get these two archives
fromhttps://garage.maemo.org/frs/?group_id=192
“https://garage.maemo.org/frs/?group_id=192”. In our case, we will get the common file and
the Linux file. Then, create an empty directory and unzip both files into that. After, just run
ESBox from the created directory. At this point you are able to install Scratchbox and Maemo
SDK if you have not done yet.
4 Compile the application on ESBox
Eclipse (http://www.eclipse.org/) is an IDE for developing C/C++/Java applications. It
provides tools for debugging and building applications, among various other utilities. ESbox is
an Eclipse plug‐in designed to make project development easier in Maemo.
ESBox (http://esbox.garage.maemo.org/) runs inside Eclipse with CDT (C/C++ Development Tools) installed. Eclipse needs a Java Virtual Machine to run properly (Sun's Java 6 or above is recommended). ESbox also needs Scratchbox targets to build and run Maemo
projects. More information about installing ESBox can be found here: http://esbox.garage.maemo.org/installation.html.
The ESBox IDE interacts directly with Scratchbox and Maemo SDK. Although it’s current
release doesn’t have a proper perspective to develop for Qt, it can be used to develop Qt
applications. Its main benefit is that it automatically configures the environment. The
developer doesn’t need to direct run commands to build and run the application.
The first step to build the Hello World application is to open ESBox IDE and create an
empty C++ Maemo project as it is shown in the picture below. This can be done selecting File >
New > C++ Maemo Project. This will open the following screen where the option Empty C++
Automake Project should be chosen (1). After this, the project should be configured setting
the Project name and Build configurations (2). After this, the project is created and the
NOTE: ESBox IDE doesn’t have native support to develop Qt applications. However it
is fully integrated with Scratchbox. This makes the development easier since none
command line execution is required to build and execute the application in the
emulator. This is the main advantage of using it.
Maemo for Mobile Developers
main.cpp can be edited to contain the Hello World Qt code (3). See the pictures below to see
all these steps.
Maemo for Mobile Developers
After this, it is necessary to create a “Make target” for Qt. To do this, click in the
project with right mouse button and select Create Make Target. The following dialog box will
appear where the build command needs to be changed to compile a Qt project. The
commands needed are the same as before: qmake –project ; qmake ; make. You
need to create two targets: the first one contains qmake –project command and
generates the .pro project file; the second contains qmake; make commands that are
responsible for building the application.
The last step is to remove some flags
used to compile C++. As Qt uses a different build system (see
http://doc.trolltech.com/4.2/qmake‐manual.html) these flags don’t need to be configured
manually. These flags can be found in Properties > Maemo build configurations. The following
picture shows the variables to be removed.
Maemo for Mobile Developers
Now the project can be compiled selecting Build Make Target. If it the first time the
project is built the all target need to be build to generate the .pro file. Once this file has been
generated, the next compilations only need to build the build target.
4.1 Run the application on ESBox
1. Click on the “X” button and select “start” to start an X server;
2. If you get an error, try to change Cygwin paths on Window ‐> Preferences ‐> ESBox ‐> X Server as shown below;
Maemo for Mobile Developers
3. Click on the “maemo” button to start the Maemo SDK on de X server;
Maemo for Mobile Developers
4. After building the application and steps above it can be run pressing the right mouse
button in the generated binary file and selecting Run As > Maemo Local Application.
5 Create a Debian installation file
To deploy an application to device, the debian package generation is required. To do this,
follow the steps below:
1. Right click on the project and select the Debian Package option;
2. Select Create Debian Structure;
Maemo for Mobile Developers
3. Here you can select the options of your choice. After that, click Finish button and the
debian structure will be created;
4. Right click again on the project and select Debian Package ‐> Build Debian Package;
Maemo for Mobile Developers
5. Select the desired target. You will be prompted to choose the destination folder. After
that, the “.deb” file will be generated;
6 Deploy the application to the device Follow the PC Connectivity installation instruction from http://pc‐
connectivity.garage.maemo.org/documentation_usbnet.html to configure the connection
between PC and internet tablet;
1. Right click the last time on the project and select Debian Package ‐> Install Debian
Package on Device;
Maemo for Mobile Developers
2. Browse the created debian file, select the appropriated device connection and click
Finish button;
If all run ok, the application will be deployed to the device.
Maemo for Mobile Developers
Chapter 4 Qt for Maemo implementation notes
Qt is a cross‐platform application and UI framework. With Qt, the developer can create
applications and run them in multiple platforms including desktops and mobile devices. The
most important features of Qt are:
Intuitive C++ class library
Portability across multiple platforms
High runtime performance and small footprint on embedded systems
Complete collection of cross platform libraries
Qt is an additional component in Maemo platform. In the latest Maemo release, called
Fremantle the Qt libraries porting have been improved to provide better performance and
enhanced platform integration. This includes Maemo Hildon compatibility with Hildon menus,
Hildon style support and Hildon input menu support. Also, Fremantle brings Qt with support to
Opengl ES 2.0, Webkit and Mysql, among other things. More information about Qt in Maemo
can be found in at http://qt4.garage.maemo.org/. There are some reasons to support Qt in
Maemo:
• Qt is Nokia cross platform toolkit, made by Nokia Qt Software
• Same applications with no modifications or just small changes can be compiled and
run in S60 but also in Desktop Linux Macintosh, Windows and even Windows
mobile
• UI needs to be tailored to specific device characteristics and Qt can solve this in a
straightforward way
The following sections provide a quick, but detailed, guide to start developing
applications with Qt for Maemo platform.
1 Platform specific changes This session indicates the changes made in the standard Qt libraries needed to
integrate then to Maemo platform concepts. For an extensive reference of standard Qt
libraries go to “http://doc.trolltech.com/”. Fremantle integration with Qt included adaptation
for:
Hildon Menus
Hildon style
Hildon Input methods
Widgets like QDialog and QMenu
Qt packages
Maemo for Mobile Developers
Maemo Qt is based on Qt for X11. It shares the same API with no API breaks.
Therefore, every Qt application that runs in other platforms runs in Maemo. So, the Qt official
documentation (http://doc.trolltech.com/4.5/index.html) can be used to develop applications
for Qt to Maemo. However, the reverse doesn’t hold in all situations as there are some small
changes in Maemo. The list of changes is presented below.
Storage Location: the function storageLocation of the class QDesktopServices receives StandardLocation as parameter. Below there is a table matching each parameter value for this function with the returned value when running in Maemo.
StandardLocation Folder in Maemo DesktopLocation /MyDocs DocumentsLocation /MyDocs/.documentsPicturesLocation /MyDocs/.images MusicLocation /MyDocs/.sounds MoviesLocation /MyDocs/.videos
Input events: QInputEvents doesn’t move the cursor along the screen. This is done through QInputMethodEvents. The reason for this is that when the user highlights the text from right to left, and the highlighted text is erased, the cursor will remain in the last char instead of the first. To do that some changes has been added to some widget function like inputMethodEvent(QInputMethodEvent *e). Modifying that function in some custom widgets may be necessary. If these functions are not re‐implemented some full screen virtual keyboard features will be break. Also QMainWindow has some hardcoded keys. They are:
F6 ‐ Toggle full screen the application
F4 ‐ Shows/Hides the application context menu
Zoom in ‐ is a standard key sequence QKeySequence::ZoomIn Zoom out ‐ is a standard key sequence QKeySequence::ZoomOut
Input method: Maemo Qt uses the Hildon IM as default Input method. Each kind of widget can set the IM mode. This allows the input method to focus on the type of input that the application is expecting. For example, spin boxes can receive only numeric characters (1‐9). Notice that Qt widgets like QTextEdit and QLineEdit set the right input method mode automatically. A developer can change the input method by using:
void QInputContext::setInputMode(int mode);
This will update the Hildon Input method immediately to the following modes:
Input method mode Description HILDON_GTK_INPUT_MODE_ALPHA alphabetical characters and whitespace HILDON_GTK_INPUT_MODE_NUMERIC numbers 0‐9 and the '‐' character HILDON_GTK_INPUT_MODE_SPECIAL special characters HILDON_GTK_INPUT_MODE_HEXA hexadecimal characters; numbers 0‐9, characters
a‐f, and A‐F HILDON_GTK_INPUT_MODE_TELE telephone numbers; numbers 0‐9, whitespace,
and the characters "pwPW/().‐+*#?," HILDON_GTK_INPUT_MODE_FULL unrestricted entry mode, combination of the
Maemo for Mobile Developers
alpha, numeric and special modes HILDON_GTK_INPUT_MODE_MULTILINE the client contains multiple lines of text or
accepts line breaks in the input HILDON_GTK_INPUT_MODE_INVISIBLE do not echo or save the input in the IM when
entering sensitive information such as passwords HILDON_GTK_INPUT_MODE_AUTOCAP automatically capitalize the first letter at the start
of a sentence HILDON_GTK_INPUT_MODE_DICTIONARY enable predictive dictionaries and learning based
on the input
The code snippet below shows how to set up the input method for a password field:
int mode = HILDON_GTK_INPUT_MODE_FULL|HILDON_GTK_INPUT_MODE_INVISIBLE; QInputContext qic = widget->inputContext(); qic->setInputMode(mode);
If you are developing a Custom widget capable to receive input text, you can set the widget to use the right input method mode just returning the mode identifier. If the Custom widget mode property is not set properly, the IM will use HILDON_GTK_INPUT_MODE_FULL (the default mode) for that widget. Setting the input method mode is quite easy. Check the code below for more understanding. The code snippet below shows how to do this. #ifdef Q_WS_HILDON #include <QInputContext> #endif QVariant QAbstractSpinBox::inputMethodQuery(Qt::InputMethodQuery query) const { Q_D(const QAbstractSpinBox); switch(query) { case Qt::ImMode:{ int mode = HILDON_GTK_INPUT_MODE_NUMERIC; return QVariant(mode); } default: return d->edit->inputMethodQuery(query); } }
QDialogs: The Fremantle WM doesn't allow QDialogs without a parent (at least this is true for Qt apps). A dialog without a parent won't be shown by the WM. The code below should be avoided:
QColorDialog::getColor ( Qt::white, 0 ); Use this code instead:
QColorDialog::getColor ( Qt::white, this );
Maemo for Mobile Developers
2 Porting a Qt application to Maemo
Porting a Qt application from desktop environment to Maemo is really simple and
requires very little effort. In most cases the above relation is true, because the developer only
needs to recompile the project to Maemo using the SDK. The Maemo style and Hildon look &
feel are implemented underneath so the developer doesn’t need to take care of them. One
example is the menu. The picture below shows a menu in desktop (smaller) and Maemo
(bigger).
0
Although it may be straightforward to port an application, some guidelines should be
followed to get the best porting of the application to Maemo. These guidelines are explained
below:
The user may use fingers to interact with the application, this means the area of the UI
elements should take this into account
The virtual keyboard may appear on the screen when the focus is on some input
widgets, so the dialogs should be arranged to fit in same screen.
Avoid the use of absolute layout because in Maemo style, fonts and buttons are much
larger to best fit the finger input
If possible, avoid to wrap a group of widgets in a QScrollArea in order to fit then in
your dialogs
Maemo for Mobile Developers
You can get more information about porting Qt application to Maemo here:
http://wiki.maemo.org/Qt4_Hildon#Porting_a_Qt_application_to_Maemo.
3 Uploading the application to Garage Maemo offers a Garage (https://garage.maemo.org/) repository where developers can
upload their applications to be available for all Maemo users. There are two repositories for
third‐party applications: the extras-devel and extras.
extras-devel This repository is the first place for applications which are
under development. This repository is intended to packaging testing of alpha
and beta releases of applications. It should be used before the application gets
mature enough to go to extras repository. This repository is not
recommended for regular usage since applications on it are usually unstable
and may potentially break the system. You can add the extra‐devel in the
tablet by opening the .install (https://garage.maemo.org/extras‐
assistant/install/extras‐devel.install) link from it.
extras This repository is the place to put 3rd‐party applications that are
stable and can be installed on internet tablets flawlessly. To upload an
application to this repository, the application should meet some requirements
that are stated at Extras Repository Process Definition
(http://wiki.maemo.org/Extras_repository_process_definition). More
information about extras repository can be found here:
http://wiki.maemo.org/Extras_repository_process_definition.
The upload process to extras and extras-devel requires an account at Garage
web site. After the creation of this account you can upload your application to both
repositories following the instructions found here:
http://wiki.maemo.org/Uploading_to_Extras. After this, any Internet Tablet owner with the
proper repository configuration can use the Maemo Application Manager search and install
the applications.
4 Links Qt software – http://www.qt.nokia.com/
Qt4 maemo – http://qt4.garage.maemo.org/
Maemo 5 SDK – http://www.forum.nokia.com/info/sw.nokia.com/id/c05693a1‐265c‐
4c7f‐a389‐fc227db4c465/Maemo_5_SDK.html
Maemo 5 Hildon Reference Manual –
http://maemo.org/api_refs/5.0/beta/hildon/index.html
Qt Documentation – http://doc.trolltech.com/
Maemo training – http://maemo.org/development/training/
Forum Nokia Wiki – http://wiki.forum.nokia.com/index.php/Wiki_Home
ESBox – http://esbox.garage.maemo.org/index.html
Maemo for Mobile Developers
Chapter 5 Using Maemo APIs in Qt applications
1 Liblocation Location services have become a common feature in mobile applications. The Maemo platform
provides a high level library called liblocation to allow applications to easily control and
retrieve data from the GPS. The library provides methods to start and stop the GPS daemon,
and allows the application to register itself to listen for GPS data changes, such as fix status,
satellite information, position, speed and so on.
It is completely different than the libgpsmgr, which is one of the libraries used to get location
information in the Diablo. The package containing liblocation binaries is the liblocation0, but
the package you must install to develop is the liblocation‐dev.
At the moment, this library is only available for Maemo and it lies on the nokia‐binaries
repository for both Diablo and Fremantle releases. The library documented here is the version
for Fremantle, as the Diablo version is a little different.
The package containing liblocation binaries is the liblocation0, but to develop applications
using the lib, it is needed to install the package liblocation‐dev, as shown below (see this
section to learn how to add nokia‐binaries repository):
$ apt-get install liblocation-dev
The summary of the package characteristics is shown below:
Library name liblocation
Package name liblocation0
Development package liblocation‐dev
Last version of the package 0.94‐7+0m5
Repository of the package nokia‐binaries
1.1 Main Classes and Methods liblocation provides two classes and one utility method as described below.
1.1.1 LocationGPSDevice The LocationGPSDevice class allows applications to register themselves to listen to GPS data
changes. Three different signals can be received:
Maemo for Mobile Developers
“changed”: emitted when any data has been changed;
“connected”: emitted when device managed to connect to the location server;
“disconnected”: emitted when device is disconnected from the location server.
All signals have the same function signature, as shown below:
void user_function (LocationGPSDevice *device, gpointer user_data)
The example in the next session will show the code to register the functions to listen these
signals with g_signal_connect().
The LocationGPSDevice object received by the callback functions has public variables
containing the GPS data provided by the API. The structure as defined in the class header file is
shown below:
typedef struct { gboolean online; LocationGPSDeviceStatus status; LocationGPSDeviceFix *fix; int satellites_in_view; int satellites_in_use; GPtrArray *satellites; LocationCellInfo *cell_info; } LocationGPSDevice;
The “online” flag keeps the connection status with the hardware. If it is TRUE, the GPS is
connected.
The “status” field is an enumeration with the GPS fix status:
LOCATION_GPS_DEVICE_STATUS_FIX and LOCATION_GPS_DEVICE_STATUS_NO_FIX.
The “satellites_in_view” field is the number of satellites the GPS device can see.
The “satellites_in_use” field is the number of satellites used to calculate information about
location, speed, and others.
The “satellites” field contains data about all found satellites. This is an array of structure
LocationGpsDeviceSatellite, which contains satellite data. The structure as defined in the class
header file is shown below:
typedef struct { int prn; int elevation; int azimuth; int signal_strength; gboolean in_use; } LocationGPSDeviceSatellite;
Maemo for Mobile Developers
The “cell_info” field is a structure of type LocationCellInfo containing the fields _gsm_cell_info
and wcdma_cell_info, which provides information about the mobile telephony cell that the
device in connected. With more than one cell information, is possible to calculate the
approximate location.
The “fix” field is a structure of type LocationGpsDeviceFix, and is where the location
information lands. It contains latitude, longitude, altitude, current speed, current direction of
motion in degrees, and other information. The structure as defined in the class header file is
shown below:
typedef struct { LocationGPSDeviceMode mode; guint32 fields; double time; double ept; double latitude; double longitude; double eph; double altitude; double epv; double track; double epd; double speed; double eps; double climb; double epc; } LocationGPSDeviceFix;
The most important fields of this structure are:
“latitude”: the latitude coordinate value.
“longitude”: the longitude coordinate value.
“altitude”: the altitude in meters.
“speed”: the current speed in km/h.
“track”: the current direction of motion in degrees (between 0 and 359).
1.1.2 LocationGPSDControl This class is responsible for controlling the location service daemon (gpsd) running in the
device. This means that it can be used to start and stop the location services.
The class implements the singleton pattern, so the application can hold only one instance of
the control class. To get the singleton object, use the function
location_gpsd_control_get_default() as shown below:
LocationGPSDControl *control;
control = location_gpsd_control_get_default();
Maemo for Mobile Developers
The application can start and stop the gpsd daemon with the methods
location_gpsd_control_start() and location_gpsd_control_stop(), respectively.
The LocationGPSDControl emits three signals:
“error”: emitted when an error has occurred;
“gpsd_running”: emitted after the location_gpsd_control_start has been called.;
“gpsd_stopped”: emitted after the location_gpsd_control_stop has been called.
The application must create a function to connect to the signal. The function signature is
shown below:
void user_function(LocationGPSDControl *locationgpsdcontrol, gpointer user_data)
Here, locationgpsdcontrol is the object that received the signal and the user_data is the user
data set when the signal handler was connected. See the GObject documentation
(http://library.gnome.org/devel/gobject/2.20/) to know how to connect a user function to a
signal.
1.2 locationdistanceutils The library also provides an useful function to calculate the distance on the surface of the
earth between two points. This function is called location_distance_between() and can be
used like in the example below:
double distance; double latitude_s = -37.1443 double longitude_s = -7.2554 double latitude_f = -38.6554 double longitude_f = -6.5778 distance = location_distance_between(latitude_s, longitude_s, latitude_f, longitude_f);
The function receives four double values, which represents the latitude/longitude coordinates
of two points. This function also returns a double value, which is the calculated distance in
kilometers between the two points.
1.3 Liblocation Example In order to archive a better understanding, the example was designed to have a very simple UI
focusing more on liblocation functionalities. As shown on Figure 1, the UI is just a form that
will have the location data values updated based on liblocation events.
Maemo for Mobile Developers
Figure 1 – Liblocation example UI.
This example was written using the GTK+ framework and uses libraries from hildon framework
to show a banner on the screen. The full example can be downloaded from [here]. The
example code is explained below. First, it is needed include the following header files:
#include <gtk/gtk.h> #include <hildon/hildon-banner.h>
The main() method initializes the GTK+ framework and call the methods to build the UI and
setup the location API:
int main( int argc, char *argv[] ) { /* Initialise GTK */ gtk_init (&argc, &argv); setupUi(); setupLocation(); gtk_main (); stopLocation(); return 0; }
The function setupUi() creates the GTK objects and build the application layout. First it creates
the main window and connects its destroy signal to the gtk_main_quit() callback, so the
application will exit when close button is pressed.
Then, a GtkTable is created to organize the labels as a grid. The table here consists of two
columns and five rows as shown in Figure 1.
In order to change the window background color a GdkColor object is instantiated, having its
value defined right after by the gdk_color_parse() function that assigns the gray color for it.
Finally, the gtk_widget_modify_bg()function sets the given color as the background color.
Maemo for Mobile Developers
The next statement adds the table widget to the window. In an effort to archive a better
modularization, this example defines a function to add a new row to the table and initializes
the UI with default values.
Finally gtk_widget_show_all() displays all widgets on the window.
void setupUi() { GtkWidget *frame; GtkWidget *label; GtkWidget *eventBox; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_window_set_title (GTK_WINDOW (window), "LibLocation Example"); gtk_container_set_border_width (GTK_CONTAINER (window), 25); /* Create table */ table = gtk_table_new (4, 2, TRUE); gtk_table_set_col_spacings(GTK_TABLE (table), 20); gtk_table_set_row_spacings(GTK_TABLE (table), 10); GdkColor color; gdk_color_parse ("gray", &color); gtk_widget_modify_bg (window, GTK_STATE_NORMAL, &color); gtk_container_add (GTK_CONTAINER (window), table); addRow(0, "GPS Status", "No Fix"); addRow(1, "Satellites in use", "0"); addRow(2, "GeoPosition", NULL); addRow(3, "Altitude", NULL); addRow(4, "Speed", NULL); gtk_widget_show_all (window); }
The addRow() function is defined as follows:
void addRow(guint rowPos, const gchar *key, const gchar *value) { GtkWidget *label; GtkWidget *eventBox; GdkColor color; label = gtk_label_new (key); gtk_table_attach (GTK_TABLE (table), label, 0, 1, rowPos, rowPos + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); setRowValue(rowPos, value); }
This function adds a row by instantiating a new GtkLabel and attaching it to the table. As the
last step it calls the setRowValue:
Maemo for Mobile Developers
void setRowValue(guint rowPos, const gchar *value) { GtkWidget *label; GtkWidget *eventBox; GdkColor color; label = gtk_label_new ( (value) ? value : " - " ); eventBox = gtk_event_box_new(); gtk_container_add (GTK_CONTAINER (eventBox), label); gtk_table_attach (GTK_TABLE (table), eventBox, 1, 2, rowPos, rowPos + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK, 20, 0); }
Now that the UI is created, the function setupLocation() will use the liblocation to register the
example to retrieve location data. To use the liblocation you must include the following two
header files:
/*including header files*/ #include <location/location-gps-device.h> #include <location/location-gpsd-control.h>
Now, the setupLocation() function will use the classes LocationGPSDevice and
LocationGPSDControl. It first gets the LocationGPSDControl object with the function
location_gpsd_control_get_default() and starts it with the function
location_gpsd_control_start(). This allows the example to control the GPS Daemon control
starting the GPS service in the device. Afterwards, the example creates the LocationGPSDevice
object and register itself to receive notifications about location data changes:
void setupLocation() { LocationGPSDControl* control; control = location_gpsd_control_get_default(); location_gpsd_control_start(control); LocationGPSDevice* device; device = g_object_new(LOCATION_TYPE_GPS_DEVICE, NULL); g_signal_connect(device, "changed", G_CALLBACK(location_changed), NULL); g_signal_connect(device, "connected", G_CALLBACK(location_connected), NULL); g_signal_connect(device, "disconnected", G_CALLBACK(location_disconnected), NULL); }
When the “connected” and “disconnected” signals are received, the callback functions only
show a hildon banner to update the user about the new state:
static void location_connected( LocationGPSDevice* device, gpointer userdata) { hildon_banner_show_information(GTK_WIDGET (window), "GPS Connected", "GPS Connected");
Maemo for Mobile Developers
} static void location_disconnected( LocationGPSDevice* device, gpointer userdata) { hildon_banner_show_information(GTK_WIDGET (window), "GPS Connected", "GPS Disconnected"); }
On the other hand, when the “changed” signal is received, the UI is updated with the new
data:
static void location_changed( LocationGPSDevice* device, gpointer userdata) { handleStatus( device->status ); handleSatellites( device->satellites_in_view, device->satellites_in_use, device->satellites); handleDeviceFix ( device->fix ); } The location_changed() method was divided into three procedures. The first two are as follow: static void handleStatus( LocationGPSDeviceStatus status ) { /* Handle Status Changed */ if (status == LOCATION_GPS_DEVICE_STATUS_NO_FIX) { setRowValue(0, "No Fix"); } else { setRowValue(0, "Fixed"); } } static void handleSatellites(int satellites_in_view, int satellites_in_use, GPtrArray *satellites) { /* Handle satellites in view */ gchar* numSatellites = g_strdup_printf("%i", satellites_in_use); setRowValue(1, numSatellites); g_free(numSatellites); }
The handleStatus() function handles the status of the GPS device indicating if it has connected
to enough satellites to calculate the position. The handleSatellites() function updates the UI to
indicate the number of satellites the GPS device is connected with.
The last function, handleDeviceFix (), is set out below:
static void handleDeviceFix ( LocationGPSDeviceFix *fix ) { gchar* location = NULL; gchar* altitude = NULL; gchar* speed = NULL;
Maemo for Mobile Developers
switch(fix->mode) { case LOCATION_GPS_DEVICE_MODE_NOT_SEEN: case LOCATION_GPS_DEVICE_MODE_NO_FIX: break; case LOCATION_GPS_DEVICE_MODE_3D: /* Testing if the altitude field of LocationGPSDeviceFix is valid. */ if (fix->fields & LOCATION_GPS_DEVICE_ALTITUDE_SET) { altitude = g_strdup_printf("%.2f m", fix->altitude); } case LOCATION_GPS_DEVICE_MODE_2D: /* Testing if the latitude and longitude fields of LocationGPSDeviceFix are valid. */ if (fix->fields & LOCATION_GPS_DEVICE_LATLONG_SET) { gchar latitude = (fix->latitude >= 0)?'N':'S'; gchar longitude = (fix->longitude >= 0)?'E':'W'; location = g_strdup_printf("%.2f° %c\n%.2f° %c", ABS(fix->latitude), latitude, ABS(fix->longitude), longitude); } break; } /* Testing if the speed field of LocationGPSDeviceFix is valid. */ if (fix->fields & LOCATION_GPS_DEVICE_SPEED_SET) { speed = g_strdup_printf("%.2f Km/h", fix->speed); } setRowValue(2, location); setRowValue(3, altitude); setRowValue(4, speed); g_free(location); g_free(altitude); g_free(speed); }
This function formats the location, altitude and speed information retrieved from the
LocationGPSDeviceFix structure. In case of GPS device not be able to see any satellites nor fix,
the output of the location will be the default, “ ‐“.
In case of being working on 2D mode (none altitude information), the function checks if the
latitude and longitudes fields are valid and formats the output in such a way that if latitude is
negative, the letter S from South is shown followed by the absolute value of the location. It
does the same way with the longitude, applying instead of S the letter W from West.
If working on 3D mode, the function also checks if the altitude field is valid and sets the
respective field on UI in addition to longitude and latitude.
The last step is to release gchar resources by calling the g_free() function.
There are other location data available in the LocationGPSDevicestructure. You can access the
other values in the same way.
Maemo for Mobile Developers
1.4 Links Liblocation reference manual: http://maemo.org/api_refs/5.0/beta/liblocation/
Python liblocation: http://brewer123.home.comcast.net/~brewer123/projects/nokia/
Using liblocation:
http://maemo.org/maemo_release_documentation/maemo4.1.x/node10.html#SECTI
ON001027000000000000000
GPSJinni application: http://maemo.org/downloads/product/OS2008/gpsjinni/
libgpsmgr API reference: http://maemo.org/api_refs/4.1/libgpsmgr‐0.2/
2 Libcityinfo
The libcityinfo API can be used to get information about a large set of cities around the world.
The information is stored in ASCII format database inside the device. The following information
can be accessed through libcityinfo API:
City name;
Country name (in which the city is placed);
Country code;
Time zone;
Geographical position;
Position on the map of clocks world map image;
Locale used in country.
2.1 Example
The following example displays the names of all countries available in the database. The
application also contains a filter edit line to find the country name. The list is constructed using
the function cityinfo_get_all(). The Qt class QListWidget is inherited and its subclass creates a
slot to update the list according to the typed string in the edit line. The most important classes
of this example APIs are: libcityinfo, QListWidget and QLineEdit.
Maemo for Mobile Developers
The example contains two source files (main.cpp and QCityInfoWidget.cpp) and one header
(QCityInfoWidget.h). The QCityInfoWidget class is derived from QListWidget. The source code
is shown below.
//QCityInfoWidget.h #ifndef QCITYINFOWIDGET_H #define QCITYINFOWIDGET_H #include <QListWidget> class QCityInfoWidget : public QListWidget { Q_OBJECT public: QCityInfoWidget(); public slots: void findSearchedString(const QString& searchString ); }; #endif // QCITYINFOWIDGET_H // QCityInfoWidget.cpp #include <cityinfo.h> #include "QCityInfoWidget.h" QCityInfoWidget::QCityInfoWidget(): QListWidget() { Cityinfo** cityArray = cityinfo_get_all(); for (int i = 0; cityArray != NULL && cityArray[i] != NULL; ++i) { addItem( QString(cityinfo_get_country( cityArray[i] )) ); } } void QCityInfoWidget::findSearchedString( const QString& searchString ) { QList<QListWidgetItem *> listItem = findItems ( searchString, Qt::MatchStartsWith ); if( listItem.count() > 0 ) { scrollToItem( listItem[0] ); } }
The class defines a public slot (findSearchedString) to be connected with a signal from the
QLineEdit class. This slot is used to scroll the list to the item that starts with the string typed of
the box.
Maemo for Mobile Developers
In the constructor of the QCityInfoWidget, the list is populated with the country names using
the addItem() method of the superclass. The registries are accessed using the cityinfo_get_all()
call. The country names are then accessed through the function cityinfo_get_country().
The main file defines the layout of the screen. In this example, the graphical elements are
displayed horizontally or vertically. Thus, QHBoxLayout and QVBoxLayout are used as screen
layouts.
On main method, the slot of the QCityInfoWidget class is connected with QLineEdit
textChanged by using QObject::connect. The main.cpp source is shown below:
#include <QApplication> #include <QLineEdit> #include <QLabel> #include <QHBoxLayout> #include <QListWidget> #include <QHeaderView> #include "QCityInfoWidget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.show(); QLabel *queryLabel = new QLabel(QString("Filter:")); QLineEdit *queryEdit = new QLineEdit(); QCityInfoWidget* listWidget = new QCityInfoWidget(); listWidget->setSelectionMode(QAbstractItemView::MultiSelection); QObject::connect(queryEdit, SIGNAL(textChanged ( const QString&) ), listWidget, SLOT(findSearchedString( const QString& ))); QHBoxLayout *queryLayout = new QHBoxLayout(); queryLayout->addWidget(queryLabel); queryLayout->addWidget(queryEdit); QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addLayout(queryLayout); mainLayout->addWidget(listWidget); window.setLayout(mainLayout); return app.exec(); }
And the .pro file:
Maemo for Mobile Developers
TEMPLATE = app TARGET = DEPENDPATH += . INCLUDEPATH += . /usr/include/glib-2.0/glib /usr/include/glib-2.0/ /usr/lib/glib-2.0/include LIBS += -lcityinfo0 -lglib-2.0 # Input HEADERS += QCityInfoWidget.h SOURCES += main.cpp QCityInfoWidget.cpp
3 mcedev Some Maemo applications often need to get information about the device mode. For example,
an application needs to know if device is on offline mode in a meeting time and, if not, the
device mode should be changed to the correct one.
Maemo development environment provides mechanisms to manage the device mode. It
provides the Mode Control Entity, which manages the device mode. In addition, Maemo
development environment provides DBus interfaces to the Mode Control Entity, so the
developer can easily use it on his application. It means that the developer can control or get
information about device mode through DBus messages. For example, the developer can
query the inactivity status or request to blank the screen.
The package which contains mce development files is the mce‐dev package. It is required to
install such package on your development environment to use MCE DBus interfaces. However,
both Diablo and Fremantle commonly have MCE development packages already installed.
To install mce‐dev files, use the following command (see this section to learn how to add
nokia‐binaries repository):
#apt-get install mce-dev
The summary of the package characteristics is shown below:
Library name mce
Package name mce‐dev
Development package mce‐dev
Last version of the package 1.6.3
Repository of the package fremantle/sdk free
Maemo for Mobile Developers
The MCE defines two header files that can be used in the development process: “dbus‐
names.h” and “mode‐names.h”. The “dbus‐names.h” file contains names definition required
to send messages through DBus (it will be explained in details later). The “mode‐names.h” file
contains names definition of modes and states.
3.1 MCE headers files The “dbus‐names.h” header file contains MCE service name, paths and interfaces required to
create a proxy object for the DBus driver. They are summarized on the following table:
Macro Value Description
MCE_SERVICE "com.nokia.mce" MCE D‐Bus service
MCE_REQUEST_IF "com.nokia.mce.request" MCE D‐Bus Request
interface
MCE_SIGNAL_IF "com.nokia.mce.signal" MCE D‐Bus Signal interface
MCE_REQUEST_PATH "/com/nokia/mce/request" MCE D‐Bus Request path
MCE_SIGNAL_PATH "/com/nokia/mce/signal" MCE D‐Bus Signal path
Note that names for signal and for requests are listed above. The service name is the same for
both, but the interface and the path differs from each other.
File “dbus‐names.h” also defines names for MCE DBus methods and MCE DBus signals. The
MCE DBus methods names are used to request changes in the device mode or query for
information. The DBus signals names are the names used to get connected with a signal and
observe changes on device mode.
File “mode‐names.h” contains current values for Internet Tablet mode. These modes are
returned by methods used to query about device mode, for example the method
"get_device_mode". Existing Internet Tablet modes are summarized on the following table:
Macro Value Description
MCE_NORMAL_MODE "normal" Normal device mode
MCE_FLIGHT_MODE "flight" Offline device mode;
RF's disabled
MCE_OFFLINE_MODE "offline"
Offline device mode;
RF's disabled; alias for
flight mode
MCE_INVALID_MODE "invalid" invalid device mode;
this should never occur
Maemo for Mobile Developers
3.2 Qt mcedev example MCE API for Maemo only provides a DBus interface, which consists of methods and signals.
Thus, in order to use MCE, DBus is required. In this section, one example is used to
demonstrate how MCE can be used on Qt applications. This example does a simple MCE
method call and also listens to a MCE signal. The full example will be available for download
later.
The example contains a button and a label. When button is pressed, the screen becomes
totally blanked. We simply change the state of Internet Tablet display to OFF, by using method
"req_display_state_off" of MCE API. This example also connects a function to a signal. In this
case, the function is called whenever device mode is changed (“normal”, “flight”, “offline” or
“invalid”). In addition, this example also changes the text of a label widget.
This example has two files: “mce_example.cpp” and “mce_example.h”. The “mce_example.h”
file is shown below. This file contains declarations of a class, variables, slots, and a method.
The class inherits from QWidget, which is required to create Qt GUI applications, and then the
QWidget header file must be included. Slots are declared in this file as well, so the Q_OBJECT
macro must be called and the QObject header file must be included.
Two slots are declared in the class: cb_func and button_callback. The cb_func slot is connected
to the signal emitted when the mode of the device is changed. The button_callback slot is
connected to the signal emitted when the button is clicked. The method connect_to_mce is
used to connect the cb_func slot to a MCE signal.
#ifndef QT_SIGNAL_H #define QT_SIGNAL_H #include <QObject> #include <QDBusMessage> #include <QWidget> class MCEExample : public QWidget { Q_OBJECT public: MCEExample(QWidget *parent = 0); ~MCEExample(); public: void connect_to_mce(); public slots: void cb_func(const QDBusMessage& rep); void button_callback(); }; #endif // QT_SIGNAL_H
The “mce_example.cpp” file contains the implementation of the class and methods declared in
the “mce_example.h” header file. At first, the required header files are included. The
Maemo for Mobile Developers
“QApplication”, “QLabel”, “QPushButton”, and “QVBoxLayout” files are used to create the Qt
QUI. The “QDBusInterface”, “QDBusConnection” and “mce/dbus‐names.h” files are used to
create a connection to a DBus signal and a remote call to a MCE method:
#include <mce_example.h> #include <QApplication> #include <QLabel> #include <QPushButton> #include <QVBoxLayout> #include <QDBusInterface> #include <QDBusConnection> #include <mce/dbus-names.h>
Two variables are declared as static because they are used in more than one method in the
code. The connection variable is used in the button callback function and the label variable is
used in the function connected to the MCE signal:
static QDBusConnection connection = QDBusConnection::systemBus(); static QLabel *label;
The constructor of the class is shown below. Here, a button and a label are created:
MCEExample::MCEExample(QWidget *parent): QWidget(parent){ label = new QLabel("Device mode :"); QPushButton *button = new QPushButton("Blank screen"); connect(button, SIGNAL(clicked()), this, SLOT(button_callback())); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(label, 0, Qt::AlignHCenter); layout->addWidget(button); setLayout(layout); }
The signal emitted when the button is pressed is connected to the method button_callback(),
which is shown below. In this method, a QDBusInterface is created and it is used to make the
call of the remote MCE method MCE_DISPLAY_OFF_REQ, which requests the device to change
its screen status:
void MCEExample::button_callback() { QDBusInterface mce_if(MCE_SERVICE, MCE_REQUEST_PATH, MCE_REQUEST_IF, connection); mce_if.call(MCE_DISPLAY_OFF_REQ); }
The following method is used to connect the method cb_func() to the MCE signal
MCE_TKLOCK_MODE_SIG, which returns the device mode:
void MCEExample::connect_to_mce() {
connection.connect(MCE_SERVICE, MCE_SIGNAL_PATH, MCE_SIGNAL_IF, MCE_TKLOCK_MODE_SIG,
Maemo for Mobile Developers
this, SLOT(cb_func(const QDBusMessage&)));
}
The cb_func() method only receives the mode name and set it to the label:
void MCEExample::cb_func(const QDBusMessage& rep) { label->setText("Device mode :" + rep.arguments().value(0).value<QString>()); }
The main function is shown below. It creates the application, creates an instance of
MCEExample and starts the application:
int main(int argc, char* argv[]){ QApplication app(argc,argv); MCEExample example; example.call_remote_method(); example.show(); return app.exec(); }
Finally, to compile this example, include the qdbus name to the CONFIG key in the “.pro” file:
CONFIG =+ qdbus
To run this application on device you will need to install qtgui and libqtdbus. A screenshot of
the application is shown below:
4 Calendarbackend The Calendar‐backend library allows the developer to manage calendars and events. Such
library provides a C++ API to create a calendar and add events, birthdays, journal, or to‐do´s,
including attendees and organizers.
Maemo for Mobile Developers
All the calendar data is stored in the SQLite (http://www.sqlite.org/) database of the device.
The Calendar‐backend library provides mechanisms to interact with database by using
methods implemented by CCalendarDB class. This library also interacts with alarm daemon
and it stores the alarm data in the local calendar database using CAlarm class methods.
Calendar‐backend is a closed library and it is available on Nokia‐binaries meta‐package.
Therefore, it is necessary to configure Nokia‐binaries local repository to install it.
The first implementation of this library was in the Fremantle. The package containing calendar
backend libraries is the calendar‐backend, and the files needed to develop applications are in
the package calendar‐backend‐dev. To install Calendar‐backend packages on your
environment, execute the following commands:
# apt-get install calendar-backend
# apt-get install calendar-backend-dev
The summary of the package characteristics is shown on the following table:
Library name Calendar backend
Package name calendar‐backend
Development package calendar‐backend‐dev
Last version of the package 0.5‐8.12+0m5
Repository of the package nokia‐binaries
4.1 Main Classes and Methods The calendar backend library contains several classes that help the developer to create
calendar and add events. The most important classes are CMulticalendar, CCalendar, and the
classes derived from CComponent.
The CMulticalendar class is the main element to access the calendar backend. Only one
instance of CMulticalendar is allowed per process. The instance of CMulticalendar can be
retrieved by using the static method MCInstance(). Once you have access to CMulticalendar
instance, it is possible to:
add a calendar with the method addCalendar();
delete a calendar with the function deletCalendar();
get a calendar by name or by ID using the functions getCalendarByName() and
getCalendarById() respectively.
However, before adding a calendar to the CMulticalendar, you have to create a CCalendar. This
class allows the developer to add, modify or delete components such as event, to‐do´s ,
journal or birthdays. It is possible to set the next alarm event with the method setNextAlarm().
Maemo for Mobile Developers
The CCalendar type can be set to Local calendar, Sync calendar or Smart calendar by using the
method setCalendarType(). The current CCalendar type can be obtained by method
getCalendarType().
The components, which can be added to the calendar, inherit from the class CComponent. This
class contains methods to get or set parameters for any event, to‐do, journal or birthday. For
example, the developer can set the ID of the component by using the method setId().
The event type that can be added to the calendar are: CBdayEvent, CEvent, CJournal, and
CTodo. Each of these classes has a set of common methods inherited from the base class
CComponent and they have their own specific methods. For example, the CEvent class
provides method method setGeo() that allows the developer to set the location (latitude and
longitude) parameter. Other example is the class CBdayEvent, which allows the developer to
set the birth date by using method setBirthDate().
Calendar‐backend library also contains the class ICalConverter, used to convert local database
format to iCal (http://www.apple.com/support/ical/) data and vice versa. VCalConverter is
other class which converts local database format to other format. This class converts local
database format to vCal format and vice versa.
You can found more information about other classes, such as CCalendarDB, on API reference
of calendar backend (http://maemo.org/api_refs/5.0/beta/calendar‐backend/index.html).
4.2 Example The example used in this section is a simple calendar. It is implemented in Qt and it also uses
the Calendar‐backend API. The example manages a calendar such as the one illustrated on the
following pictures:
After creating a calendar, the application allows the management of events:
Maemo for Mobile Developers
The events, to‐do´s or birthdays can be visualized. It is possible to create new elements as well:
The example contains the following files (available for download later):
main.cpp: creates the Qt application and initializes calendar widget;
widget.h: contains declaration of names and methods to be implementated on
“widget.cpp” file;
widget.cpp: implements of main screen;
eventdialog.h: contains declaration of names and methods to be implementated on
“eventdialog.cpp” file;
eventdialog.cpp: implements event creation screen;
calendar.h: contains declaration of names and methods used on calendar.cpp file;
calendar.cpp: direclty accesses Calendar‐backend API.
The content of file “calendar.h” is shown below. This file declares class Calendar, including
variables and methods. This class inherits from QObject, which is the superclass for all Qt
applications. Then, it is necessary to add QObject hearder file. In this application, the date and
the time are managed in some functions, thus QDateTime header file must be included too.
Maemo for Mobile Developers
This header file also contains the declaration of five methods: addCalendar, removeCalendar,
addEvent, getEventsDays, and getEventsDescription.
#ifndef CALENDAR_H #define CALENDAR_H #include <QObject> #include <QDateTime> class CCalendar; class CMulticalendar; class CComponent; class Calendar : public QObject { Q_OBJECT public: Calendar(); ~Calendar(); public: bool addCalendar(const QString& calendarName); bool removeCalendar(const QString& calendarName); void addEvent(const QString& calendarName, const QDateTime& date, const QString& eventName, const QString& description, int type); /* Returns a list of dates that have events.*/ QList< QDate > getEventsDays(const QString& calendarName, int type, const QDateTime& startDate, const QDateTime& endDate); /* Returns a list of events descriptions.*/ QList<QString> getEventsDescription(const QString& calendarName, int type, const QDateTime& date); private: CMulticalendar* multiCalendar; }; #endif // CALENDAR_H
The “calendar.cpp” file contains the implementation of the functions declared in the header
file Calendar.h. At first, insert the required header files (calendar.h, CCalendar.h, etc.). These
files provide methods to manage calendars, multicalendars, events, to‐do´s, and birthdays:
#include "calendar.h" #include <CCalendar.h>
Maemo for Mobile Developers
#include <CMulticalendar.h> #include <CTodo.h> #include <CBdayEvent.h> #include <CEvent.h>
The variable DAY_IN_SECONDS is declared to be used in some methods:
static const int DAY_IN_SECONDS = 86400;
In Calendar class constructor, a single instance of a CMulticalendar is retrieved by using the
method MCInstance() of CMulticalendar:
Calendar::Calendar() { multiCalendar = CMulticalendar::MCInstance(); }
The destructor deletes the CMulticalendar instance:
Calendar::~Calendar() { delete multiCalendar; }
The method addCalendar adds a calendar to the CMulticalendar instance. This function
receives a string representing the calendar name to be added. To add a calendar, the method
addCalendar() of CMulticalendar must be used. This method receives the following parameters
in sequence: calendar title, color, flag for read only, flag for visible, type (0 for Local calendar, 1
for Sync calendar or 2 for Smart calendar), the tune which will be played in alarms, string for
calendar version, and the reference to the error code. When an error occurs, the value of the
errorCode is set to 0:
bool Calendar::addCalendar(const QString& calendarName) { CalendarType type = (CalendarType) 0; int errorCode = 0; multiCalendar->addCalendar (calendarName.toStdString(), COLOUR_RED, 0, 1, type , "Default", "0.1", errorCode); return (errorCode); }
The method removeCalendar() is used to remove a calendar from the CMultiCalendar instance.
This method receives the name of the calendar to be removed and uses the method
deleteCalendar() of CMultiCalendar to delete the calendar. The method deleteCalendar()
receives a calendar ID and a reference to error code. To get the calendar ID, a calendar
instance is required. The CMultiCalendar allows the developer to get an instance of CCalendar
by using the method getCalendarByName(), which receives the name of the calendar and a
Maemo for Mobile Developers
poiters to error code. Then, the ID of the calendar can be obtained with the method
getCalendarId() of CCalendar.
bool Calendar::removeCalendar(const QString& calendarName) { int errorCode = 0; bool success = false; CCalendar *calendar = multiCalendar->getCalendarByName (calendarName.toStdString(), errorCode); if (errorCode) { success = multiCalendar->deleteCalendar (calendar->getCalendarId(), errorCode); } delete calendar; return success; }
The method addEvent() add an event (to do, birthday or event) to a calendar. This method
receives four parameters which are: the name of the calendar in which the event will be
added, the date of the event, the name of the event, the description of event and the type of
event, which should be 0 for to do, 1 for birthday and 2 for event. The methods used to add
events are addTodo(), addBirthDay(), or addEvent() from CMultiCalendar. These methods
receive an instance of CTodo, CBdayEvent, or CEvent respectively. Each of these classes
receives in constructor the summary of the event, the due date and, in some cases, the status.
The possible values for status are: NEEDSACTION_STATUS , COMPLETED_STATUS,
INPROCESS_STATUS, CANCELLED_STATUS, CONFIRMED_STATUS, TENTATIVE_STATUS,
DRAFT_STATUS, FINAL_STATUS, SENT_STATUS, DECLINED_STATUS, DELEGATED_STATUS, or
ACCEPTED_STATUS.
void Calendar::addEvent(const QString& calendarName, const QDateTime& date, const QString& eventName, const QString& description, int type) { int errorCode = 0; int dateUtc = date.toTime_t(); CCalendar *calendar = multiCalendar->getCalendarByName (calendarName.toStdString(), errorCode); switch (type) { case 0: { CBdayEvent *pBdayEvent = new CBdayEvent(eventName.toStdString(), eventName.toStdString(), dateUtc); calendar->addBirthDay(pBdayEvent, errorCode); delete pBdayEvent; } break; case 1: { CEvent *pEvent = new CEvent(eventName.toStdString(), description.toStdString(), "", dateUtc, dateUtc);
Maemo for Mobile Developers
multiCalendar->addEvent(pEvent, calendar->getCalendarId(), errorCode); delete pEvent; } break; case 2: { CTodo *pTodo = new CTodo(eventName.toStdString(), dateUtc, ACCEPTED_STATUS); multiCalendar->addTodo(pTodo, calendar->getCalendarId(), errorCode); delete pTodo; } break; } delete calendar; }
The method getEventsDays() receives the calendar name, the type of the component (1 for
event, 2 for to do, or 3 to journal), the start date and the end date. The returned value is a
vector containing the dates of events:
QList< QDate > Calendar::getEventsDays(const QString& calendarName, int type, const QDateTime& startDate, const QDateTime& endDate) { int errorCode = 0; type = (type) ? type : 4; CCalendar *calendar = multiCalendar->getCalendarByName (calendarName.toStdString(), errorCode); vector< CComponent * > components; components = multiCalendar->getComponents(calendar->getCalendarId(), type, startDate.toTime_t(), endDate.toTime_t(), errorCode); QList<QDate> componentsVector; for (vector<CComponent *>::iterator it = components.begin();it!=components.end(); ++it) { QDateTime date = QDateTime::fromTime_t ( (*it)->getDateStart() ); componentsVector.append(date.date()); } return componentsVector; }
Maemo for Mobile Developers
The method getEventsDescription() receives three parameters: the calendar name, the type of
the component (1 for event, 2 for to do, or 3 to journal), and the date of events. The returned
value is a vector containing the description of the events of the specified date:
QList<QString>Calendar::getEventsDescription(const QString& calendarName, int type, const QDateTime& date) { int errorCode = 0; type = (type) ? type : 4; CCalendar *calendar = multiCalendar->getCalendarByName (calendarName.toStdString(), errorCode); vector< CComponent * > components; components = multiCalendar->getComponents (calendar->getCalendarId(), type, date.toTime_t(), date.toTime_t() + DAY_IN_SECONDS, errorCode); QList<QString> componentsVector; for (vector<CComponent *>::iterator it = components.begin();it!=components.end(); ++it) { QString output; QDateTime date = QDateTime::fromTime_t ( (*it)->getDateStart() ); output.append(date.toString(Qt::SystemLocaleShortDate)); output.append(" - "); output.append(QString::fromStdString((*it)->getSummary())); output.append("\n"); output.append(QString::fromStdString((*it)->getDescription())); componentsVector.append(output); } return componentsVector; }
4.3 Links SQLite ‐ http://www.sqlite.org/
Calendar backend ‐ http://maemo.org/api_refs/5.0/beta/calendar‐
backend/index.html
Maemo for Mobile Developers
5 ICD2
5.1 Introduction The Internet Connection Daemon 2 (ICd2) is responsible to manage connections to the internet on Maemo. It helps developers by providing an abstract layer to be used on applications that needs to get connected on internet. It is initialized at system boot time and stopped at system shutdown by /etc/init.d/icd2 init script. The main concept behind internet connections on Maemo devices is the Internet Access Point (IAP). As described in (Maemo.org, 2009), IAP represents a logical internet connection defined by the user. It defines, among other things, the radio bearer, procedures for authentication, proxy servers and the corresponding access point in the internet. ICd2 API defines methods to retrieve information about system connections besides requesting a connection, initiate scan procedures and request connection state. Such API is proprietary, becoming impossible to compile it and run on other platforms or in standard Linux as well. Although, it provides header files to be include in C and C++ source codes. The latest version is 0.85+0m5 and it is compatible with Diablo and Fremantle Maemo SDK versions. It is simple and it has only three header files to be exported. ICd2 is a D‐Bus API, internal to the connectivity subsystem and it is used by LibConic and connectivity UIs. LibConic is indicated to be used instead of requesting network connections by interacting directly with ICd2 since it is the stable maintained API for network connectivity, which encapsulates D‐Bus calls. As pointed by (Maemo.org, 2009), ICd2 is considered to be in alpha state and it may change without further notice. Despite that, using LibConic becomes harder if the code has to be written in Qt, once LibConic is written using Glib, what incurs in a problem of two main loops needing to run concurrently. In addition, Qt provides an easy way to call methods or receive signals from D‐Bus through QtDBus library. Considering that, this documentation focus on ICd2 usage linked to Qt through D‐bus. Once this API works through D‐Bus, it is better to test codes on target device. It is also necessary to check if environment settings are correctly defined, which would lead to a problem of connecting to this service. This API also makes it possible to write new Network or Service modules and run Debian‐style network scripts to be executed before and/or after a network connection is connected and disconnected. A Network module has three layers: the link layer, the authentication layer and the IP layer. A module can choose to implement functions on one or more layer. It is necessary to a link layer module to implement network search functionality, which reports to ICd2 what networks are available. Service modules provide functionalities that are often used after IP address has been acquired, such as authentication for WLAN hotspot logins.
5.2 Architecture ICd2 API has three modules: Network module API definitions, Service Provider API and
ICd2 D‐Bus API. The first one is used to define the network itself regarding the link layer, the
authentication layer and/or the IP Layer.
The Service Provider API provides an identification function, which receives network
module search results and returns service module information if the service module is able to
use the network (Maemo.org, 2009).
The ICd2 D‐Bus API generates responses to D‐Bus API requests. It also creates IAP’s and
it selects the right networks associated with it.
Maemo for Mobile Developers
5.3 Main Classes and Methods This documentation is focused on using the ICd2 D‐bus API to call methods from Qt
using QtDBus library. The main methods of this module are:
ICD_DBUS_API_ADDRINFO_REQ "addrinfo_req" Requests specific connection addresses info. Callback:ICD_DBUS_API_ADDRINFO_SIG "addrinfo_sig"
o DBUS_TYPE_STRING service type or empty string o DBUS_TYPE_UINT32 service attributes, see o DBUS_TYPE_STRING service id or empty string o DBUS_TYPE_STRING network type or empty string o DBUS_TYPE_UINT32 network attributes, see o DBUS_TYPE_ARRAY (BYTE) network id or empty string o DBUS_TYPE_ARRAY ( o DBUS_TYPE_STRING IP address o DBUS_TYPE_STRING IP netmask o DBUS_TYPE_STRING IP default gateway o DBUS_TYPE_STRING IP address of DNS server #1 o DBUS_TYPE_STRING IP address of DNS server #2 o DBUS_TYPE_STRING IP address of DNS server #3 o )
ICD_DBUS_API_CONNECT_REQ "connect_req" Requests a network connection. It makes ICd2 to select a suitable connection or try the specified connection. Callback: ICD_DBUS_API_CONNECT_SIG "connect_sig"
o DBUS_TYPE_STRING service type or empty string o DBUS_TYPE_UINT32 service attributes o DBUS_TYPE_STRING service id or empty string o DBUS_TYPE_STRING network type or empty string o DBUS_TYPE_UINT32 network attributes o DBUS_TYPE_ARRAY (BYTE) network id or empty string o DBUS_TYPE_UINT32 status
ICD_DBUS_API_DISCONNECT_REQ "disconnect_req" Requests to disconnect an ongoing connection or the last connection.
ICD_DBUS_API_SCAN_REQ "scan_req" Initiates or stops an IAP scan. Callback: ICD_DBUS_API_SCAN_SIG "scan_result_sig"
o DBUS_TYPE_UINT32 icd_scan_status o DBUS_TYPE_UINT32 timestamp when last seen o DBUS_TYPE_STRING service type o DBUS_TYPE_STRING service name o DBUS_TYPE_UINT32 service attributes o DBUS_TYPE_STRING service id o DBUS_TYPE_INT32 service priority within a service type o DBUS_TYPE_STRING network type o DBUS_TYPE_STRING network name
Maemo for Mobile Developers
o DBUS_TYPE_UINT32 network attributes o DBUS_TYPE_ARRAY(BYTE) network id o DBUS_TYPE_INT32 network priority for different network types o DBUS_TYPE_INT32 signal strength/quality,0(none) ‐ 10(good) o DBUS_TYPE_STRING station id o DBUS_TYPE_INT32 signal value in dB
ICD_DBUS_API_SELECT_REQ "select_req" Requests the 'Select connection' dialog.
ICD_DBUS_API_STATE_REQ "state_req" Requests connection state. Callback: ICD_DBUS_API_STATE_SIG "state_sig" States signal sent in response to ICD_DBUS_API_STATE_REQ or broadcasted whenever the state of a connection changes. This is the unique signal that is broadcasted regardless of a previous request.
o DBUS_TYPE_STRING service type or empty string o DBUS_TYPE_UINT32 service attributes o DBUS_TYPE_STRING service id or empty string o DBUS_TYPE_STRING network type or empty string o DBUS_TYPE_UINT32 network attributes o DBUS_TYPE_ARRAY (BYTE) network id or empty string o DBUS_TYPE_STRING error that occurred; empty string on success o DBUS_TYPE_UINT32 state of the network
ICD_DBUS_API_STATISTICS_REQ "statistics_req" Requests specific connection statistics or for all connections. Callback:ICD_DBUS_API_STATISTICS_SIG "statistics_sig" Sent if there are ongoing connections.
o DBUS_TYPE_STRING service type or empty string o DBUS_TYPE_UINT32 service attributes o DBUS_TYPE_STRING service id or empty string o DBUS_TYPE_STRING network type or empty string o DBUS_TYPE_UINT32 network attributes o DBUS_TYPE_ARRAY (BYTE) network id or empty string o DBUS_TYPE_UINT32 time active, measured in seconds o DBUS_TYPE_INT32 signal strength/quality o DBUS_TYPE_UINT32 bytes sent
Maemo for Mobile Developers
5.4 Example
5.4.1 Internet Connection Daemon 2 Example This example was designed to have a very simple UI focusing on Internet Connection Daemon
2 functionalities. As shown on Figure 1, the UI is a form with two columns where the
connection state and activity will be displayed.
Figure 2 – Icd2 example UI.
This example was written using the Qt framework. It is split into five files: widget.cpp,
widget.h, icdhandler.cpp, icdhandler.h and main.cpp. The files widget.cpp and widget.h
contains functions to control user interface. The files icdhandler.cpp is responsible to
communicate with ICd2 by using the QtDBus library. The file main.cpp has only the main
function to create the described objects and start the application.
The UI developed for this example uses QVBoxLayouts and QHBoxLayouts in addition to a
QFormLayout in the left column and QGridLayout on the right column to organize the widgets.
The majority of widgets are QLabels but a QProgressBar is used to display the signal quality.
The example application will be availa ble for download later. The example code is explained as
follows. The main functionality is implemented by a class labeled IcdHandler. It is used to
encapsulate D‐Bus calls. In doing so, it is necessary to include the headers from ICd2 library
and QDbus library into the source file as follows:
#include <QtDBus>
#include <icd/dbus_api.h>
To link the example against QDBus and ICd2 library, it is necessary to add the following line to
the project file:
CONFIG += icd2 qdbus
Maemo for Mobile Developers
To get connected to the system bus through QDBus library, it is necessary to call the static
method systemBus() from QDBusConnection class.
static QDBusConnection bus = QDBusConnection::systemBus();
In order to connect to ICd2 Bus API interface, an object of QDBusInterface has to be
instantiated. It is necessary to pass the ICD_DBUS_API_INTERFACE, the ICD_DBUS_API_PATH
and the system bus as arguments to the constructor.
IcdHandler::IcdHandler(QObject *parent):QObject(parent)
{
interface = new QDBusInterface (ICD_DBUS_API_INTERFACE,
ICD_DBUS_API_PATH,
ICD_DBUS_API_INTERFACE,
bus);
bus.connect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH, ICD_DBUS_API_INTERFACE,
ICD_DBUS_API_STATISTICS_SIG, this, SLOT(statisticsSentResult(const QDBusMessage&)));
bus.connect(ICD_DBUS_API_INTERFACE, ICD_DBUS_API_PATH, ICD_DBUS_API_INTERFACE,
ICD_DBUS_API_STATE_SIG, this, SLOT(changeState(const QDBusMessage&)));
}
In order to listen to a signal from ICD_DBUS_API_INTERFACE, the connect() method from
QDBusConnection is used to connect a signal emitted from D‐Bus to a slot of this class.
The first connect call links the ICD_DBUS_API_STATISTICS_SIG to the statisticsSentResult(const
QDBusMessage&) slot. The second connects the ICD_DBUS_API_STATE_SIG signal from ICd2 to
the changeState(const QDBusMessage&) slot. The interaction between these classes can be
seen on Figure 2.
Maemo for Mobile Developers
To retrieve information from a QDBusMessage, it is necessary to call the arguments() method
from QDBusMessage object. It returns a QList object with QVariants objects.
Both changeState(const QDBusMessage&) and statisticsSentResult(const QDBusMessage&
rep) slots just receive the signal from ICd2, retrieve the QList and emit a Qt signal as shown on
the following code snip:
void IcdHandler::changeState(const QDBusMessage& rep)
{
emit stateChanged(rep.arguments());
}
void IcdHandler::statisticsSentResult(const QDBusMessage& rep)
{
emit statisticsChanged(rep.arguments());
}
The main.cpp file has only the main function, which creates the Widget and the IcdHandler
classes. In addition, the main class also connects both classes through signals and slots.
The IcdHandler class has the following slots and signals:
class IcdHandler : public QObject
{
…
public slots:
void statisticsSentResult(const QDBusMessage& rep);
void changeState(const QDBusMessage& rep);
void disconnect();
void connect();
void updateStatistics();
void updateConnectionState();
signals:
ICD_DBUS_API_STATISTICS
ICD_DBUS_API_STATE_REQ
ICD_DBUS_API_DISCONNECT_REQ
statisticsSentResult ICD_DBUS_API_STATISTICS_SIG
IcdHandler D‐Bus
ICD_DBUS_API_STATE_SIGchangeState
Maemo for Mobile Developers
void stateChanged(const QList<QVariant> state);
void statisticsChanged(const QList<QVariant> statistics);
…
};
The Widget class has the following slots and signals:
class Widget : public QWidget
{
…
signals:
void connectionButton_clicked();
void disconnectButton_clicked();
void updateStatisticsRequested();
void updateStateRequested();
public slots:
void updateConnectionState(const QList<QVariant> state);
void updateStatisticsState(const QList<QVariant> statistics);
private slots:
void on_disconnectButton_clicked();
void on_connectionButton_clicked();
void timer_tick();
…
private:
…
QTimer *timer;
};
Once Widget and IcdHandle object are instantiated, the main function connects signals and
slots from them as follows:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget widget;
IcdHandler handler;
QObject::connect(&widget, SIGNAL(connectionButton_clicked()), &handler,
SLOT(connect()));
QObject::connect(&widget, SIGNAL(disconnectButton_clicked()), &handler,
SLOT(disconnect()));
Maemo for Mobile Developers
QObject::connect(&widget, SIGNAL(updateStatisticsRequested()), &handler,
SLOT(updateStatistics()));
handler.updateConnectionState();
QObject::connect(&handler, SIGNAL(stateChanged(const QList<QVariant>)),
&widget, SLOT(updateConnectionState(const QList<QVariant>)));
QObject::connect(&handler, SIGNAL(statisticsChanged(const QList<QVariant>)),
&widget, SLOT(updateStatisticsState(const QList<QVariant>)));
widget.show();
return a.exec();
}
Figure 3 – Signals and slots connections between Widget, IcdHandler and Timer classes
Widget
Timer
connectionButton_clicked
disconnectButton_clicked
connect
disconnect
updateStatisticsRequested updateStatistics
updateConnectionState stateChanged
IcdHandler
statisticsChangedupdateStatisticsState
Besides interacting with IcdHandler, the Widget also receives periodic signals from QTimer to
be used to update connection statistics. It is done in the following way:
D‐Bus
Widget::Widget(QWidget *parent)
Maemo for Mobile Developers
: QWidget(parent)
{
timer = new QTimer(this);
…
}
void Widget::updateConnectionState(const QList<QVariant> state)
{
unsigned int connectionStatus = state.value(7).value<unsigned int>();
if (connectionStatus)
{
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timer_tick()));
timer‐>start(800);
}
else
{
timer‐>stop();
networkField‐>setText("");
durationField‐>setText("");
progressBar‐>setValue(0);
sentField‐>setText("");
receivedField‐>setText("");
}
if (connectionStatus < 6)
{
statusField‐>setText(connectionStates[connectionStatus]);
}
}
When connections status becomes different of zero, it indicates that the device is connected
to the internet the timer has been started. As the device gets disconnected, it is stopped and
the statistics fields of the UI are cleaned.
5.5 Links ‐ Garage project
‐ SVN
‐ Upstream project page
‐ Applications using this lib
5.5.1 Documentation/Maemo 5 Developer Guide/Using Connectivity Components/Maemo Connectivity
http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Connectivity_Co
mponents/Maemo_Connectivity
Maemo for Mobile Developers
5.5.2 Internet Connectivity daemon version 2 http://maemo.org/api_refs/5.0/beta/icd2
5.5.3 Bibliography Maemo.org. (17 de Agosto de 2009). Internet Connectivity daemon version 2 API Reference.
Acesso em 17 de Agosto de 2009, disponível em Internet Connectivity daemon version 2:
http://maemo.org/api_refs/5.0/beta/icd2/
Maemo.org. (17 de Agosto de 2009). Maemo 5 Developer Guide. Acesso em 17 de Agosto de
2009, disponível em Maemo 5 Developer Guide:
http://wiki.maemo.org/Documentation/Maemo_5_Developer_Guide/Using_Connectivity_Co
mponents/Maemo_Connectivity
6 A GUI example
6.1 Introduction One of the greatest advantages of Qt framework is its portability to different platforms, so an
application that runs on Desktop probably runs on mobile devices as well. With Qt, porting
applications to Maemo platform is a painless task. Only few things must be considered, such as
storage location, input events and input method, which are detailed in this section.
For Maemo platform, the Qt framework is significantly well integrated. However, Qt looks a
little bit different in Maemo platform, because it was modified to be integrated with Hildon.
Hildon is an application framework for mobile devices based on Linux operating system. In
addition, Hildon takes into account all constraints of mobile devices, such as restrict user
interface, in order to provide enhancements for user experience. The following screenshot of a
Qt application running on Maemo without Hildon integration:
Note that widgets (combo boxes, lists, menu, etc.) are small and they are not suitable to be
selected with fingers. In addition, considering that the font is also small, the labels are difficult
to read. Now, look at the same Qt application running with Hildon:
Maemo for Mobile Developers
6.2 Main classes and methods The most important class in Qt, concerning about graphical user interface, is the QWidget
class, which is the base class of all GUI objects.
One of the most important classes inherited from QWidget is the main window. On main
window, it is possible to add widgets, such as menus, tables, boxes, buttons, text fields or
other useful components. In Qt, the class representing the main window is the QMainWindow.
Some other useful methods of QMainWindow are described below:
setCentralWidget: this method receives a widget and places it on the central area of
the main window;
menuBar: returns the menu bar for the main window, which allows to add menu
actions. The menu lies in the top of window;
statusBar: returns the status bar for the main window. It is possible to add messages
on it.
As additional examples, other useful widgets inherited from QWidget are QPushButton,
QLineEdit, and QComboBox. QPushButton is a Qt button that emits the clicked() signal when it
is activated. QLineEdit is a text field that emits signals, such as textChanged() (emitted when
the text inside the widget is changed). QComboBox is a widget that merges a button and
popup list and it emits the signal currentIndexChanged() when the selection is changed.
You can use other widgets. For more documentation about it, see Qt classes documentation
(http://doc.trolltech.com/4.5/classes.html).
6.3 Example To describe how to develop Qt GUI Maemo applications, we provide an interesting example
that implements a SIP extensions viewer. The SIP and names values are retrieved from a file.
This example will be available for download later. The main window contains a list of
extensions as shown on the following picture:
Maemo for Mobile Developers
In addition, the main window also contains a menu list with a few options:
When the Menu → Import from file option is selected, a dialog is opened to insert the file
location which is used to populate the list:
After file selection, the table is updated:
Maemo for Mobile Developers
Finally, it is possible to search for contacts:
The example package contains eight files, which are described as follows:
sip_finder.cpp: contains the class SIPFinder implementation, which represents the
main window;
sip_finder.h: contains the definition of the SIPFinder class and variables definition;
sip_finder_table.h: contains the definition of the SIPFinderTable class. This class
inherits from table types that lists SIP extensions and their names. The table can be
filtered with regular expressions inserted in a text field;
sip_finder_table.cpp: provides SIPFinderTable class implementation;
import_dialog.h: contains the definition of the ImportDialog class;
import_dialog.cpp: contains the implementation of ImportDialog class, which is a
dialog containing a text field and a button;
sip_finder.pro: contains information to compile the application.
6.3.1 Main window
Maemo for Mobile Developers
The “sip_finder.h” file is shown as follows. Note that the class SIPFinder inherits from
QMainWindow, so the “QMainWindow” header file must be included. The constructor of the
class SIPFinder receives an instance of SIPFinderTable as parameter, so the “qt_gui.h” header
file must be included. This instance is used as main widget of the window. The slot
importFromFile() will be connected to a menu action. The methods createActions() and
createMenus() help to create menus and their actions:
#ifndef SIPFinder_H
#define SIPFinder_H
#include <QMainWindow>
#include <qt_gui.h>
class QAction;
class QActionGroup;
class QLabel;
class QMenu;
class SIPFinder : public QMainWindow
{
Q_OBJECT
public:
SIPFinder(SIPFinderTable *table);
protected:
void contextMenuEvent(QContextMenuEvent *event);
private slots:
void importFromFile();
private:
void createActions();
void createMenus();
SIPFinderTable *sipFinderTable;
QMenu *fileMenu;
QActionGroup *alignmentGroup;
QAction *importFromFileAct;
QAction *exitAct;
};
#endif
Maemo for Mobile Developers
The “sip_finder.cpp” file is described in details as follows. This file includes seven header files.
The “QtGui” header is used for create GUI components. The “QFile”, “QIODevice” and
“QTextStream” files allow reading data from local files:
#include <QtGui>
#include <QFile>
#include <QIODevice>
#include <QTextStream>
#include "sip_finder_table.h"
#include "sip_finder.h"
#include "import_dialog.h"
The constructor of SIPFinder class receives a SIPFinderTable instance as parameter and set it as
the central widget of application. This is made by the function setCentralWidget() of
QMainWindow. The window title is set with the function setWindowTitle(). The methods
createActions() and createMenus() are called to create the actions for menu and the menu
itself:
SIPFinder::SIPFinder(SIPFinderTable *table)
{
sipFinderTable = table;
setCentralWidget(sipFinderTable);
createActions();
createMenus();
setWindowTitle(tr("Menu"));
}
The method createActions() creates two QAction objects: importFromFileAct and exitAct. The
QAction receives a String as menu item name. The importFromFileAct is connected to slot
importFromFile(), which imports the file with SIP extensions, and the exitAct is connected to
the slot close(), which closes the window:
void SIPFinder::createActions()
{
importFromFileAct = new QAction(tr("Import from file"), this);
importFromFileAct‐>setStatusTip(tr("Import extensions from a local file"));
connect(importFromFileAct, SIGNAL(triggered()), this, SLOT(importFromFile()));
exitAct = new QAction(tr("Exit"), this);
exitAct‐>setStatusTip(tr("Exit the application"));
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
}
Maemo for Mobile Developers
The method createMenus() calls the method menuBar() of QMainWindow. This method
returns a QMenuBar instance, which provides the method addMenu(), which is used to append
a new menu (with the name passed as paremeter) to the menu bar. This operation returns a
QMenu instance, which is associated to the fileMenu variable. The actions importFromFileAct
and exitAct are added to fileMenu by using method addAction():
void SIPFinder::createMenus()
{
fileMenu = menuBar()‐>addMenu(tr("Import"));
fileMenu‐>addAction(importFromFileAct);
fileMenu‐>addSeparator();
fileMenu‐>addAction(exitAct);
}
The method importFromFile() creates a dialog. The dialog contains a text field and a button.
The user can insert the file location containing SIP extensions and names in the text field and
press the button to confirm. After that, the file is opened and the content of the table placed
on central part of the window is changed with the function setSourceModel() of
SIPFinderTable. To open a file, an QFile object is created and the method open() of QFile is
called. To read the file, an QTextStream object is created and, until it reaches the end of file,
each line is read with the method readLine() of QTextStream:
void SIPFinder::importFromFile()
{
ImportDialog import(this);
import.exec();
QFile file(import.getLineEditText());
QStringList sipAndName;
QStringList sip;
QStringList name;
QString line;
if (file.open(QIODevice::ReadOnly)) {
QTextStream textStream( &file );
while ( ! textStream.atEnd() ) {
line = textStream.readLine();
sipAndName = line.split(",");
sip.append(sipAndName[0]);
name.append(sipAndName[1]);
}
}
file.close();
Maemo for Mobile Developers
sipFinderTable‐>setSourceModel(sipFinderTable‐>createSIPModel(sip, name));
}
The following file is used to populate the list of SIP extensions and names. To separate the SIP
extension and the name, methods split() of QString are used. This method receives the
separation token as parameter and creates a QStringList with the separated elements.
101,Diego Bezerra
102,Mateus Lima
103,Hallyson Melo
6.3.2 Table The “sip_finder_table.h” is shown below. The class SIPFinderTable inherits from QWidget, so
we need to include QWidget header file. Three methods are defined to help the creation of
table: setSourceModel(), addExtension(), and createSIPModel(). One slot, SetRegExpFilter, is
invoked whenever the pattern of filter changes.
#ifndef SIPFinderTable_H
#define SIPFinderTable_H
#include <QWidget>
class QAbstractItemModel;
class QComboBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QSortFilterProxyModel;
class QTreeView;
class SIPFinderTable : public QWidget
{
Q_OBJECT
public:
SIPFinderTable();
void setSourceModel(QAbstractItemModel *model);
void addExtension(QAbstractItemModel *model, const QString &extension,
const QString &name);
QAbstractItemModel *createSIPModel(QStringList sip, QStringList name);
private slots:
void SetRegExpFilter();
void filterColumnChanged();
Maemo for Mobile Developers
private:
QSortFilterProxyModel *proxyModel;
QGroupBox *proxyGroupBox;
QTreeView *proxyView;
QLabel *filterPatternLabel;
QLabel *filterColumnLabel;
QLineEdit *filterPatternLineEdit;
QComboBox *filterColumnComboBox;
};
#endif
File “sip_finder_table.cpp” is described as follows. At first, the QtGui header file is included so
it is possible to use Qt GUI components:
#include <QtGui>
#include "sip_finder_table.h"
The constructor creates the table which contains the SIP extensions and names, and it creates
a text field to allow the user searching for names or SIP extensions. The table created,
proxyView, is of type QTreeView. Such table type needs a model. In this case, it is used a model
of type QSortFilterProxyModel (named proxyModel), which provides support for sorting and
filtering data. After that, a text field is created with name filterPatternLineEdit and type
QLineEdit, and is associated to label filterPatternLabel. Once created, the text field is
connected to slot SetRegExpFilter, which is called when the text changes.
A combo box named filterColumnComboBox of type QComboBox is created to hold the search
options “Name” or “Extension”. It indicates in which text field the string pattern will be
located. This combo box is connected to the slot filterColumnChanged(), which is called
whenever the option in the combo box is changed.
Finally, the grid layout proxyLayout of type QGridLayout is created to hold some GUI
components, which is implemented by function addWidget().
SIPFinderTable::SIPFinderTable()
{
/*The QSortFilterProxyModel class provides support for sorting and
filtering data passed between another model and a view*/
proxyModel = new QSortFilterProxyModel;
proxyModel‐>setDynamicSortFilter(true);
proxyGroupBox = new QGroupBox(tr("Extensions list"));
proxyView = new QTreeView;
Maemo for Mobile Developers
proxyView‐>setRootIsDecorated(false);
proxyView‐>setAlternatingRowColors(true);
proxyView‐>setModel(proxyModel);
proxyView‐>setSortingEnabled(true);
filterPatternLineEdit = new QLineEdit;
filterPatternLabel = new QLabel(tr("Search:"));
filterPatternLabel‐>setBuddy(filterPatternLineEdit);
connect(filterPatternLineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(filterRegExpChanged()));
filterColumnComboBox = new QComboBox;
filterColumnComboBox‐>addItem(tr("Extension"));
filterColumnComboBox‐>addItem(tr("Name"));
filterColumnLabel = new QLabel(tr("Search for:"));
filterColumnLabel‐>setBuddy(filterColumnComboBox);
connect(filterColumnComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(filterColumnChanged()));
QGridLayout *proxyLayout = new QGridLayout;
proxyLayout‐>addWidget(proxyView, 0, 0, 1, 3);
proxyLayout‐>addWidget(filterPatternLabel, 1, 0);
proxyLayout‐>addWidget(filterPatternLineEdit, 1, 1, 1, 2);
proxyLayout‐>addWidget(filterColumnLabel, 2, 0);
proxyLayout‐>addWidget(filterColumnComboBox, 2, 1, 1, 2);
proxyGroupBox‐>setLayout(proxyLayout);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout‐>addWidget(proxyGroupBox);
setLayout(mainLayout);
setWindowTitle(tr("Basic Sort/Filter Model"));
resize(800, 480);
proxyView‐>sortByColumn(1, Qt::AscendingOrder);
filterColumnComboBox‐>setCurrentIndex(1);
}
The method createSIPModel() is called in the main window by method importFromFile(), which
reads a file and populate the table with the SIP extensions and names from the file. A generic
model for storing custom data is created with name model and type QStandardItemModel. The
constructor of QStandardItemModel receives three parameters: the rows quantity, the
Maemo for Mobile Developers
columns quantity and the parent window. The method setHeaderData is used to set columns
names. The method addExtension() is called to populate the table and it is detailed later.
QAbstractItemModel* SIPFinderTable::createSIPModel(QStringList sip, QStringList name)
{
QStandardItemModel *model = new QStandardItemModel(0, 2, this);
model‐>setHeaderData(0, Qt::Horizontal, QObject::tr("Extension"));
model‐>setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
for (int i = 0; i < sip.size(); ++i){
addExtension(model, sip[i], name[i]);
}
return model;
}
The method addExtension() update SIP extensions and names of an model received as
QAbstractItemModel as parameter. This is made by using the method setData() of
QAbstractItemModel.
void SIPFinderTable::addExtension(QAbstractItemModel *model, const QString &extension,
const QString &name)
{
model‐>insertRow(0);
model‐>setData(model‐>index(0, 0), extension);
model‐>setData(model‐>index(0, 1), name);
}
The method setSourceModel() is called in the constructor of SIPFinder class. This method only
sets the source model of QAbstractItemModel, by using the method setSourceModel().
void SIPFinderTable::setSourceModel(QAbstractItemModel *model)
{
proxyModel‐>setSourceModel(model);
}
The slot filterRegExpChanged() creates a regular expression (QRegExp) based on text inserted
by the user. It uses such expression as filter and set it to proxyModel using the method
setFilterRegExp().
void SIPFinderTable::filterRegExpChanged()
{
QRegExp regExp(filterPatternLineEdit‐>text(), Qt::CaseInsensitive, QRegExp::RegExp);
proxyModel‐>setFilterRegExp(regExp);
Maemo for Mobile Developers
}
The slot filterColumnChanged only sets the filter, to a selected column in the combo box, to
the proxyModel using the method setFilterKeyColumn.
void SIPFinderTable::filterColumnChanged()
{
proxyModel‐>setFilterKeyColumn(filterColumnComboBox‐>currentIndex());
}
6.4 Links Qt examples: http://doc.trolltech.com/4.5/examples.html
Opening files in Qt: http://doc.trolltech.com/4.5/qfile.html
7 Whacamole game example
7.1 introduction In this section we present a whac‐a‐mole Qt game for Maemo. This example uses a lot of Qt
widgets and uses the touch screen functionality. Through this section we will show some
screenshots and the code to generate them. The example will be available for download later.
The complete example contains the following files:
main.cpp: entry point of application;
game_window.cpp: implementation of main window;
main_screen.cpp: implementation of a screen for start the game and set the player
name;
records_screen.cpp: implementation of a screen to show the game records;
records.txt: file for records persistence;
moleCatcher.pro: project definition file;
gamecontroller.cpp: implementation of game core. It is responsible for all game
control;
graphwidget.cpp: implementation of QGraphicsView class, which is responsible for
display a QGraphicsScene;
mole.cpp: implementation of a class that encapsulates a QGraphicsPixmapItem item.
This item will be managed in QGraphicsScene described above;
mainui.cpp: implementation of a class responsible for set up the game screen
(QGraphicsView mentioned above), such as set up background image;
pngitem.cpp: implementation of a QGraphicsPixmapItem wich will be managed in
QGraphicsScene described above. It loads a png image file. ;
graphwidgetpositioner.cpp: implementation of a class responsible for calculate
positions for QGraphicsPixmapItem items on QGraphicsScene scene.
Maemo for Mobile Developers
The game start point is the class GameWindow. This class creates the main window, initiates
the GameController class and creates a MainUi instance. The main game classes are described
below.
7.2 Example
7.2.1 Game main window The game_window.cpp file contains the implementation of the game main window. It inherits
from QMainWindow, which allows the creation of a window to hold menu, status bar, widgets,
layouts, toolbars and other things. In this example, the main window will hold a menu and
some widgets as central widgets. The central widget will change in time. At first, we set a
widget containing a label, a text field for player name entry, and a start button. When the user
presses the start button, the central widget is changed to a QGraphicsView, which is the game
action screen. When the user choices “Show records” menu option, a widget containing a
QTreeView (used to show the table of records) is set as central widget. A screenshot of the
game main window is show below:
To set a widget as central widget of a QMainWindow is very easy. It is made by using the
function setCentralWdget(), which receives a widget as parameter. An example code is shown
below:
...
mainScreen = new MainScreen(); setCentralWidget(mainScreen); ...
The window menu bar holds three options: “Start Game”, “Show records”, and “exit”. At first,
the actions are created with the following code:
void GameWindow::createActions()
{
startGameAct = new QAction(tr("Start Game"), this);
startGameAct‐>setStatusTip(tr("Starts the game"));
connect(startGameAct, SIGNAL(triggered()), this, SLOT(startGame()));
Maemo for Mobile Developers
showRecordsAct = new QAction(tr("Show records"), this);
showRecordsAct‐>setStatusTip(tr("Shows the records list"));
connect(showRecordsAct, SIGNAL(triggered()), this, SLOT(showRecords()));
exitAct = new QAction(tr("Exit"), this);
exitAct‐>setStatusTip(tr("Exit the application"));
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
}
Note that startGameAct and showRecordsAct actions are connected to startGame() and
showRecords() slots respectively. These slots are used to set widgets as central widget. After
that, a menu is created on the menu bar and the actions above are added:
mainMenu = menuBar()‐>addMenu(tr("Main menu"));
mainMenu‐>addAction(startGameAct);
mainMenu‐>addAction(showRecordsAct);
mainMenu‐>addAction(exitAct);
A screenshot of menu is shown below:
7.2.2 Main screen The “main_screen.cpp” file contains the implementation of a widget to get the player name
and start the game. This widget is shown in the initialization of the game as the main screen
central widget. A screenshot of this widget is shown below:
Maemo for Mobile Developers
The player name is set through a QLineEdit widget. An example of QLineEdit creation is shown
below:
QLineEdit *playerNameLineEdit = new QLineEdit();
To get the text inserted in this widget is quite easy by using the method text(), for example:
playerNameLineEdit‐>text();
Other widget used in main screen is a QPushButton. The button is created using the code
below:
QPushButton *startGameButton = new QPushButton("Start game");
The button is connected to a signal in spite of a slot. This is made by using the macro SIGNAL
such as in following code:
connect(startGameButton, SIGNAL(clicked()), this, SIGNAL(startButtonPressed()));
In this case, the signal clicked() of QPushButton is connected to the signal startButtonPressed()
(declared as signal in “main_screen.h” header file). When the button is pressed, the signal
startButtonPressed() is emitted. This signal is connected to a slot, which starts the game, in
“game_window.cpp” file.
7.2.3 Records screen The “records_screen.cpp” file contains the implementation of a widget used to show records
(names and scores) in a table. A screenshot of this widget is shown below:
Maemo for Mobile Developers
The table itself is a QTreeView, which is created with the following code:
QTreeView *proxyView = new QTreeView();
A model must be created and set as QTreeView model by using setModel() method. The model
can be of type: QAbstractListModel, QAbstractProxyModel, QAbstractTableModel, QDirModel,
QFileSystemModel, QHelpContentModel, QProxyModel, or QStandardItemModel. All these
models inherit from QAbstractItemModel. In this example we have used
QSortFilterProxyModel such as in the code below:
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel();
proxyView‐>setModel(proxyModel);
In this example a QStandardItemModel object is created and is processed by proxyModel. It is
possible by using the method setSourceModel(). The code below shows how to create a
QStandardItemModel and add two columns to it:
QStandardItemModel *model = new QStandardItemModel(0, 2, this);
model‐>setHeaderData(0, Qt::Horizontal, QObject::tr("player"));
model‐>setHeaderData(1, Qt::Horizontal, QObject::tr("score"));
Here, two columns are created with “player” and “score” names as headers, respectively. To
add items to QStandardItemModel, we firstly insert a new row with insertRow() and then use
setData() to insert items on it. The setData() method receives item index (index(row, column)),
and the item value:
model‐>insertRow(0); model‐>setData(model‐>index(0, 0), “player1”); model‐>setData(model‐>index(0, 1), “1200”);
Now we can set the source model to QSortFilterProxyModel:
proxyModel‐>setSourceModel(model);
Maemo for Mobile Developers
7.2.4 Game controller The “gamecontroller.cpp” file contains the GameController class implementation. This class is
responsible for controlling game timers, such as the timer which will count the game duration
and the timer which will count the duration of a mole on the screen. It also choices randomly
the position where a new created mole will appear on the screen.
The class GameController constructor generates, at first, a random number sequence of
pseudo random integers. It will be used latter for determine a new mole position on screen. It
also assigns the value zero to currentScore integer:
qsrand((QTime::currentTime()).msec());
currentScore = 0;
After it, all the game timers are initialized:
mole_timer = new QTimer(this);
connect(mole_timer, SIGNAL(timeout()), this, SLOT(timerTick()));
mole_timer‐>start(MOLE_DURATION);
QTimer::singleShot(GAME_DURATION, this, SLOT(gameTimeout()));
Note that a QTimer is created and its signal timeout() is connected to timerTick() slot. After it,
the timer is started with MOLE_DURATION integer as parameter. It means that when the timer
reaches the MOLE_DURATION milliseconds value, the slot timerTick() is called. This slot is
shown below:
void GameController::timerTick()
{
int position = qrand() % NUM_SLOTS;
emit moleAdded(position, MOLE_DURATION);
}
This slot calculates a random number between zero and NUM_SLOTS and emits the
moleAdded() signal with the calculated number (position) and the duration which a new mole
will stay on the screen.
Let’s take a look at the method startGame() of GameWindow:
void GameWindow::startGame()
{
playerName = mainScreen‐>getPlayerName();
controller = new GameController();
gameUi = new MainUi();
showRecordsAct‐>setVisible(false);
Maemo for Mobile Developers
QObject::connect(controller, SIGNAL(moleAdded(int, int)), gameUi, SLOT(addMole(int, int)));
QObject::connect(controller, SIGNAL(gameStarted(quint32)), gameUi,
SLOT(setupUi(quint32)));
QObject::connect(controller, SIGNAL(scoreChanged(int)), gameUi, SLOT(changeScore(int)));
QObject::connect(controller, SIGNAL(gameEnded(int)), this, SLOT(endGame(int)));
QObject::connect(gameUi, SIGNAL(hit()), controller, SLOT(updateScore()));
QObject::connect(gameUi, SIGNAL(userLeave()), controller, SLOT(endGame()));
controller‐>startGame();
setCentralWidget(gameUi);
}
Note that three signals defined in GameController are connected to MainUi() slots. The signals
are: moleAdded(), gameStarted() and scoreChanged(). The GameController moleAdded() signal
is connected to MainUi() addMole() slot, which is called when a mole is requested to be added
on the scene. The GameController scoreChanged() signal is connected to MainUi()
changeScore() slot to change score value on screen. Two GameController slots are connected
to MainUi() signals: updateScore() and endGame(). The first is called when MainUi() emits the
signal hit(), which means that the player has hit a mole and the score must be updated. The
second is called when MainUi() emits userLeave() signal, which means that the player leaves
the game.
When the game is finished the following screen is shown:
7.2.5 Graphics view widget The file “mainui.cpp” contains the class MainUi, which is responsible to create, set up and
manage an instance of GraphWidget class. This class inherits from QGraphicsView, providing a
way to display the contents of a QGraphicsScene. The content may be a QGraphicsItem item,
or an item which inherits from it, in our case a QGraphicsPixmapItem.
A screenshot of the game QGraphicsView with the QGraphicsPixmapItem representing the
mole is shown below:
Maemo for Mobile Developers
At the constructor of GraphWidget a QGraphicsScene object is created with a QRect as
parameter. The QGraphicsScene is created with the device desktop size, so we need to create a
QDesktopWidget:
QDesktopWidget* desktopWidget = QApplication::desktop();
QRect rect = desktopWidget‐>availableGeometry();
Then, we create a scene and set it to GraphWidget:
scene = new QGraphicsScene( QRect( QPoint(0, 0), rect.size() ) );
setScene( scene );
We also create a text and add it to the scene to serve as score display:
text = new QGraphicsTextItem(QString("0"));
text‐>setPos(scene‐>width() ‐ 60, scene‐>height() ‐ 80);
scene‐>addItem(text);
Let’s take a look at the moleAdded() method:
void GraphWidget::addMole(int position, int duration)
{
QPoint point = positioner‐>getPosition(this‐>width(), this‐>height(), position);
Mole *mole = new Mole(point, duration, scene);
QObject::connect(mole, SIGNAL(animationStopped(Mole*)), this,
SLOT(removeMole(Mole*)));
QObject::connect(mole, SIGNAL(animationClicked(Mole*)), this, SLOT(hit(Mole*)));
QGraphicsItem* graphic = mole‐>getGraphicItem();
scene‐>addItem(graphic);
}
This method creates a mole and adds it to scene. The Mole class receives a random position
where it will be placed on the scene and the duration it will be displayed. Two Mole signals are
used here: animationStopped() and animationClicked(). The first signal is emitted when the
Maemo for Mobile Developers
duration of a mole on the screen ends, so it is connected to GraphWidget removeMole() slot,
which removes the mole item from scene:
void GraphWidget::removeMole(Mole* mole)
{
scene‐>removeItem(mole‐>getGraphicItem());
}
The signal animationClicked() is emitted when the player hits a mole, so GraphWidget hit() slot
is called. This slot is shown below:
void GraphWidget::hit(Mole* mole)
{
scene‐>removeItem(mole‐>getGraphicItem());
emit animationClicked();
}
It only removes the hit mole from scene and emits the signal animationClicked(). At MainUI
class, this signal is connected to the signal hit().
QObject::connect(graphWidget, SIGNAL(animationClicked()), this, SIGNAL(hit()));
The signal hit is connected to GameController updateScore() slot, so it will increment the score
value:
QObject::connect(gameUi, SIGNAL(hit()), controller, SLOT(updateScore()));
7.2.6 Mole item The “mole.cpp” file contains the class Mole. This class basically creates a PngItem
(QGraphicsPixmapItem) object and animates it. At first a PngItem object is created and its
scale is set up:
static const double INITIAL_SCALE = 0.001;
...
mole = new PngItem();
mole‐>scale(INITIAL_SCALE, INITIAL_SCALE);
Now a QtimeLine is created with mole duration set in GameController:
duration = (duration >= 25) ? duration : 1000;
timer = new QTimeLine(duration, this);
A QgraphicsItemAnimation is used to make item animation. The method setItem() is used to
set the PngItem as item to be animated and the method setTimeLine() to set the QtimeLine as
controler of the rate of animation:
Maemo for Mobile Developers
QGraphicsItemAnimation *animation = new QGraphicsItemAnimation(this);
animation‐>setItem(mole);
animation‐>setTimeLine(timer);
The PngItem scale is changed on animation using the method setScaleAt() of
QgraphicsItemAnimation as shown below:
animation‐>setScaleAt(i / (2.0 * numSteps), angleCoefficient*(i+INITIAL_SCALE),
angleCoefficient*(i+INITIAL_SCALE));
The method setScaleAt() receives three qreal values: the animation step when the scale must
be changed, the horizontal shear factor and the vertical shear factor. The animation starts
when the timer is started:
timer‐>start();
Two slots are used in this class: stopAnimation() and setMoleClicked(). The first is connected to
QtimeLine finished() signal, so this slot will be called when the timer reaches the end. The
second slot is connected to PngItem clicked() signal, so it will be called when the PngItem is
clicked:
QObject::connect(timer, SIGNAL(finished()), this, SLOT(stopAnimation()));
QObject::connect(mole, SIGNAL(clicked()), this, SLOT(setMoleClicked()));
The slot stopAnimation() only emits the signal animationStopped():
void Mole::stopAnimation()
{
emit animationStopped(this);
}
The slot setMoleClicked()only emits the signal setMoleClicked():
void Mole::setMoleClicked()
{
emit animationClicked(this);
}
The signals animationStopped() and setMoleClicked() are connected to GraphWidget
removeMole() and hit() slots respectively.
7.3 Links Whac‐a‐mole description: http://en.wikipedia.org/wiki/Whac‐A‐Mole
QGraphicsView API: http://doc.trolltech.com/4.5/qgraphicsview.html
Maemo for Mobile Developers
8 Capturing key events When a widget has the keyboard input focus, key events are sent to it when keys are
pressed or released. Sometimes the developer wants to use events from keyboard to perform
custom action, such as control in games. It can be done by reimplementing the virtual
protected method QWidget::keyPressEvent in a class which inherits from QWidget.
8.1 Example The example shown here contains a button in which the central text chages when the
user types some text using keyboard. When the button is pressed, the actuan button text is
shown in a warning message box. The complete example can be achieved at
http://wiki.forum.nokia.com/index.php/Qt_Key_Event_test_example.
This example consists of a QMainWindow class, which inherits from QWidget, so it can
handle keyboard events. Then, the method keyPressEvent is reimplemented. This method
receves a QKeyEvent parameter so, when a key is pressed, this method is called with the
QKeyEvent, representing the key pressed, as parameter. Let’s look at the code:
#include "capturekeys.h" #include "ui_capturekeys.h" #include <QDebug> #include <QPushButton> #include <QMessageBox> CaptureKeys::CaptureKeys(QWidget *parent) : QMainWindow(parent) { buttonText = ""; centralButton = new QPushButton("Insert some text"); connect(centralButton, SIGNAL(clicked()), this, SLOT(buttonPressed())); setCentralWidget(centralButton); } CaptureKeys::~CaptureKeys() { } void CaptureKeys::keyPressEvent( QKeyEvent * event){ buttonText += event->text(); centralButton->setText(buttonText); } void CaptureKeys::buttonPressed(){ QString msg(centralButton->text()); QMessageBox::warning(this, QLatin1String("button pressed"), msg, QMessageBox::Ok, QMessageBox::Ok); }
At first, we have created a big button with the text “Insert some text” and connected it to
slot buttonPressed . Below is shown the screenshot of the application start screen:
Maemo for Mobile Developers
The reimplementation of the method keyPressEvent() only change the value of the button
text to text typed by the user. Look at the screenshot of the application when the user has
typed “ok”:
If the user presses the button, a warning message is shown with the typed text:
Chapter 6 Additional Maemo tools In this section are presented some useful tools to help the development to the Maemo platform. Many of these tools are available in the official Maemo tools repository
Maemo for Mobile Developers
(http://repository.maemo.org/). Some of them may have already been available unofficially, but these versions are tested for functionality.
These tools can be split in the following subsections:
Miscellaneous;
Networking;
Wireless tools;
Test automation tools. To use these tools the lines below must be added in the /etc/apt/sources.list in the scratchbox target or in real device.
# Fremantle tools
deb http://repository.maemo.org fremantle/tools free non-free
# Fremantle extras-devel
deb http://repository.maemo.org/extras/ fremantle free non-free
1 Miscellaneous
1.1 Screenshottool Screenshot‐tool is a command line utility used to capture screenshots of the tablet screen. This tool takes a screenshot of the current screen and saves the image as a PNG file. To install it use the following command:
# apt-get install screenshot-tool
The use of this feature is simple as:
$ screenshot-tool screen.png
Additionally, this feature allows to take delayed screenshots, with the command:
$ screenshot-tool -d 5 screen.png
taking screenshot in 3 seconds...
taking screenshot in 2 seconds...
taking screenshot in 1 second...
Where the “‐d” option specifies the delay in seconds before taking the screenshot. There is
also the “‐q” option for quiet mode.
1.2 HomeIP HomeIP is a small widget which displays the current IP address of the internet tablet on the desktop area. To install it use the following command:
# apt‐get install homeip
Maemo for Mobile Developers
1.3 Dpkg and Apt Maemo platform, as any Debian distribution, packages software into Debian packages. It is
possible to manage packages (install, remove and configure) and obtain information about
them with tools provided by Debian Package Management System: dpkg and apt (Advantage
Packaging Tool).
Dpkg contains a set of tools which install, remove, and provide information about Debian
packages. To install a Debian package, execute the following command:
$ dpkg –I <debian_package>.deb
To remove the Debian package, execute the following command:
$ dpkg –r <debian_package>.deb
In addition, it possible to get information about Debian packages installed on the system. In
order to get the list of installed packages, the following command can be used:
$ dpkg –l
Dpkg also provides information about a certain package. For example, to information about a
package (dependencies, description, size and version):
$ dpkg --status <debian_package>
Dpkg is very useful, but it a low level tool. To help package management, Apt can be used to
fetch packages from remote repositories and compute complex package relations. Apt also
retrieve information about packages, such as description, version, size and dependencies. It is
important to configure remote repository, so Apt can work properly.
Maemo for Mobile Developers
During package installation, Apt checks if package exists on any of configured repositories and
it computes dependencies as well. To install a package, use the following command:
# apt-get install <debian_package>
To remove a package, execute the following command:
# apt-get remove <debian_package>
You can get information about any package:
# apt-cache showpkg <debian_package>
For more information, see Dpkg or Apt man pages.
2 Networking This category presents tools to retrieve and analyze network information, like routing, name resolution, IP address check and network package tracking.
2.1 Iputils Once your application is properly tested on Scratchbox environment, it is important to test it on Internet Tablet. Generally, the device is on a TCP/IP wireless network and problems, such as network downtime, may happen. Thus, utility tools that help to inspect connection problems on a TCP/IP network are very useful to developers.
Iputis is a small collection of utilities to monitor/check TCP/IP related issues. The components of this collection are: ping, to test network functionality; arping, to send ARP requests to a host; and tracepath, to trace a path to a host discovering MTU (Maximum Transmission Unit) along the way.
To install them on the device use the following command:
#apt-get install iputils-arping iputils-tracepath iputils-ping
The usage of these tools is simple as:
$ ping nokia.com
PING nokia.com (147.243.3.83): 56 data bytes
64 bytes from 147.243.3.83: seq=0 ttl=226 time=409.8 ms
64 bytes from 147.243.3.83: seq=1 ttl=227 time=427.0 ms
64 bytes from 147.243.3.83: seq=2 ttl=227 time=437.4 ms
--- nokia.com ping statistics ---
4 packets transmitted, 3 packets received, 25% packet loss
round-trip min/avg/max = 409.8/424.7/437.4 ms
Maemo for Mobile Developers
The time shown in this case (409.8 ms), is the round‐trip time of an IP package sent to the remote host. It uses the protocol ICMP (Internet Control Message Protocol) to test the connectivity of a link.
$ arping -c 4 host.name.net -I wlan0
ARPING 4.79.81.157 from 192.168.1.163 wlan0
Sent 4 probes (4 broadcast(s))
Received 0 response(s)
This command sends ARP (Address Resolution Protocol) requests to the specified host (in the same local network) through the wireless interface (wlan0) to calculate the round‐trip time of sent packages.
$ tracepath www.maemo.org
1: 192.168.1.163 (192.168.1.163) 2.869ms pmtu 1500
1: 192.168.1.1 (192.168.1.1) 60.944ms
2: 192.168.254.254 (192.168.254.254) 9.796ms
3: 192.168.254.254 (192.168.254.254) asymm 2 7.873ms pmtu 1492
4: gigabitethernet13-0.91-vpt-pb-rotd-02.telemar.net.br (200.164.197.145) 65.613ms
5: pos10-2-bvg-pe-rotd-02.telemar.net.br (200.164.196.42) asymm 7 200.775ms
6: pos6-0-cen-ce-rotn-01.telemar.net.br (200.223.131.58) asymm 7 91.980ms
7: 200223045158.host.telemar.net.br (200.223.45.158) asymm 8 308.686ms
8: 194.25.208.61 (194.25.208.61) asymm 16 307.343ms
9: 194.25.6.201 (194.25.6.201) asymm 14 394.287ms
10: no reply
11: so-0-2-0.XT1.HEL2.ALTER.NET (146.188.5.206) asymm 16 589.966ms
12: POS1-0.GW3.HEL2.ALTER.NET (146.188.12.105) asymm 17 510.498ms
13: 62.176.60.162 (62.176.60.162) asymm 15 512.207ms
Maemo for Mobile Developers
This command tries to calculate a network path to the remote host across the Internet.
2.2 Netcat On certain scenarios, the developer needs to test if the internet tablet is receiving data over
TCP or UDP networks in a specific port. For example, consider that the developer is creating a
chat program that uses port 5060 to receive data. Thus, it is necessary to know if such port is
not blocked by any firewall and if it is possible to receive data over TCP properly. Netcat tool
can be used on such problem.
Netcat is a simple utility used to read and write data across network connections, using TCP or UDP protocols. The name of the command line executable is nc.
To install it on the device use the following command:
# apt-get install netcat
The usage of this feature is as simple as:
# nc -l -p 5060
This command opens a TCP port. The option ‐l stands for listen and the option ‐p allows specifying the port number. Then, a listening socket will be created on port 5060. When someone connects to this port and send data to it, the data will be printed on the console.
After run the command above, you can test if the internet tablet is receiving data in the port specified using the following Python program:
import socket
HOST = '192.168.1.163'
PORT = 5060
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('netcat test')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
This program just connects to the IP address assigned to HOST and to the port assigned to
PORT. In this case, we have assigned the IP address and the port of the internet tablet which is
running the Netcat command.
If you run the program above, you will see this output on internet tablet:
# nc -l -p 5060
Maemo for Mobile Developers
netcat test
It is also possible to use Netcat to connect to a host and send data to it by running the following command: # nc host port
In this case, the host can be the IP address of one computer which are running the following Python program. The port can be the value assigned to the PORT variable in the program
import socket
HOST = "192.168.1.52"
PORT = 5060
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
data = conn.recv(1024)
print data
conn.close()
This program creates a socket server over TCP and listens for a connection.
For effective example test, first run the Python program described above (using the local machine IP address for HOST) and after run the command (using the correct IP address):
# nc 192.168.1.52 5060
ok
The output of the python program will be:
Connected by ('192.168.1.163', 51723)
ok
The Netcat tool allows connecting to or waiting for UDP connections by using the ‐u option.
Others options can be used (like ‐t for enable telnet negotiation) on Netcat and you can get
details about it in the Netcat manual page
(http://maemo.org/development/documentation/man_pages/nc/).
Maemo for Mobile Developers
2.3 Tcpdump On some cases, Netcat tool is not enough. For example, the developer needs to monitor all
packets received from some computer on the network (and not only the data send for it). In
such case, you can use Tcpdump.
Tcpdump is a utility to capture and monitor data from the network. This tool can filter network data traffic using boolean expressions. A description for each captured packet could be printed on the screen. For a better analysis, it is preferred to save the captured data in a file for later analysis.
To install it on the device use the following command:
#apt-get install tcpdump
As an example, the following command can be used to catch packages from a specific domain:
$ tcpdump -w capture.cap src host.domain.net
In this case, all data that comes from the host host.domain.net to the target device is captured and saved in the file capture.cap.
$ tcpdump -X udp and dst host.domain.net
In this second example, the content of UDP packets going to host.domain.net are displayed on the screen in hexadecimal representation.
2.4 Traceroute Traceroute is a utility that prints the route packets to a network host. It displays each network hop and the time taken to reach it.
To install them on the device use the following command:
# apt-get install traceroute
To use this tool, run the command:
$ traceroute www.maemo.org
traceroute to maemo.org (62.61.69.114), 30 hops max, 40 byte packets
1 192.168.1.1 (192.168.1.1) 3.052 ms 4.272 ms 3.387 ms
2 192.168.254.254 (192.168.254.254) 3.937 ms 4.273 ms 5.250 ms
3 200.217.72.216 (200.217.72.216) 316.925 ms 404.786 ms 311.005 ms
4 gigabitethernet13-0.91-vpt-pb-rotd-02.telemar.net.br (200.164.197.145) 305.969 ms 303.589 ms 407.409 ms
5 pos10-2-bvg-pe-rotd-02.telemar.net.br (200.164.196.42) 309.479 ms 405.487 ms 409.851 ms
Maemo for Mobile Developers
6 pos6-0-cen-ce-rotn-01.telemar.net.br (200.223.131.58) 405.182 ms 200223045201.host.telemar.net.br (200.223.45.201) 307.953 ms 309.479 ms
7 200.223.254.81 (200.223.254.81) 402.740 ms 200223045158.host.telemar.net.br (200.223.45.158) 421.265 ms 200.223.254.81 (200.223.254.81) 395.385 ms
8 194.25.208.61 (194.25.208.61) 506.592 ms 508.667 ms
2.5 Nslookup Nslookup is a utility to query Internet name servers interactively. There is a command to translate a name to an IP address. With this command is possible to identify problems in the name resolution process.
This command comes to Maemo through busybox binary. As an example, use the following command:
$ nslookup www.maemo.org
Server: 127.0.0.1
Address 1: 127.0.0.1 Nokia-N800-43-7
Name: www.maemo.org
Address 1: 62.61.69.114
This command shows the IP address of the specified host. The ping command described above could also be used to retrieve an IP address from the internet name.
2.6 Wget Wget is a utility to download files from the web through the command line. With wget is possible to retrieve files using the protocols HTTP, HTTPS and FTP.
To install it on the device use the following command:
# apt-get install wget
Use this tool like in the example:
$wget http://www.host.net/file.txt
3 Wireless tools In this category are present tools used to manage wireless connections using Bluetooth and Wi‐Fi technologies.
3.1 Bluetooth tools Bluez‐hcidump allows the capture of raw data in the Bluetooth HCI (Host controller interface) layer in a human readable way.
To install on the device use the following command:
Maemo for Mobile Developers
# apt-get install bluez-hcidump
To use bluez‐hcidump, run this command:
$ hcidump -V -x
This command enables the decoding of Bluetooth packets interactively and display the content in a hexadecimal form.
3.2 Wirelesstools Wireless‐tools is a package containing a lot of utilities to manage Wi‐Fi connections. With it, it is possible to manipulate wireless LAN specific parameters like wireless SSID and grab statistics about connections. The applications provided by these tools are:
ifrename: allow user to change network interfaces names;
iwconfig: used to configure parameters of the wireless interface, analogous to ifconfig command;
iwevent: display wireless events generated by drivers and settings changes;
iwgetid: used to get information about the current wireless network, like the Id of the network, the access point MAC address, the channel number, the frequency, the connected mode and the protocol info. This information is also reported by iwconfig command, but iwgetid is more friendly to be used in scripts;
iwlist: display additional information from a wireless network interface, and can be used to scan network in the coverage area. The information that can be grabbed by this command are frequency, rate, keys, power, txpower, retry, event, auth, wpakeys, genie and modulation;
iwpriv: allow the configuration of private parameters of a wireless network. These parameters should be indicated in the documentation of each driver;
iwspy: used to grab statistics from specific wireless nodes. This feature isn’t supported currently with the native wireless interface.
To install them on the device use the following command:
#apt-get install wireless-tools ifrename
Usage examples of these tools are shown below:
$ ifrename -p -i wlan0 -n eth1
This command renames the wlan0 interface to eth1 interface. It only works when the interface is not in use.
$ iwconfig wlan0 essid MaemoNet key 123456789A mode Ad-Hoc channel 7
To create an Ad‐Hoc network with ESSID MaemoNet using WEP security and listening on channel 7.
$ iwevent
23:02:54.392303 wlan0 Scan request completed
To listen events that happens in the wireless network card.
Maemo for Mobile Developers
$ iwgetid -r -a
To get the MAC address of the connected access point.
$ iwlist wlan0 scanning
To scan the wireless network reachable by internet tablet device.
$ iwpriv wlan0
To list the available IO controls calls for the wireless interface.
4 Test automation In this category, a set of tools used to automate test execution for Maemo based systems are described. With these tools, it is possible to perform stress tests, simulate user interaction and measure how long times it takes between an action and the execution.
4.1 Sptests This tool makes it possible to generate extra demand for system and see how the application deal with situations of high system loads in terms of CPU, memory and I/O requests. This package consists of the following utilities:
cpuload: used to generate CPU load;
ioload: used to generate I/O load;
memload: used to generating memory load.
To install them on the device, use the following command:
# apt-get install sp-stress
As a first example, execute the following command to start CPU stress tests:
$ cpuload 25
The above command generates an extra CPU load of 25 percent. Now, the following example creates a file on memory card used to generate I/O extra load:
$ dd if=/dev/zero of=/media/mmc1/workfile count=1024 bs=1024
$ ioload /media/mmc1/workfile
The internal memory of Internet Tablet should not be used because its file‐system (JFFS2) is not appropriated for this kind of operation. Then, ioload is used to start I/O stress tests. The content of the file created is destroyed at the end of tests. Finally, memload is used to generate stress tests on memory:
$ memload 25
The command above creates a process that consumes 25 megabytes of memory.
Maemo for Mobile Developers
4.2 Xnee This tool is used to automate user interaction under X server. Xnee make it possible to record, replay and redistribute user actions (X events) under the X11 environment. This package contains the following utilities:
cnee: a command line utility;
gnee: a graphical user interface for cnee.
To install Xnee on Internet Tablet, use the following command:
# apt-get install xnee
As your first example, execute the following command:
$ cnee --record --mouse --events-to-record 100 -o input_events_rec.xnl
The command above records the first 100 input events. Then, use the following command replays the commands recorded in the file input_events_rec.xnl.
$ cnee --replay --file input_events_rec.xnl
4.3 Xresponse With Xresponse, it is possible to monitor screen updates. It is also possible to measure the time used to update the screen after user interactions. The screen update areas are output in the “X geometry” format (width x height + X position + Y position). It can also simulate stylus taps.
To install it on the device, use the following command:
# apt-get install xresponse
As your first example, execute the following command:
$ xresponse -w 0 -i
This command start to listen the screen changes for ever (or until a control‐C press), ‐w 0 option, and display the area changed in the occurrence of an update screen event.
A detailed analysis of screen changes can be done with the Xresponse‐visualize scripts. This set of scripts allows the generation of animations from xresponse logs.
5 Resource usage
5.1 Htop Htop is a text‐only, interactive process viewer similar to 'top'.
The process list is scrollable;
Control screen items with the stylus in addition to the keyboard;
The information on screen is configurable;
Strace can be attached to a process with a single keypress.
Maemo for Mobile Developers
To install Htop connect with device using ssh and run the following command:
$ apt-get install htop
Now, you can run Htop with the command as follows:
$htop
Htop generates the following output:
5.2 Spmemusage Maemo programming environment also provides tools to monitor memory usage. sp‐
memusage consists of utility scripts and tools that monitor memory usage of your system.
With sp‐memusage, it is possible to check how the memory is being used by a certain process,
for example. It provides the following tools and scripts:
mem‐smaps‐private: shows information about private memory usage of a process;
run‐with‐mallinfo: executes a Maemo application under mallinfo, a function that
provides data regarding to space usage;
run‐with‐memusage: executes a Maemo application under memusage, a Glib function
that provides data regarding to memory usage;
mem‐dirty‐code‐pages: shows information about dirty code pages allocated by the
processes;
mem‐monitor: monitors system memory usage during a certain interval and prints
information about it;
mem‐monitor‐smaps: monitors memory usage of some specified processes during an
interval and prints information about it.
To install sp‐memusage on your develop environment, open an SSH section with device and
execute the following command:
Maemo for Mobile Developers
#apt-get install sp-memusage
mem‐dirty‐code‐pages helps to check how many dirty code pages the processes are using. It
summarizes how many KBs of shared or private dirty code pages the processes are using. If the
processes are using a lot of dirty code pages, it means that they are not properly compiled with
option –fPIC. The usage of mem‐dirty‐code‐pages is very simple:
$mem-dirty-code-pages PID1 [ PID2 ... ]
Consider PIDs as processes identification numbers. The output will look like this:
Applications with private/shared dirty code pages:
Shared dirty code summed from all processes = 0 kB
Private dirty code pages total = 0 kB
mem‐monitor is very useful, because it monitors system memory usage during a certain
interval. This tool collects information from /proc/meminfo at given intervals. If you do not
specify time interval, it use 3 seconds as default. On the following example, mem‐monitor
provides information about system memory usage during 5 seconds:
$mem-monitor 5
It generates the following ouput:
time: total: avail: used: use-%: status:
12:59:06 126796 73084 53712 42
12:59:11 126796 73080 53716 42
12:59:16 126796 73080 53716 42
mem‐monitor‐smaps provides information about memory usage of the specified processes
during a given time interval. As mem‐monitor, mem‐monitor‐maps also collects information
from /proc/meminfo system file. It can be used with the options ‐i (to determine the interval
between memory usage information updates) and –p (to determine the PID of the process
which the tool has to monitor). On the following example, mem‐monitor‐smaps monitors
process with PID 1272 and the memory usage information have to be updated every 4
seconds:
$mem-monitor-smaps -i 4 -p 1272
The command described above outputs the following result:
List available system memory and given process memory usage
for /usr/bin/mediaplayer-engine[1272] according to SMAPS.
(without swap as SMAPS doesn't report swap correctly)
Maemo for Mobile Developers
system process private /------ dirty ---------\
time: avail: size: rss: clean: shared: private: change:
10:05:16 72908 16640 3780 60 0 572 +0 kB
10:05:20 72888 16640 3780 60 0 572 +0 kB
10:05:24 72888 16640 3780 60 0 572 +0 kB
10:05:29 72888 16640 3780 60 0 572 +0 kB
mem‐smaps‐private monitors private memory usage of a given process. This information is
collected from /proc/PID/smaps system file. The usage of mem‐smaps‐private is very simple:
$mem-smaps-private PID
Consider PID as the identification number of the process the mem‐smaps‐private has to
monitor. It generates the following output:
PID 1272: mediaplayer-engine
- Dirty shared memory: 0 kB
- Dirty private memory: 572 kB
- Clean private memory: 60 kB
run‐with‐memusage runs a given application under memusage, a wrapper library provided by
GLib. It collects information about application memory usage during its execution and
generates a report with the summary of memory management. The sintax of run‐with‐
memusage command is as follows:
$run-with-memusage <binary> [args]
Consider binary as the application to be monitor and args as arguments of the specified binary.
It outputs the following result:
Maemo for Mobile Developers
run‐with‐mallinfo runs a given application under mallinfo wrapper library and reports space
usage based on several memory information, such as number of ordinary blocks, number of
small blocks, space in free ordinary blocks, and much more. The result is saved on
$HOME/mallinfo‐PID.trace file. The usage of run‐with‐mallinfo script is very simple:
$run-with-mallinfo <binary> [args]
Consider binary as the application to be monitor and args as arguments of the specified binary.
However, it is necessary to set MALLINFO environment variable before using run‐with‐
mallinfo:
$export MALLINFO=yes
For a certain example, run‐with‐mallinfo generates the following output:
Using LD_PRELOAD for loading mallinfo to ./qtmaemo
To enable tracing you have to set MALLINFO variable:
export MALLINFO=yes -- use 5 seconds timeout and SIGALRM
export MALLINFO=signal=10 -- use SIGUSR1 to generate the report
export MALLINFO=period=10 -- periodic report for 10 seconds
mallinfo version 0.2.0 build Sep 17 2008 17:21:49 (c) 2005 Nokia
Maemo for Mobile Developers
detected variable MALLINFO with value 'yes'
signal 14 (Alarm clock) is used for reporting
report will be created every 5 seconds
report file /home/user/mallinfo-1558.trace
Hello World
Closing application...
mallinfo finalization completed
In this case, the result is saved on file /home/user/mallinfo‐1558.trace:
time,arena,ordblks,smblks,hblks,hblkhd,usmblks,fsmblks,uordblks,fordblks,keepcost,total,sbrk
0,135168,1,0,0,0,0,0,440,134728,134728,135168,0x00034000
5,1200128,33,3,3,208896,0,136,1147792,52336,49160,1409024,0x00138000
8,1200128,217,709,0,0,0,26960,1009584,190544,45328,1200128,0x00138000
The following output provides information about: time interval (time), total space in arena
(arena), number of ordinary blocks (ordblks), number of small blocks (smblks), space in
holding block headers (hblks), number of holding blocks (hblkhd), space in small blocks in
use (usmblks), space in free small (fsmblks), space in ordinary blocks in use (uordblks),
space in free ordinary blocks (fordblks), space penalty if keep option is used (keepcost)
and result of sbrk tool (sbrk).
5.3 Spsmapsmeasure sp‐smaps‐measure installs an utility that can be invoked to take a snapshot of
/proc/PID/smaps files. The smaps files contain very detailed information about processes
memory consumption.
To install sp‐smaps‐measure, just run the command:
#apt-get install sp-smaps-measure
To put it to work, run the command:
$sp_smaps_snapshot
It will print several information about processes memory usage on the screen. To avoid it, is
also possible to send the information to a file using this command:
$sp_smaps_snapshot > file.cap
The “.cap” extension file can be analyzed by the sp‐smaps‐visualize tool.
Maemo for Mobile Developers
5.4 Spsmapsvisualize sp‐smaps‐visualize provides utilities to analyze smaps data captured by sp‐smaps‐measure. To
install it run the command:
#apt-get install sp-smaps-visualize
Now you be able to run the command:
$sp-smaps-visualize file.cap
Where file “.cap” is the file containing information generated by sp_smaps_snapshot tool.
After run, an html will be generated containing information in an easy to view format.
5.5 Xrestop Xrestop shows how much X resources from the X server are being used by the X clients. It is
similar to top and htop.
To install Xrestop, run the following command:
#apt-get install xrestop
As your first example, you can run xrestop using the command:
$xrestop
Then, the xrestop application appears as shown on the following image:
Maemo for Mobile Developers
Chapter 7 Debugging and Profiling
1 Debugging Even if you are worried about bugs on your code and develop Maemo applications considering
good programming practices, it is not possible to assure that your application is bug‐free. Thus,
it is important to find in which part the application has problems and correct them.
Debugging is known as the technique that helps to find errors in a code with purpose to
correct them. This section is targeted to show some of the Maemo debugging tools that help
developers to find errors easily.
In this section, we will get into details of the following debugging tools:
Maemo‐debug‐scripts
Gdb
Sp‐error‐visualizer
Sp‐rich‐core
Syslog
These tools can be installed in the device by activating the tools repository in the Application
manager. There are different repositories for Diablo and Fremantle releases. Developers can
install them to the device and in Scratchbox using the command line interface. In this tutorial,
Fremantle is being used as main platform.
To activate the tools repository with the Application Manager, create a new catalogue like this:
1. Start the Application Manager
2. From its menu bar select Tools and then Application catalogue...
3. Press the “New” button
4. Enter the following:
Catalogue name:fremantle tools
Web address:http://repository.maemo.org
Distribution:fremantle/tools
Components:free non‐free
Disabled:leave unchecked
5. Click OK
If you prefer to edit configuration files yourself instead of using the Application Manager, add
these lines to /etc/apt/sources.list:
For Diablo:
# diablo tools
Maemo for Mobile Developers
deb http://repository.maemo.org diablo/tools free non‐free # diablo tools sources deb‐src http://repository.maemo.org diablo/tools free non‐free
For Fremantle:
# Fremantle tools
deb http://repository.maemo.org fremantle/tools free non‐free
# Fremantle tools sources
deb‐src http://repository.maemo.org fremantle/tools free non‐free
Note: To have these tools visible in the Application Manager, you need to have the Red Pill
Mode (http://maemo.org/community/wiki/ApplicationManagerRedPillMode/) activated.
To install a binary package in Scratchbox:
$ fakeroot apt‐get install <package_name>
To install a binary package into device:
$ sudo gainroot
$ apt‐get install <package_name>
1.1 General tools
1.1.1 Maemodebugscripts maemo‐debug‐scripts is a convenience package for Maemo developers needing to debug their
programs. To install maemo‐debug‐scripts use the following command:
$ apt‐get install maemo‐debug‐scripts
This command will install a few helper scripts:
native‐gdb
o runs the target native GDB (by default Scratchbox runs the host binary if it
exists, this script overrides that)
debug‐dep‐install
o installs debug symbols for given binaries and their dependencies listed by
"ldd"
debug‐pkg‐check
o checks the correctness of a debug package for a given package
list‐mmapped‐libs
o lists all packages containing libs and binaries that given process uses. It can be
used to find out the libraries mmapped through dlopen that "ldd" (used by
debug‐deb‐install script) doesn't find
run‐with‐valgrind
Maemo for Mobile Developers
o helper script for running a binary with Valgrind memcheck plugin (memory
access errors, leaks etc) so that all suitable options are set for it
run‐with‐callgrind
o helper script for running a binary with Valgrind callgrind plugin (performance
profiling) so that all suitable options are set for it
run‐with‐massif
o helper script for running a binary with Valgrind massif plugin (memory usage
visualization) so that all suitable options are set for it
run‐with‐helgrind
o helper script for running a binary with Valgrind helgrind plugin (race condition
detector for threaded programs) so that all suitable options are set
run‐with‐strace
o helper script for running a binary with strace. Like above helper scripts,
handles Maemo‐launched binaries automatically
Following, we will show some of these scripts in details.
1.1.2 nativegdb By default Scratchbox uses its own host tools instead of the target ones, if such are installed.
This (trivial) script overrides that setting for /usr/bin/gdb. To use it, run the command:
$native‐gdb
Because the host Gdb will use the thread_db coming with the toolchain with which has been
built with, it cannot debug threads properly. Instead of using this script, you can also remove
or rename the Scratchbox host Gdb.
1.1.3 debugdepinstall debug‐dep‐install is a helper script for installing debug symbol packages in the Maemo
GNU/Linux environment. The script checks what libraries the given binaries and libraries are
linked against, into which packages those belong to, and whether they have corresponding
debug symbols packages. Then it installs the available debug symbols packages. To use it just
run:
$ debug‐dep‐install <binaries>
Then, the debug symbol packages will be installed for the given binaries. For example, run the
debug‐dep‐install for native‐gdb binaries:
$ debug‐dep‐install /usr/bin/native‐gdb
Note: you must use the full path for the script binaries to make it work. You can use the
command “which” to find application’s full path.
The script works on both device and Scratchbox development environments.
Maemo for Mobile Developers
1.1.4 listmmappedlibs list‐mmapped‐libs is a helper script that can be used with debug‐dep‐install. Debug‐dep‐install
installs only the dependencies that the given binaries (or libraries) link directly. This script can
find out what additional libraries have been dlopened by the given process so that you can give
them also to debug‐dep‐install. To use it just run:
$list‐mmapped‐libs <PID>
Here, PID is the process identification number which you want to observe. To get the process
identification number, just run the command:
ps xau
1.2 GDB Debugging is an important method to find bugs in order to fix them. Such iterative cycle of
find‐fix bugs improves application quality, and the result is a more stable and reliable system.
Debugging is often used to find more complex bugs that cannot be detected using traditional
testing approaches (unit tests, for example). In the context of embedded systems
development, the developer generally faces strange errors that cannot be properly defined.
When developing for Maemo using Scratchbox, the host platform is different from the target
one. In general, you may face some complex bugs (a segmentation fault, for example) related
to memory or registers usage. As developers, we need a useful tool that displays a lot of
detailed data about application which is being launched and also about the platform.
GDB, the GNU Project debugger, is a helpful debugger that provides information about a
program during its execution: control over application execution (start, pause, stop), memory
map, registers, variables, source code, backtrace and much more. GDB was developed to be
used on many Unix‐like systems and it works for many programming languages, such as C, C++
and Java.
With GDB, it is possible to see what is going on inside a program while it executes, including
the moment it crashed. It is possible to check variables values to verify if the program logic is
correct, or follow the function calls to see what peace of the code is been executed for a given
feature.
GDB can be used to debug a Maemo application on different scenarios: on Scratchbox (both
ARMEL and X86 targets) and also directly on Internet Tablet. However, for each of these
environments, there are some configuration steps to be performed. This section shows how
you can use GDB to debug a Maemo application in order to improve the quality of your
software.
An advanced way to debug with GDB is running it as a client‐server application. The gdbserver
is launched on remote device and it runs application debugging section. On the desktop side,
GDB is used as a client to control the gdbserver and view the debugging results. The
communication between the machines is established using GDB protocol via serial port or
TCP/IP. More details about how to debug with gdbserver is described in this section.
Maemo for Mobile Developers
1.2.1 Installing and testing gdb As described before, you can debug a Maemo application on Scratchbox or on Internet Tablet.
On this section, we describe how to install GDB on both environments and how to check if it
was properly installed.
1.2.1.1 Preparing Scratchbox environment Both Fremantle targets (FREMANTLE_ARMEL and FREMANTLE_X86) provide a GDB executable.
However, such GDB executables are not suitable for Maemo development, because they are
not properly configured to application debugging on Maemo rootstraps. Instead, we need to
use a native executable, a non Scratchbox version of GDB, which is accessible using script
native‐gdb. At first, in order to set properly native‐gdb, it is necessary to install package
Maemo‐debug‐scripts as described on this section. As your first try, launch native‐gdb without
any parameter:
[sbox-FREMANTLE_X86: ~] > native-gdb
GNU gdb (GDB) 6.8.50.20090417-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb)
Therefore, from now one native‐gdb script is used instead of GDB for Maemo application
debugging on Scratchbox.
1.2.1.2 Preparing Internet Tablet environment You need to establish an SSH section as root with Internet Tablet to proceed.
maemo@maemo-desktop:~$ ssh [email protected]
[email protected]'s password:
In addition, GDB for Internet Tablet is available on Maemo Tools repository. Then, if Maemo
Tools repository is not properly configured on your Internet Tablet, edit file
/etc/apt/sources.list and add the following line:
deb http://repository.maemo.org/ fremantle/tools free non-free
Maemo for Mobile Developers
Once Maemo Tools repository was added as a valid repository, it is necessary to update the
packages list. Execute the following commands as root to refresh the package database and
install GDB in the device:
Nokia-N810:~# apt-get update
… snip …
Nokia-N810:~# apt-get install gdb
Now, you have GDB installed on Internet Tablet. You can start debugging maemo applications on device.
Nokia-N810:~# gdb
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabi".
(gdb)
To quit from GDB, press ‘q’ and hit ENTER key.
1.2.2 Debugging with nativegdb on Scratchbox NOTE: Qt libraries for Maemo are supposed to be installed on Scratchbox before continuing.
See Section 2.3, on Chapter chapter 2.
On this section, we present one example application that will help to understand the basic use
of native‐gdb on Scratchbox. The application defines a simple Qt widget, which inherits from
QWidget class. This widget creates a Qt push button and connects it to a slot function
(MyButton::printAndQuit). When such button is clicked, the function MyButton::printAndQuit
is invoked: a message (“Hello World...”) is printed on console and the application is finished. A
screenshot with the application is shown as follows:
Maemo for Mobile Developers
The code of first example (gdb_qt_example.cpp and gdb_qt_example.h) is as follows:
1 #ifndef GDB_QT_EXAMPLE_H 2 #define GDB_QT_EXAMPLE_H 3 4 #include <QWidget> 5 6 class MyButton : public QWidget { 7 Q_OBJECT 8 public: 9 MyButton(QWidget *parent = 0); 10 private: 11 void printMessage(); 12 void quitApplication(); 13 public slots: 14 void printAndQuit(); 15 }; 16 17 #endif 1 #include <QApplication> 2 #include <QPushButton> 3 #include <QWidget> 4 #include <QVBoxLayout> 5 #include <iostream> 6 7 void MyButton::printMessage() { 8 std::cout << "Hello World\n"; 9 std::cout << "Closing application...\n"; 10 } 11 12 void MyButton::quitApplication() {
Maemo for Mobile Developers
13 qApp->quit(); 14 } 15 16 void MyButton::printAndQuit() { 17 printMessage(); 18 quitApplication(); 19 } 20 21 MyButton::MyButton(QWidget *parent) : QWidget(parent) { 22 QPushButton *quitButton = new QPushButton("Quit"); 23 connect(quitButton, SIGNAL(clicked()), this, SLOT(printAndQuit())); 24 25 QVBoxLayout *layout = new QVBoxLayout; 26 layout->addWidget(quitButton); 27 setLayout(layout); 28 } 29 30 int main(int argc, char* argv[]) { 31 int x = 10; 32 std::cout << "Value of x: " << x; 33 QApplication app(argc,argv); 34 MyButton *button = new MyButton; 35 button->show(); 36 return app.exec(); 37 }
This application is a very simple Qt application with a push button. When the button is
pressed, the function MyButton::printAndQuit (file gdb_qt_example.cpp, line #16) is invoked:
it prints a message on console and quit from application.
Before debugging the application, it is necessary to compile it properly in order to generate an
executable with debug symbols, so we can debug it with GDB. The debugging information is
stored in object file and contains data type of each symbol (variable or function) and also the
correspondence between source line numbers and memory addresses of executable code.
If you want to request debugging information for Qt Maemo application, it is necessary to
modify the *.pro file of the project. Include the following configuration option on *.pro file:
TEMPLATE = app TARGET = DEPENDPATH += . INCLUDEPATH += . CONFIG += debug # Input HEADERS += gdb_qt_example.h SOURCES += gdb_qt_example.cpp
Now, (re)generate the project´s Makefile, and build the sources:
[sbox-FREMANTLE_X86: ~/gdbexample] > qmake
Maemo for Mobile Developers
[sbox-FREMANTLE_X86: ~/gdbexample] > make
The application is ready for debugging with GDB. Remember that we have to use the native
GDB (native‐gdb), not Scratchbox one. Finally, start native‐gdb application:
[sbox-FREMANTLE_X86: ~/gdbexample] > native-gdb gdbexample
... snip …
(gdb)
During debugging sections, we often need to follow the application control flow. In order to
pause application execution at a certain line of the source code, you need to set breakpoints.
Once your application execution is frozen at a certain point of the code, you can check the
values of variables, registers and memory. As an example, insert two breakpoints: one on
function MyButton::printAndQuit(), and another one on function MyButton::printMessage().
To do this use GDB function break:
(gdb) break MyButton::printAndQuit
Breakpoint 1 at 0x804a6d8: file gdb_qt_example.cpp, line 19.
(gdb) break MyButton::printMessage
Breakpoint 2 at 0x804a1e4: file gdb_qt_example.cpp, line 10.
You can also insert a breakpoint on a certain line of source code. For example, if you want to
insert a breakpoint on line 33, execute the following command:
(gdb) break gdb_qt_example.cpp:33
Breakpoint 2 at 0x804a400: file gdb_qt_example.cpp, line 33.
For more information about GDB breakpoints, see GDB documentation.
Once breakpoints are properly inserted, we can start debugging the application under native‐
gdb.
(gdb) run
Starting program: /home/maemo/gdbexample/gdbexample
[Thread debugging using libthread_db enabled]
QGtkStyle cannot be used together with the GTK_Qt engine.
Breakpoint 1, MyButton::printAndQuit (this=0x8061998) at gdb_qt_example.cpp:19
19 printMessage();
(gdb)
Maemo for Mobile Developers
As you can see, the application pauses on first breakpoint it found: function
MyButton::printAndQuit(). It is possible to see the source code around a certain line number.
For example, if you want to see the code around line #20, use GDB function list:
(gdb) list 19 14 void MyButton::quitApplication() { 15 qApp->quit(); 16 } 17 18 void MyButton::printAndQuit() { 19 printMessage(); 20 quitApplication(); 21 } 22 23 MyButton::MyButton(QWidget *parent) : QWidget(parent) {
To continue the debugging section until the next breakpoint, use GDB function “continue”. If
you want to continue running your program until control reaches a different source line, use
GDB function step:
(gdb) continue
Continuing.
Breakpoint 2, MyButton::printMessage (this=0x80718e8) at gdb_qt_example.cpp:10
10 std::cout << "Hello World\n";
(gdb) step
Hello World
11 std::cout << "Closing application...\n";
GDB provides a list with functions that have been called during the current debugging section
(GDB function backtrace). The list goes from recent to older. The oldest function was naturally
the main() function at the end of the list. It shows also the parameters to the called functions:
(gdb) backtrace
#0 MyButton::printMessage (this=0x8061998) at gdb_qt_example.cpp:10
#1 0x0804a685 in MyButton::printAndQuit (this=0x8061998) at gdb_qt_example.cpp:19
#2 0x0804a8d2 in MyButton::qt_metacall (this=0x8061998, _c=QMetaObject::InvokeMetaMethod, _id=0, _a=0xbfffd2f8) at moc_gdb_qt_example.cpp:66
Maemo for Mobile Developers
#3 0xb73f320e in QMetaObject::activate(QObject*, int, int, void**) () from /usr/lib/libQtCore.so.4
#4 0xb73f362e in QMetaObject::activate(QObject*, QMetaObject const*, int, int, void**) () from /usr/lib/libQtCore.so.4
#5 0xb7df4473 in QAbstractButton::clicked(bool) () from /usr/lib/libQtGui.so.4
#6 0xb7ade609 in QAbstractButtonPrivate::emitClicked() () from /usr/lib/libQtGui.so.4
…
As mentioned before, you can inspect the value of the variables. Let´s insert a breakpoint on
file gdb_qt_example.cpp line #36 to verify the values of main function variables:
(gdb) break gdb_qt_example.cpp:36 Breakpoint 3 at 0x804a43b: file gdb_qt_example.cpp, line 36. (gdb) continue Continuing. Breakpoint 3, main (argc=1, argv=0xbffff5e4) at gdb_qt_example.cpp:36 36 QApplication app(argc,argv);
Use GDB function print to inspect a variable (variable x, for example):
(gdb) print x $1 = 10
GDB has very interesting functions to display registers values (GDB function info registers),
show memory regions (GDB function display [EXP]), and much more. For more information,
see GDB documentation.
1.2.3 Debugging with gdb on device NOTE: Qt libraries for Maemo are supposed to be installed on Scratchbox before continuing.
See 2.4,"Install Qt on Scratchbox" on Chapter 2.
In this section, we will use the same example adopted in previous section to demonstrate how
to debug with GDB on Internet Tablet.
It is possible to debug an application in the Internet Tablet device itself using GDB. In order to
make the work easier, we need to establish a SSH section with device. Please, look in the
section 6.2,"Deploy application to the device" to learn how to connect with device using SSH.
Since the executable is supposed to be launched on Internet Tablet, we need to compile it to
ARMEL architecture. Thus, we need to change the Scratchbox target from FREMANTLE_X86 to
FREMANTLE_ARMEL.
Now, compile the Qt. Do not forget to modify *.pro file so debug information is properly
generated into object file:
Maemo for Mobile Developers
[sbox-FREMANTLE_ARMEL: ~/gdbexample] > qmake
[sbox-FREMANTLE_ARMEL: ~/gdbexample] > vim gdbexample.pro
[sbox-FREMANTLE_ARMEL: ~/gdbexample] > make
Copy the ARMEL version of the gdb_qt_example to the tablet using SCP:
[sbox-FREMANTLE_ARMEL: ~/gdbexample] >scp gdbexample [email protected]:/home/user
Log in on the device with SSH as user. The IP address is an example, your device IP address can
be different:
[sbox-FREMANTLE_ARMEL: ~/gdbexample] > ssh [email protected] [email protected]'s password:
Start the gdb debugger with the gdb_qt_example application:
Nokia-N810:~# gdb gdbexample GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "arm-linux-gnueabi"... (gdb)
If you try to debug the executable gdbexample on device, you will certainly face the following
problem:
(gdb) break MyButton::printAndQuit Breakpoint 1 at 0xa24c: file gdb_qt_example.cpp, line 19. (gdb) run Starting program: /home/user/gdbexample … snip… [Switching to Thread 0x40020cd0 (LWP 2423)] Breakpoint 1, MyButton::printAndQuit (this=0x115208) at gdb_qt_example.cpp:19 20 gdb_qt_example.cpp: No such file or directory. in gdb_qt_example.cpp
Since the source file is not on device, you cannot verify the corresponding source code. Then, if
you want to follow your application execution, it is necessary to copy the source code into the
same folder where the binary is located in the device.
[sbox-FREMANTLE_ARMEL: ~/gdbexample] >scp gdb_qt_example.cpp [email protected]:/home/user
Maemo for Mobile Developers
Now, it is possible to inspect the source code during the GDB debugging section on device.
Launch the application again on GDB and start debugging:
(gdb) run Starting program: /home/user/gdbexample … [Switching to Thread 0x40020cd0 (LWP 2473)] Breakpoint 1, MyButton::printAndQuit (this=0x115208) at gdb_qt_example.cpp:19 19 printMessage(); (gdb) list 19 14 void MyButton::quitApplication() { 15 qApp->quit(); 16 } 17 18 void MyButton::printAndQuit() { 19 printMessage(); 20 quitApplication(); 21 } 22 23 MyButton::MyButton(QWidget *parent) : QWidget(parent) { (gdb)
The version of GDB for Internet Tablet has the same features of the one for Scratchbox. Then,
you can check variables, registers, memory and much more. The instruction described on
section 2.1.2.3 can also be applied for GDB debugging on device.
1.2.3.1 Debugging with gdbserver on device GDB also provides an interesting feature: the remote debugging. Such feature was initially
provided to debug applications on machines that could not run GDB in usual way. At first years
of Maemo development, GDB was not available for Internet Tablet and gdbserver was the only
way to debug Maemo application on device. In addition, gdbserver does not require the
application´s source code. Then, it is not necessary to copy all source code files to Internet
Tablet in order to debug you application. This seems not a big issue, but it is really very helpful
for large application with a lot of source code files.
There are two different environments involved: gdbserver launches the application on Internet
Tablet while GDB (client) is launched on host machine. gdbserver is the one that controls
application debugging and it sends information to GDB instance on host machine. The
communication is established by serial or TCP/IP protocols, using the standard GDB remote
serial protocol.
Gdbserver belongs to GDB package. Thus, if GDB is installed on Internet Tablet, gdbserver is
installed on it as well. To start with, you need to start gdbserver on device so GDB can get
connected with remote debugging section. You need a copy of the program you want to
debug, including any libraries it requires.
On device, launch gdbserver and tell it how it can communicate with GDB, its TCP/IP host
address and port:
Maemo for Mobile Developers
Nokia-N810-43-7:~# gdbserver 192.168.2.15:2345 ./gdbexample Process ./gdbexample created; pid = 1488 Listening on port 2345 Remote debugging from host 192.168.2.15
Now, in the host machine, GDB can get connected with device and start application debugging.
On GDB, you need a copy of your application compiled with debug option, since GDB needs
symbol and debugging information. gdbserver does not need your program's symbol table,
then you can strip the program if necessary. Before starting the debug process, we need to
specify the executable on GDB in order to load symbols for your application. Use GDB file
command:
[sbox-FREMANTLE_ARMEL: ~/gdbexample] > native-gdb GNU gdb 6.4.90 Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "arm-linux-gnueabi"... (gdb) file gdbexample Reading symbols from /home/maemo/gdbexample/gdbexample...done.
Once gdbserver is up and running on Internet Tablet, use GDB command target remote to get
connected with gdbserver:
(gdb) target remote 192.168.2.15:2345 Remote debugging using 192.168.2.15:2345 [New thread 1488] 0x400007d0 in ?? ()
On GDB, you can proceed as a local debugging section, including registers and memory
inspection. For example, you can set breakpoints, proceed with execution and list source code
lines.
(gdb) break MyButton::printAndQuit Breakpoint 1 at 0xa24c: file gdb_qt_example.cpp, line 19. (gdb) continue Continuing. Breakpoint 1, MyButton::printAndQuit (this=0x113268) at gdb_qt_example.cpp:19 19 printMessage(); (gdb) list 19 14 void MyButton::quitApplication() { 15 qApp->quit(); 16 } 17 18 void MyButton::printAndQuit() {
Maemo for Mobile Developers
19 printMessage(); 20 quitApplication(); 21 } 22 23 MyButton::MyButton(QWidget *parent) : QWidget(parent) {
For more information about gdbserver, see gdbserver documentation.
1.2.4 Core dump files Internal errors may occur, which cause processes to crash. In this situation, it is somewhat
difficult to debug the application directly, considering you have no idea in which function the
application had broken. Some developers start to look for the error in the code adding print
messages all around it, execute the code, add some more messages, and follow this slow
process until to find the bug.
A common error while programming with GTK is when the application connects signals to an
object, and the object responsible for the callback is destroyed by the program. When the
signal is troughed, it does not find its callback and them a crash happens. This situation is very
difficult to find with print messages, since the developer is not expecting the program flow is
passing into the callback function.
Fortunately, there are options to generate log files (core dumps) with information capable to
retrieve the scenario when the error occurred. In general, the developer can open the
generated core dump file with GDB and inspect the system state in the exact moment it had
crashed.
There are some Maemo tools available to help developers to retrieve core dump files from the
device. These tools are available in the sp‐rich‐core package. Once installed, sp‐rich‐core will
produce a core dump file and also additional information about process, most of /proc data,
last lines from syslog, df, ifconfig output and much more. All of such information is added to a
rich core dump package (.rcore) and then, it is compressed (.lzop) in order to save disk space.
sp‐rich‐core generates the core dump files as lzop compressed files, so they have to be
uncompressed before using them on debuggers. The package sp‐rich‐core‐postproc provides
the rich‐core‐extract utility, which extracts the information from a rich core dump file so GDB
can read it. Before continue, install packages sp‐rich‐core and sp‐rich‐core‐postproc.
Nokia-N810:~# apt-get install sp-rich-core sp-rich-core-postproc
The Internet Tablet kernel does not save core dump files as default. The default options for
code dump file saving are defined in the file /mnt/initfs/linuxrc. Its content is as follows:
…
enable_coredumps() { coredir=/media/mmc1/core-dumps echo -n "Enabling core dumps to $coredir/..." echo "$coredir/%e-%s-%p.core" > /proc/sys/kernel/core_pattern ulimit -c unlimited
Maemo for Mobile Developers
echo "done." } …
The core dumps are saved by default on directory /media/mmc1/core‐dumps. These options
also define the size limit of core dump files and their names, which includes the name of the
executable (%e), the signal (%s) and the PID number (%p).
The following example shows how to generate a core dump file and how we can debug it. To
show how GDB can be used to debug an application from its core dump file, a modified version
of gdbexample application is used (gdb_qt_buggy_example.cpp and
gdb_qt_buggy_example.h). The only changes remain on function crashApplication(): it is
invoked before printing messages on console and it tries to assign a value to a uninitialized
pointer (ptr). Such operation is invalid and it throws a segmentation fault exception. The
modified code is as follows:
01 #include <QWidget> 02 #include <QVBoxLayout> 03 #include <iostream> 04 05 #include "gdb_qt_example.h" 06 07 void MyButton::crashApplication() { 08 char *ptr = 0; 09 memcpy(ptr, 0x00, sizeof(ptr)); 10 } 11 12 void MyButton::printMessage() { 13 std::cout << "Hello World\n"; 14 std::cout << "Closing application...\n"; 15 crashApplication(); 16 } 17 18 void MyButton::quitApplication() { 19 qApp->quit(); 20 } …snip…
Now, compile application gdbbuggyexample on FREMANTLE_ARMEL rootstrap and copy it to
device. Do not forget to edit file *.pro to add debug option:
[sbox-FREMANTLE_ARMEL: ~] > make
… snip …
[sbox-FREMANTLE_ARMEL: ~] >scp gdbbuggyexample [email protected]:/home/user
Run the gdbexample application in the device:
Nokia-N810:~#./gdbbuggyexample
Maemo for Mobile Developers
The gdbbuggyexample is now running in the background and the application is shown on
Internet Tablet screen. The application crashes when the button “Quit” is pressed: method
MyButton::crashApplication is invoked inside method MyButton::printMessage.:
Nokia-N810:~# ./gdbbuggyexample Value of x: 10 Hello World Closing application... Segmentation fault (core dumped)
The core dump file with information about gdbbuggyexample application is saved under
/media/mmc1/core‐dumps. As configured on /mnt/initfs/linuxrc file, its name includes the
name of the file and the PID number of the gdbbuggyexample program at the end. You can see
the compressed core dump file (.lzo) saved under /media/mmc1/core‐dumps:
Nokia-N810:~# cd /media/mmc1/core-dumps
Nokia-N810:/media/mmc1/core-dumps# ls -l gdbbuggyexample-11-2478.rcore.lzo
-rw-r--r-- 1 user root 665.9k Jul 21 12:07 gdbbuggyexample-11-2478.rcore.lzo
The core dump file is now properly generated, but it is still compressed. GDB cannot read the
core dump file in such format, so it is needed to uncompress it with rich‐core‐extract
application.
Nokia-N810:/media/mmc1/core-dumps# rich-core-extract \ gdbbuggyexample-11-2478.rcore.lzo coredir
Nokia-N810:/media/mmc1/core-dumps# ls -l coredir/
drwxr-xr-x 2 user root 0 Jul 21 12:35 .
drwxr-xr-x 3 user root 0 Jul 21 12:35 ..
-rw-r--r-- 1 user root 9 Jul 21 12:36 cmdline
-rw-r--r-- 1 user root 55 Jul 21 12:36 component_version
-rw-r--r-- 1 user root 2.7M Jul 21 12:36 coredump
-rw-r--r-- 1 user root 30 Jul 21 12:36 date
-rw-r--r-- 1 user root 521 Jul 21 12:36 df
-rw-r--r-- 1 user root 741 Jul 21 12:36 fd
-rw-r--r-- 1 user root 796 Jul 21 12:36 ifconfig
-rw-r--r-- 1 user root 1.2k Jul 21 12:36 ls_proc
-rw-r--r-- 1 user root 397 Jul 21 12:36 osso-product-info
Maemo for Mobile Developers
-rw-r--r-- 1 user root 15.2k Jul 21 12:36 packagelist
-rw-r--r-- 1 user root 28.9k Jul 21 12:36 proc2csv
-rw-r--r-- 1 user root 11.9k Jul 21 12:36 slabinfo
-rw-r--r-- 1 user root 44.1k Jul 21 12:36 smaps
As described before, the compressed rich core dump has a lot of information about system,
including the core dump file (coredump) and files with system package list, ifconfig output,
df/fd output, the command line used to launch the application and much more. In addition,
such compressed format saves disk space and speeds up information recording.
The debug information from the example code is available in the core dump due to the “‐g”
option used to compile it (automatically added when *.pro file is modified by adding line
CONFIG += debug), however, as the application is dynamically linked against other libraries
(e.g. libc6, libqt4), if you want to be able to resolve symbols also for these library, it is needed
to install the package containing debug symbols of such library. For example, for Qt libraries,
you have to install libqt4‐dbg package in order to resolve Qt debug symbols. The debug‐dep‐
install utility described in this section provides an easy way to install the debug packages for all
libraries the application depends.
The gdbexample is linked against libc, glib and qt libraries. We need to install them to get
debug symbols for these libraries:
Nokia-N810:~# apt-get install libc6-dbg libglib2.0-0-dbg libqt4-dbg
Now, you can start to debug the application using the core dump file. You need both core
dump and gdbexample binary previously compiled with debug option (‐g). Execute the
following command in order to launch GDB (gdbexample binary as first parameter and core
dump file as the second parameter:
Nokia-N810:~# gdb ./gdbbuggyexample /media/mmc1/core-dumps/coredir/coredump
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabi"...
Reading symbols from /usr/lib/libQtGui.so.4...done.
Loaded symbols for /usr/lib/libQtGui.so.4
Reading symbols from /usr/lib/libQtCore.so.4...done.
Maemo for Mobile Developers
…
Core was generated by `./gdbbuggyexample'.
Program terminated with signal 11, Segmentation fault.
[New process 3068]
#0 0x40db99ec in memcpy () from /lib/libc.so.6 (gdb)
You need now to find out what function caused the crash. The backtrace command will show
the functions invoked during the application execution:
(gdb) backtrace
#0 0x40db99ec in memcpy () from /lib/libc.so.6
#1 0x0000a120 in MyButton::crashApplication (this=0x110ee8) at gdb_qt_example.cpp:10
#2 0x0000a2a0 in MyButton::printMessage (this=0x110ee8) at gdb_qt_example.cpp:17
#3 0x0000a2f4 in MyButton::printAndQuit (this=0x110ee8) at gdb_qt_example.cpp:25
#4 0x0000ac70 in MyButton::qt_metacall (this=0x110ee8, _c=QMetaObject::InvokeMetaMethod, _id=0, _a=0xbed59930) at moc_gdb_qt_example.cpp:66
#5 0x40bd3b2c in QMetaObject::activate () from /usr/lib/libQtCore.so.4
#6 0x408c0e28 in QAbstractButton::clicked () from /usr/lib/libQtGui.so.4
#7 0x405dcc10 in QAbstractButtonPrivate::emitClicked () from /usr/lib/libQtGui.so.4
#8 0x405dd5bc in QAbstractButtonPrivate::click () from /usr/lib/libQtGui.so.4
#9 0x405dd778 in QAbstractButton::mouseReleaseEvent () from /usr/lib/libQtGui.so.4
#10 0x4025df48 in QWidget::event () from /usr/lib/libQtGui.so.4
#11 0x405dcbd8 in QAbstractButton::event () from /usr/lib/libQtGui.so.4
#12 0x4068d778 in QPushButton::event () from /usr/lib/libQtGui.so.4
#13 0x402059e8 in QApplicationPrivate::notify_helper () from /usr/lib/libQtGui.so.4
#14 0x402072d8 in QApplication::notify () from /usr/lib/libQtGui.so.4
Maemo for Mobile Developers
#15 0x40bbddc0 in QCoreApplication::notifyInternal () from /usr/lib/libQtCore.so.4
#16 0x40206660 in QApplicationPrivate::sendMouseEvent () from /usr/lib/libQtGui.so.4
#17 0x4027f38c in QETWidget::translateMouseEvent () from /usr/lib/libQtGui.so.4
#18 0x4027dd10 in QApplication::x11ProcessEvent () from /usr/lib/libQtGui.so.4
#19 0x402a50d0 in ?? () from /usr/lib/libQtGui.so.4
#20 0x0000a634 in main (argc=1, argv=0xbe8486c4) at gdb_qt_example.cpp:37
1.2.5 Sperrorvisualizer
sp‐error‐visualizer is a small utility that's designed to help you in noticing errors that are
written to syslog.
To install it, run the command:
#apt-get install sp-error-visualizer
Just install the sp‐error‐visualizer package and it will immediately start tracking syslogged messages. It's also started automatically on bootup. If syslog is not running, it provides itself the syslog socket for the applications.
The error visualizer can be disabled by running the following command or uninstalling the package.
$ /etc/init.d/sp-error-visualizer stop
1.2.6 Syslog
The syslogd daemon is responsible for providing logging of messages received from programs and facilities on the local host as well as from remote hosts.
The klogd daemon listens to kernel message sources and is responsible for prioritizing and processing operating system messages. The klogd daemon can run as a client of syslogd or optionally as a standalone program.
To install sysklogd run the command:
#apt-get install sysklogd
To start the sysklogd daemon:
$ /etc/init.d/sysklogd start
Maemo for Mobile Developers
2 Profiling On Maemo development, it is important to assure that your application does not demand a lot
of system resources, for example memory consumption and processing. An application that
demands a considerable amount of memory, certainly impacts directly on Internet Tablet
performance as well.
Thus, it is necessary to inspect how much of system resources the application is demanding.
Profilling allows extracting information about application execution and it generates a lot of
interesting information, such as system resources and potencial bugs related to memory
management, for example.
In this section, we will get into details of the following profilling tools:
Valgrind
OProfile
Strace
Ltrace
These applications can be installed from Tools repository, as described on Section 1.
2.1 Valgrind On C/C++ development, applications commonly use memory management operations. The
developer has to handle carefully the dynamically allocated memory in order to avoid memory
leaks, invalid assign operations, cyclic references, undefined pointers operations and much
more. The Valgrind tool can be used to debug memory operations to find this kind of
problems.
Valgrind is a suite of debugging and profiling tools for Linux applications. It has tools for
memory debugging, memory leak detection, and profiling. Originally designed to be a powerful
memory debugging tool, Valgrind has evolved and it is now a generic framework to develop
tools for debugging and profiling Linux applications.Valgrind simulates X86 processor and it
instruments binary code on the fly. Then, it directly impacts on application performance by 10‐
300 times slower than usual scenario, depending on the used Valgrind tool.
It runs on X86/Linux, AMD64/Linux, PPC32/Linux and PPC64/Linux platforms, but not on
ARM/Linux platform. Therefore, it is not possible to run Valgrind on scratchbox ARMEL target
or on Internet Tablet. Considering Maemo development environment, Valgrind can be used
only on X86 targets.
Valgrind have some tools available to help debugging. Some of them are described here:
massif: Run‐time memory usage graph and hyperlinked allocation backtraces;
memcheck: This tool detects memory access errors and memory leaks. It reports less
false positives than any other tool and can call GDB when the error happens;
cachegrind: A performance profiler which can be started and stopped at any moment
and the results can be sorted according to instructions, cache hits etc;
callgrind: AsCachegrind, but stores also callgraph information (but can show only
instruction counts);
Maemo for Mobile Developers
helgrind: This tool detects race conditions when threaded programs access global data.
To install Valgrind on Scratchbox, run de command:
[sbox-FREMANTLE_X86: ~] > apt-get install valgrind
Valgrind package install all necessary dependencies, including libc6‐dbg. Most of dependencies
are packages with symbols, so Valgrind can match suppressions to the internal library
functions.
An example of Maemo C application is used to demonstrate the basic usage of Valgrind tool.
The following example allocates two pointers, but only one is deallocated (ptra) and memory is
lost (memory leak). In addition, file descriptor fp is opened (line #23), but it is not closed. Also,
remember that file descriptor fd is also a pointer and it should be deallocated.
01 #include <stdio.h> 02 #include <malloc.h> 03 04 int main() { 05 FILE* fp; 06 char *ptra, *ptrb; 07 // First allocation: 50 bytes 08 if ((ptra= (char *) malloc(50)) == NULL) { 09 perror("malloc failed for 50 bytes."); 10 exit(-1); 11 } 12 13 // Second allocation: 100 bytes 14 if ((ptrb= (char *) malloc(100)) == NULL) { 15 perror("malloc failed for 100 bytes."); 16 exit(-1); 17 } 18 19 // 100 bytes allocated above are cleaned. 20 free(ptra); 21 22 // the following file descriptor is not closed 23 fp=fopen("/tmp/tempfile.txt","a"); 24 25 return 0; 26 }
Create a directory to save example:
[sbox-FREMANTLE_X86: ~] >mkdir valgrind_example [sbox-FREMANTLE_X86: ~] >cd valgrind_example
Compile the example:
[sbox-FREMANTLE_X86: ~/valgrind_example] >gcc–g valgrind_example.c \ -o valgrind_example
Maemo for Mobile Developers
After compiling the small example application, it can be run under Valgrind. The basic usage of
Valgrind is:
valgrind [options] prog-and-args
Run Valgrindwith some arguments and example application with the command:
[sbox-FREMANTLE_X86: ~/valgrind_example] >valgrind --tool=memcheck \ --leak-check=full --show-reachable=yes --num-callers=20 \ --track-fds=yes ./valgrind_example
Explanation of the parameters and their meanings:
‐‐tool=memcheck
o Defines which tool Valgrind should use. In this example, the memory checker
tool (memcheck) is used, but you can use one of the tools described above.
Default option is memcheck.
‐‐leak‐check=full
o Searchs for potential memory leaks at exit. Possible options are no, summary
or full. In order to see full report about memory leak, full option should be
used. Default option is summary.
‐‐show‐reachable=yes
o Shows stack trace of reachable blocks that contain memory leak errors. Default
option is no.
‐‐num‐callers=20
o Defines the number of function call levels that Valgrind displays. More the
value is increased, more memory Valgrind demands. Default value is 12.
‐‐track‐fds=yes
o Report status of file descriptors. If application opens files with fopen()oropen()
but do not close them properly, Valgrind reports the problems. Default option
is no.
Based on the following example, Valgrind is supposed to detect a memory leak generated by
ptrb pointer lost and also open file descriptors detected at program exit.
Here you can see a piece of the output generated by Valgrind tool for the example above:
==8829== Memcheck, a memory error detector.
==8829== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
Maemo for Mobile Developers
==8829== Using LibVEX rev 1884, a library for dynamic binary translation.
==8829== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==8829== Using valgrind-3.4.1-maemo, a dynamic binary instrumentation framework.
==8829== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==8829== For more details, rerun with: -v
==8829==
==8829==
==8829== FILE DESCRIPTORS: 4 open at exit.
==8829== Open file descriptor 3: /tmp/testfile.txt
==8829== at 0x40CF14E: __open_nocancel (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x40829D1: _IO_file_fopen@@GLIBC_2.1 (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x40786C6: __fopen_internal (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x407871E: fopen@@GLIBC_2.1 (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x80484C8: main (valgrind_example.c:25)
==8829==
==8829== Open file descriptor 2: /dev/pts/0
==8829== <inherited from parent>
==8829==
==8829== Open file descriptor 1: /dev/pts/0
==8829== <inherited from parent>
==8829==
==8829== Open file descriptor 0: /dev/pts/0
==8829== <inherited from parent>
==8829==
==8829==
==8829== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 1)
Maemo for Mobile Developers
==8829== malloc/free: in use at exit: 402 bytes in 2 blocks.
==8829== malloc/free: 3 allocs, 1 frees, 502 bytes allocated.
==8829== For counts of detected errors, rerun with: -v
==8829== searching for pointers to 2 not-freed blocks.
==8829== checked 56,280 bytes.
==8829==
==8829== 50 bytes in 1 blocks are definitely lost in loss record 1 of 2
==8829== at 0x4020C19: malloc (in /targets/FREMANTLE_X86/usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==8829== by 0x8048452: main (valgrind_example.c:10)
==8829==
==8829==
==8829== 352 bytes in 1 blocks are still reachable in loss record 2 of 2
==8829== at 0x4020C19: malloc (in /targets/FREMANTLE_X86/usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==8829== by 0x407867A: __fopen_internal (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x407871E: fopen@@GLIBC_2.1 (in /targets/FREMANTLE_X86/lib/libc-2.5.so)
==8829== by 0x80484C8: main (valgrind_example.c:25)
==8829==
==8829== LEAK SUMMARY:
==8829== definitely lost: 50 bytes in 1 blocks.
==8829== possibly lost: 0 bytes in 0 blocks.
==8829== still reachable: 352 bytes in 1 blocks.
==8829== suppressed: 0 bytes in 0 blocks.
The Valgrind output shows that there are some open file descriptors at program exit. As a
good programming practice, file descriptors (and other resources) should be properly closed
before quit from application. In this case, there are 4 open file descriptors: the first one is
related to /tmp/testfile.txt file (line #25); the last 3 file descriptors are related to file
/dev/pts/0 and they are closed by operating system.
Maemo for Mobile Developers
In addition, Valgrind output reports 402 unallocated bytes in 2 different blocks: the first block
is ptrb pointer allocation (line #10) and the second one is fd pointer allocation (line #25). Thus,
the following scenario clearly defines a memory leak on the application and it should be
avoided. Then, programmer should review the code and free properly allocated pointers.
It is possible to use the same example on more Valgrind tools, such as cachegrind and massif.
For more information about Valgrind, including its profiling and debugging tools, see Valgrind
User Manual.
2.2 OProfile Today, even with advances on hardware for mobile devices, including the Internet Tablet,
programmers often deal with system resources constraints, such as memory and CPU
processing. Although in some cases the device CPU speed is enough for the application, using
fewer resources will save device battery. These restrictions impact directly on how developers
do their jobs: the code cannot demand too much memory or CPU processing. Thus, even if a
certain Maemo application under development is considered bug‐free, it is necessary to check
if it is consuming a considerable amount of system resources.
It is important to check where application´s bottlenecks are: hardware and software interrupt
handlers, kernel modules, the kernel, shared libraries or applications. The Maemo
development environment provides OProfile, a well known profiling tool for systems running
Linux 2.2, 2.4, and 2.6 kernels. OProfile runs transparently in the background and profile data
can be collected at any time. It can be used to find CPU usage bottlenecks in the whole system
and within processes.
2.2.1 Installing OProfile on Scratchbox OProfile can be installed on both Maemo rootstraps: X86 and ARMEL. OProfile is available on
Maemo Tools repository. Then, if Maemo Tools repository is not properly configured on your
environment, edit file /etc/apt/sources.list and add the following line:
deb http://repository.maemo.org/ fremantle/tools free non-free
Once Maemo Tools repository was added as a valid repository, it is necessary to update the
packages list. Execute the following command as root to refresh the package:
[sbox-FREMANTLE_X86: ~] > fakeroot apt-get update
To install OProfile on Scratchbox, execute the following command:
[sbox-FREMANTLE_X86: ~] > fakeroot apt-get install oprofile
2.2.2 Installing OProfile on Internet Tablet At first, install OProfile in device. Do not forget to configure Maemo Tools repository and get
connected with device through a SSH section as described on section 2.2.1.
Nokia-N810:~# apt-get install oprofile
In order to run OProfile on Internet Tablet, it is necessary to update the system kernel so it is
possible to catch required system events used by OProfile, such as signals and interruptions. A
Maemo for Mobile Developers
pre‐compiled kernel with OProfile support is provided by kernel‐oprofile package and it can be
downloaded from the Fremantle tools repository in Scratchbox environment:
[sbox-FREMANTLE_ARMEL: ~] > fakeroot apt-get install kernel-oprofile
Package kernel‐oprofile installs the kernel image suitable for OProfile into /boot/ directory.
[sbox-FREMANTLE_ARMEL: ~] >ls -l /boot
lrwxrwxrwx 1 root root 19 Sep 26 23:43 XXX
Once oprofile‐enabled kernel is saved, it is possible to flash Internet Tablet so OProfile can be
used on device. However, it is necessary to copy oprofile‐enabled kernel image to outer
environment (host Desktop system) so flasher tool can be used to flash Internet Tablet.
Remember that Scratchbox is under Desktop environment, so the contents of Scratchbox file
system can be easily accessed by Desktop user.
Now, copy the kernel image to the /tmp directory using the following command:
[sbox-FREMANTLE_ARMEL: ~] >cp /boot/XXX/tmp
Flasher tool is required to flash kernel image into Internet Tablet. Visit flasher tool download
page (http://tablets‐dev.nokia.com/d3.php) and download the newest version of flasher tool.
In this tutorial, flasher‐3.0 is being used.
Once flasher tool is available, it is necessary to change its permissions so flasher‐3.0 can be
executed. Go to the directory where flasher‐3.0 was previously saved and execute the
following command:
maemo@maemo-desktop:~$ chmod +x flasher-3.0
For more information about flasher tool, see visit flasher tool page
(https://wiki.maemo.org/Flasher).
Once kernel oprofile‐enabled and flasher tool are available, it is possible to flash the Internet
Tablet.
2.2.2.1 Flashing the kernel This approach flashes the device, so the current kernel is replaced by oprofile‐enabled kernel.
To flash the new kernel image, use the linux flasher utility with options –f (flash) and –R
(reboot):
maemo@maemo-desktop:~$ sudo./flasher-3.0 -f --kernel /tmp/XXX-R
This operation does not destroy existing data in the device. However, it is suggested to backup
Internet Tablet data before flashing the device. Once flasher tool has finished, the device is
ready for OProfile.
Maemo for Mobile Developers
Once there is nothing more to do with OProfile, the user can restore the normal kernel. In such
case, since the system kernel was replaced by oprofile‐enabled kernel, it is necessary to re‐
flash the device with other kernel using the following command:
maemo@maemo-desktop:~$ flasher -f --flash-only kernel -F \ <image> -R
# The FIASCO image is the whole product image with a name like:
# RX-44_DIABLO_3.2008.17-8_PR_COMBINED_MR0_ARM.bin
As suggested before, re‐flashing the kernel does not destroy any of the other parts, but it is
safe to backup Internet Tablet data before flashing the device.
2.2.2.2 Boot with the new kernel This approach only boots the device with oprofile‐enabled kernel. Thus, if Internet Tablet is
turned off, the normal kernel is restored.
maemo@maemo‐desktop:~$ sudo./flasher‐3.0 ‐‐load ‐‐boot ‐‐kernel /tmp/X
2.2.3 Using OProfile The following instructions can be executed on both Scratchbox and Internet Tablet,
considering that OProfile is properly installed and configured on them. In addition, the
instructions must be executed as root.
If OProfile is executed on Internet Tablet, remember that it is necessary to establish a SSH
section with device in order to make things easier. Thus, get connected with Internet Tablet as
described before. In this tutorial, commands are executed on Internet Tablet.
To start with, it is necessary to init opcontrol, which controls OProfile execution and manages
data collection. The following commands are used to load modules and other essential files to
OProfile (‐‐init option), indicate that there is no kernel image available (‐‐no‐vmlinux option)
so kernel events are not supposed to be hold, and the number of CPU cycles between
interrupts (‐e option). It is possible to use other system events (CPU_CLK_UNHALTED or
RTC_INTERRUPTS) to define interrupts.
Nokia-N810:~# opcontrol --init
Nokia-N810:~# opcontrol --no-vmlinux
Nokia-N810:~# opcontrol -e=CPU_CYCLES:100000
For more information about opcontrol, visit OProfile User Documentation
(http://oprofile.sourceforge.net/doc/index.html).
Now, OProfile data collection can be started:
Nokia-N810:~# opcontrol–start
Using 2.6+ OProfile kernel interface.
Using log file /var/lib/oprofile/samples/oprofiled.log
Maemo for Mobile Developers
Daemon started.
Profiler running.
OProfile collects all necessary information to generate reports. Once data collection has been
started, the application to analyze can be launched. Data about the current application
execution is collected as well.
To collect information about Qt libraries and symbols, it is suggested to execute the
gdb_example application: a simple Qt application with a push button. When the button is
pressed, the application is finalized.
Considering that the application is finalized, opcontrol data collection can be stopped:
Nokia-N810:~# opcontrol--stop
Stopping profiling.
It is possible to reset data just collected and restart the process:
Nokia-N810:~# opcontrol --reset
Nokia-N810:~# opcontrol --init
Once some data has been collected, it can be processed. OProfile provides different tools to
process dump files and show human‐readable information: opreport, opannotate, or opgprof.
opreport utility generates two types of data: image summaries and symbol summaries. An
image summary shows statistics about individual binary images such as libraries or
applications, and symbol summary provides per‐symbol profile data.
These numbers are very important to inspect where application bottlenecks are located and
how it is possible to speed up application execution. For example, if a certain application
spends more than 50% of its execution time on a single function, the programmer has to check
why it takes too much time and how it is possible to modify the algorithm in order to save
time. The following example shows information about image and symbol symmaries collected
by OProfile:
Nokia-N810:~# opreport
CPU: ARM V6 PMU, speed 0 MHz (estimated)
Counted CPU_CYCLES events (clock cycles counter) with a unit mask of 0x00 (No unit mask) count 100000
CPU_CYCLES:100000|
samples| %|
------------------
7788 43.7848 no-vmlinux
2000 11.2442 ld-2.5.so
Maemo for Mobile Developers
1552 8.7255 libc-2.5.so
1070 6.0156 libglib-2.0.so.0.1200.12
906 5.0936 libgobject-2.0.so.0.1200.12
608 3.4182 Xomap
485 2.7267 libQtGui.so.4.5.2
428 2.4063 libgtk-x11-2.0.so.0.1000.12
424 2.3838 oprofiled
397 2.2320 libgcc_s.so.1
381 2.1420 libpthread-2.5.so
327 1.8384 libQtCore.so.4.5.2
252 1.4168 libgdk-x11-2.0.so.0.1000.12
238 1.3381 busybox
151 0.8489 libX11.so.6.2.0
121 0.6803 libmb.so.1.0.9
86 0.4835 libfontconfig.so.1.1.0
70 0.3935 libfreetype.so.6.3.16
60 0.3373 libz.so.1.2.3
50 0.2811 esd
42 0.2361 libgthread-2.0.so.0.1200.12
42 0.2361 libpango-1.0.so.0.1600.4
38 0.2136 libsapwood.so
35 0.1968 libexpat.so.1.0.0
30 0.1687 libpng12.so.0.1.2.8
25 0.1406 libgdk_pixbuf-2.0.so.0.1000.12
15 0.0843 libhildondesktop.so.0.0.0
14 0.0787 UTF-16.so
13 0.0731 libcairo.so.2.11.5
13 0.0731 libstdc++.so.6.0.3
... snip ...
To see more detailed symbol analysis use opreport ‐l:
Maemo for Mobile Developers
Nokia-N810:~# opreport -l|more
warning: /no-vmlinux could not be found.
BFD: /usr/lib/debug/lib/ld-2.5.so: warning: sh_link not set for section `.ARM.exidx'
BFD: /usr/lib/debug/lib/libc-2.5.so: warning: sh_link not set for section `.ARM.exidx'
CPU: ARM11 PMU, speed 0 MHz (estimated)
Counted CPU_CYCLES events (clock cycles counter) with a unit mask of 0x00 (No unit mask) count 100000
7788 43.7848 no-vmlinux /no-vmlinux
609 3.4238 ld-2.5.so do_lookup_x
608 3.4182 Xomap /usr/bin/Xomap
485 2.7267 libQtGui.so.4.5.2 /usr/lib/libQtGui.so.4.5.2
428 2.4063 libgtk-x11-2.0.so.0.1000.12 /usr/lib/libgtk-x11-2.0.so.0.1000.12
424 2.3838 oprofiled /usr/bin/oprofiled
397 2.2320 libgcc_s.so.1 /lib/libgcc_s.so.1
327 1.8384 libQtCore.so.4.5.2 /usr/lib/libQtCore.so.4.5.2
267 1.5011 ld-2.5.so check_match.0
259 1.4561 ld-2.5.so strcmp
252 1.4168 libgdk-x11-2.0.so.0.1000.12 /usr/lib/libgdk-x11-2.0.so.0.1000.12
238 1.3381 busybox /bin/busybox
185 1.0401 libc-2.5.so memcpy
179 1.0064 libc-2.5.so _int_malloc
151 0.8489 ld-2.5.so _dl_relocate_object
151 0.8489 libX11.so.6.2.0 /usr/lib/libX11.so.6.2.0
133 0.7477 ld-2.5.so _dl_map_object
126 0.7084 libpthread-2.5.so pthread_mutex_lock
121 0.6803 libmb.so.1.0.9 /usr/lib/libmb.so.1.0.9
112 0.6297 libgobject-2.0.so.0.1200.12 g_type_check_instance_is_a
110 0.6184 libc-2.5.so strcmp
Maemo for Mobile Developers
108 0.6072 libglib-2.0.so.0.1200.12 g_hash_table_lookup
100 0.5622 libc-2.5.so malloc
96 0.5397 libc-2.5.so strchr
86 0.4835 libfontconfig.so.1.1.0 /usr/lib/libfontconfig.so.1.1.0
86 0.4835 libpthread-2.5.so pthread_getspecific
82 0.4610 ld-2.5.so dl_new_hash
80 0.4498 ld-2.5.so __udivsi3
80 0.4498 libglib-2.0.so.0.1200.12 g_slice_alloc
… snip …
opannotate is used to generate annotated source code. It is possible to show assembly code
mixed with source code, including the number of samples for each line. In order to use
opannotate, the application must have debug information, and the source must be available
through this debug information.
opgprof generates reports on GNU‐gprof format, so you can use the output on many gprof UI
analyzers.
2.2.4 OProfile with callgraph OProfile is commonly used on basic mode to collect statistics about a certain application and it
is possible to obtain interesting information about your application by using utility tools
(opreport, opannotate, opgprof). However, more sophisticated information can be obtained by
using OProfile together with callgraphs, which show relationships between callers and callees.
To use callgraphs, it is required to recompile all the code (binaries, libraries) of application.
Before recompiling the code, it is necessary to change compiling options by adding ‐fno‐omit‐
frame‐pointer to GCC options (for more information about Scratchbox environment variable,
see /scratchbox/doc/variables.txt file):
Nokia-N810:~# export SBOX_BLOCK_COMPILER_ARGS="-fomit-frame-pointer"
Nokia-N810:~# export SBOX_EXTRA_COMPILER_ARGS="-fno-omit-frame-pointer"
Once the code is properly recompiled, copy the result to device by using SCP, just like
described in this section.
Init oprofileand enablecallgraph sample collection (‐c option) with an integer as argument
which represents the maximum depth:
Nokia-N810:~# opcontrol --init
Nokia-N810:~# opcontrol --no-vmlinux
Maemo for Mobile Developers
Nokia-N810:~# opcontrol -e=CPU_CYCLES:100000 –c 20
Run the opreport command with ‐c option:
Nokia-N810:~# opreport -l -c
The output is as follows:
CPU: ARM V6 PMU, speed 0 MHz (estimated) Counted CPU_CYCLES events (clock cycles counter) with a unit mask of 0x00 (No unit mask) count 1000000
BFD: /usr/lib/debug/lib/ld-2.5.so: warning: sh_link not set for section `.ARM.exidx'
BFD: /usr/lib/debug/lib/libc-2.5.so: warning: sh_link not set for section `.ARM.exidx'
samples % app name symbol name ---------------------------------------------------------------------- 141 55.5118 no-vmlinux /no-vmlinux 141 100.000 no-vmlinux /no-vmlinux [self] ---------------------------------------------------------------------- 20 7.8740 busybox /bin/busybox 20 100.000 busybox /bin/busybox [self] ---------------------------------------------------------------------- 13 5.1181 libgobject-2.0.so.0.1200.12 /usr/lib/libgobject-2.0.so.0.1200.12 13 100.000 libgobject-2.0.so.0.1200.12 /usr/lib/libgobject-2.0.so.0.1200.12 [self] ---------------------------------------------------------------------- 6 2.3622 libc-2.5.so strchr 6 100.000 libc-2.5.so strchr [self] ---------------------------------------------------------------------- 6 2.3622 libgtk-x11-2.0.so.0.1000.12 /usr/lib/libgtk-x11-2.0.so.0.1000.12 6 100.000 libgtk-x11-2.0.so.0.1000.12 /usr/lib/libgtk-x11-2.0.so.0.1000.12 [self] ---------------------------------------------------------------------- 5 1.9685 Xomap /usr/bin/Xomap 5 100.000 Xomap /usr/bin/Xomap [self] ---------------------------------------------------------------------- 4 1.5748 ld-2.5.so _dl_relocate_object 4 100.000 ld-2.5.so _dl_relocate_object [self] ---------------------------------------------------------------------- 4 1.5748 ld-2.5.so check_match.0 4 100.000 ld-2.5.so check_match.0 [self] ---------------------------------------------------------------------- 4 1.5748 ld-2.5.so do_lookup_x 4 100.000 ld-2.5.so do_lookup_x [self] ---------------------------------------------------------------------]
Maemo for Mobile Developers
OProfile report represents calling relationships between subroutines of the same
application/library. The output shows the nodes of callgraph: for example, on library ld‐2.5.so,
functions do_lookup_x, check_match.0 and __dl_relocate_object are invoked during OProfile
data collection.
2.2.5 oprofileui oprofileui is a graphical user interface to the oprofile system profiler. At first, it is necessary to
establish a SSH section to the device as root and install oprofileui‐viewer and oprofileui‐server
packages:
Nokia-N810:~# apt-get install oprofileui-viewer oprofileui-server
… snip …
To see callgraphs, do not forget to compile the target binaries with frame pointers enabled
(GCC ‐fno‐omit‐frame‐pointer option) just like described in the section OProfile with callgraph.
Reset opcontrol to clear old dump and start oprofile‐server in the device:
Nokia-N810:~# opcontrol --reset
Nokia-N810:~# oprofile-server&
Start oprofile‐viewer in the device:
Nokia-N810:~# oprofile-viewer
A graphical user interface for OProfile will appear on Internet Tablet screen:
Press “Connect”button on toolbar:
Maemo for Mobile Developers
Select “This Computer” and click “Connect” button.
Click “Start” button and then click “Stop” button.
oprofileui lists the report as list on main window:
Note that oprofileui components are also visible at OProfile report, since it collects all
symbols/functions invoked during data collection.
2.3 Strace Maemo applications certainly do a lot of system calls, such as I/O and memory operations. In
some situations it might be needed to monitor what system calls are been executed by the
application, for example to look for a crash related to the interaction with system or to
optimize some peace of the code that is executing system calls too often, like heavy file
opening and closing.
Strace is a debugging tool that monitors all system calls used by a process and also all the
signal it receives. Strace is really simple to use: the application under analysis does not need to
have debugging symbols available. In addition, strace can be attached to a running process,
and retrieve information about the system calls used by it.
Maemo for Mobile Developers
Strace can be installed on both Scratchbox and Internet Tablet environments. On Scratchbox,
strace is already installed by default. If strace is supposed to be used on Scratchbox, it is
suggested that strace be used in an X86 target rather than in an ARMEL target: in an ARMEL
target strace will actually trace the system calls of the QEMU process.
Strace is available at Maemo Tools repository. Then, if Maemo Tools repository is not properly
configured on your environment, edit file /etc/apt/sources.list and add the following line:
deb http://repository.maemo.org/ fremantle/tools free non-free
Once Maemo Tools repository was added as a valid repository, it is necessary to update the
packages list. Execute the following command as root to refresh the package:
Nokia-N810:~# apt-get update
On Internet Tablets, you need to install strace by using the following command:
Nokia-N810:~# apt-get install strace
… snip …
The usage of strace is very simple like in the command below:
Nokia-N810:~# strace program
Strace also can be attached to a running process. To do this run the command:
Nokia-N810:~# strace -p PID
Here, PID is the process identification number.You can find the process PID with ps command.
For more information about strace, visit the Strace manual page
(http://maemo.org/development/documentation/man_pages/strace/).
In this tutorial, a very simple Qt example is used to demonstrate the strace tool
(strace_example.cpp). The application just opens a Qt application with a “Hello World” label.
01 #include <QApplication>
02 #include <QLabel>
03
04 int main(intargc, char* argv[]) {
05 QApplicationapp(argc,argv);
06 QLabel *label = new QLabel("Hello World!");
07 label->show();
08 return app.exec();
09 }
Maemo for Mobile Developers
Compile the application on ARMEL roostrap:
[sbox-FREMANTLE_ARMEL: ~] >qmake –project
[sbox-FREMANTLE_ARMEL: ~] >qmake
.. snip …
Copy the application to device using SCP (see Section 6,"Test the application on a device" in
Chapter 2.). Now, run strace with strace_example as parameter:
Nokia-N810:~# strace ./strace_example
execve("./strace_example", ["./strace_example"], [/* 59 vars */]) = 0
brk(0) = 0x11000
uname({sys="Linux", node="Nokia-N810", ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x4001b000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=26046, ...}) = 0
mmap2(NULL, 26046, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40024000
close(3) = 0
open("/usr/lib/libQtGui.so.4", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0(\0\1\0\0\0\320\25\35\0004\0\0\0t"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0644, st_size=10445228, ...}) = 0
mmap2(NULL, 10485276, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x4002c000
mprotect(0x409f9000, 28672, PROT_NONE) = 0
mmap2(0x40a00000, 172032, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x9cc) = 0x40a00000
mmap2(0x40a2a000, 7708, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40a2a000
close(3) = 0
… snip …
write(6, "@"..., 1) = 1
Maemo for Mobile Developers
close(6) = 0
close(5) = 0
rt_sigaction(SIGCHLD, {SIG_DFL}, {0x40b94da0, [], SA_NOCLDSTOP|0x4000000}, 8) = 0
exit_group(0) = ?
Each line has the name, parameters and returned value of system calls. As the example is
linked against Qt libraries. You can see in the strace output the system call to load Qt libraries.
Basically, library loading consists of a .so file opening and the system call open is used for this
issue. For example, strace_example loads QtGui library ("/usr/lib/libQtGui.so.4"), as a read‐
only file (O_RDONLY), as listed on strace output:
open("/usr/lib/libQtGui.so.4", O_RDONLY) = 3
For open system call, the returned value is the identifier of file descriptor (3). Such value is
used to close the file when necessary (close system call).
As example of failed system call, there is the following example extracted from previous strace
output:
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
The system call access checks if file ld.so.preload ("/etc/ld.so.preload") has read permission
(R_OK). The file does not exists and access system call returns error code (‐1).
It is possible to generate a summary with count time, calls, and errors for each system call.
Execute the strace tool with ‐c option:
Nokia-N810:~# strace -c ./strace_example
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
31.39 0.005429 1 6313 5 lstat64
20.98 0.003629 3 1369 901 open
15.35 0.002655 5 517 1 mmap2
10.60 0.001833 3 711 5 read
7.23 0.001250 3 387 munmap
4.94 0.000854 4 194 write
NOTE: Failed system calls usually (not always) return a return code of ‐1.
NOTE: If you are using strace in scratchbox with ARMEL target, the option ‐f needs to
be given, so that the process run under the QEMU is also traced.
Maemo for Mobile Developers
3.17 0.000549 1 638 26 access
2.82 0.000488 1 573 readlink
2.47 0.000428 19 22 writev
1.06 0.000183 2 86 44 stat64
0.00 0.000000 0 473 close
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 pipe
0.00 0.000000 0 15 brk
0.00 0.000000 0 56 ioctl
0.00 0.000000 0 4 gettimeofday
… snip …
0.00 0.000000 0 5 2 connect
0.00 0.000000 0 1 shutdown
0.00 0.000000 0 1 SYS_305
0.00 0.000000 0 1 SYS_307
------ ----------- ----------- --------- --------- ----------------
2.4 Ltrace Applications often use subroutines and symbols defined on dynamic libraries installed in the
system. For example the Qt libraries: QtGui and QtCore. Maemo development environment
provides Ltrace as a tool for monitoring dynamic libraries calls performed by a process and also
to trace the signals which are received by such process. Ltrace is very similar to strace, but
strace only intercepts and records system calls.
Ltrace can be used on both Scratchbox and Internet Tablet environments. It is available at
Maemo Tools repository. Before installing it, configure Maemo Tools repository as described
on previous section about strace. In order to install ltrace, execute the following command:
[sbox-FREMANTLE_ARMEL: ~] >apt-get install ltrace
… snip …
To demonstrate how ltrace can be used, the same example of section strace is used. At first,
compile the application on ARMEL roostrap:
[sbox-FREMANTLE_ARMEL: ~] >qmake –project
[sbox-FREMANTLE_ARMEL: ~] >qmake
.. snip …
Maemo for Mobile Developers
Them, copy the executable to Internet Tablet using SCP. Now, run ltrace with strace_example
as parameter:
Nokia-N810:~# ltrace ./ltrace_example
__libc_start_main(35000, 1, 0xbe80c6e4, 35300, 35412 <unfinished ...>
_ZN12QApplicationC1ERiPPci(0xbe80c568, 0xbe80c554, 0xbe80c6e4, 263426, 0xbe80c590) = 0xbe80c568
_ZN7QString16fromAscii_helperEPKci(35436, -1, 0, 0x40a24ee8, 0xbe80c590) = 168952
_Znwj(20, 168994, 0, 33, 0xbe80c590) = 0x110368
_ZN6QLabelC1ERK7QStringP7QWidget6QFlagsIN2Qt10WindowTypeEE(0x110368, 0xbe80c560, 0, 0xbe80c558, 0xbe80c590) = 0x110368
_ZN12QApplication4execEv(0xbe80c4f8, 0xbe80c4f8, 4, 0x40c9e468, 0xbe80c590) = 0
_ZN12QApplicationD1Ev(0xbe80c568, 0x40e5f0ac, 0, 0, 0xbe80c590) = 0xbe80c568
+++ exited (status 0) +++
The output format of ltrace looks like strace output: each line consists of library function
name, a list of parameters and the result code.
In addition, it is possible to track system calls with ltrace as well (‐S parameter):
Nokia-N810:~# ltrace -S ./ltrace_example
3119 SYS_brk(NULL) = 0x00011000 <0.000366>
3119 SYS_uname(0xbe83c1f0) = 0 <0.000366>
3119 SYS_mmap2(0, 4096, 3, 34, -1) = 0x4001b000 <0.000427>
3119 SYS_access("/etc/ld.so.preload", 04) = -2 <0.000397>
3119 SYS_open("/etc/ld.so.cache", 0, 01) = 3 <0.000488>
3119 SYS_fstat64(3, 0xbe83baa0, 0xbe83baa0, 0, 3) = 0 <0.000366>
3119 SYS_mmap2(0, 26046, 1, 2, 3) = 0x40024000 <0.000457>
3119 SYS_close(3 = 0 <0.000702>
3119 SYS_open("/usr/lib/libQtGui.so.4", 0, 010000433450) = 3 <0.000519>
3119 SYS_read(3, "\177ELF\001\001\001", 512) = 512 <0.000427>
3119 SYS_fstat64(3, 0xbe83bad0, 0xbe83bad0, 0, 23) = 0 <0.000397>
3119 SYS_mmap2(0, 0x9ffe1c, 5, 2050, 3) = 0x4002c000 <0.000458>
Maemo for Mobile Developers
Maemo for Mobile Developers
3119 SYS_mprotect(0x409f9000, 28672, 0) = 0 <0.000580>
3119 SYS_mmap2(0x40a00000, 172032, 3, 2066, 3) = 0x40a00000 <0.000732>
3119 SYS_mmap2(0x40a2a000, 7708, 3, 50, -1) = 0x40a2a000 <0.000671>
3119 SYS_close(3) = 0 <0.000366>
… snip …
ltrace outputs the process ID, name of system call, its parameters and its result code:
3119 SYS_open("/etc/ld.so.cache", 0, 01) = 3 <0.000488>
As strace, ltracegenerates a summary with count time, calls, and calls for each library
invocation. Execute the ltrace tool with ‐c option:
% time seconds usecs/call calls function
------ ----------- ----------- --------- --------------------
71.98 6.845215 6845215 1 _ZN12QApplicationC1ERiPPci
27.74 2.638214 2638214 1 _ZN12QApplication4execEv
0.24 0.022552 22552 1 _ZN12QApplicationD1Ev
0.02 0.002258 2258 1 _ZN6QLabelC1ERK7QStringP7QWidget6QFlagsIN2Qt10WindowTypeEE
0.01 0.000732 732 1 _Znwj
0.01 0.000702 702 1
_ZN7QString16fromAscii_helperEPKci
------ ----------- ----------- --------- --------------------
100.00 9.509673 6 total
For more information about ltrace, visit the Ltrace manual page
(http://maemo.org/development/documentation/man_pages/ltrace/).