Android NDK Beginner's Guide (2nd Ed.) [Ratabouil 2015 04 30]

ANDROID_NDK_BEGINNERS_GUIDE_SECOND_EDITION

Android%20NDK%20Beginner's%20Guide%20(2nd%20ed.)%20%5BRatabouil%202015-04-30%5D

ANDROID%20NDK%20BEGINNERS%20GUIDE%20NDK

ANDROID%20NDK%20BEGINNERS%20GUIDE%20NDK

ANDROID%20NDK%20BEGINNERS%20GUIDE%20NDK

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 494

DownloadAndroid NDK Beginner's Guide (2nd Ed.) [Ratabouil 2015-04-30]
Open PDF In BrowserView PDF
[1]

Android NDK Beginner's Guide
Second Edition

Discover the native side of Android and inject the power
of C/C++ in your applications

Sylvain Ratabouil

BIRMINGHAM - MUMBAI

Android NDK Beginner's Guide
Second Edition

Copyright © 2015 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system,
or transmitted in any form or by any means, without the prior written permission of the
publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the
information presented. However, the information contained in this book is sold without
warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers
and distributors will be held liable for any damages caused or alleged to be caused directly
or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the
companies and products mentioned in this book by the appropriate use of capitals.
However, Packt Publishing cannot guarantee the accuracy of this information.

First published: January 2012
Second Edition: April 2015

Production reference: 1240415

Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham B3 2PB, UK.
ISBN 978-1-78398-964-5
www.packtpub.com

Credits
Author
Sylvain Ratabouil
Reviewers

Project Coordinator
Mary Alex
Proofreaders

Guy Cole

Simran Bhogal

Krzysztof Fonał

Safis Editing

Sergey Kosarevsky
Raimon Ràfols

Indexer
Monica Ajmera Mehta

Commissioning Editor
Ashwin Nair

Graphics
Disha Haria

Acquisition Editor
Vinay Argekar

Production Coordinator
Conidon Miranda

Content Development Editor
Rohit Singh

Cover Work
Conidon Miranda

Technical Editor
Ryan Kochery
Copy Editors
Hiral Bhat
Adithi Shetty
Sameen Siddiqui

About the Author
Sylvain Ratabouil is an IT consultant, experienced in Android, Java, and C/C++. He has
contributed to the development of digital and mobile applications for large companies as
well as industrial projects for the space and aeronautics industries. As a technology lover,
he is passionate about mobile technologies and cannot live without his Android smartphone.

About the Reviewers
Guy Cole is a veteran Silicon Valley contractor with engagements in many well-known
companies such as Facebook, Cisco, Motorola, Cray Research, Hewlett-Packard, Wells Fargo
Bank, Barclays Global Investments, DHL Express, and many smaller, less-famous companies.
You can contact him via LinkedIn for your next project.

Krzysztof Fonał is passionate about computer science. He fell in love with this field when
he was eleven. He strongly believes that technology doesn't matter; problem solving skills
matters, as well as the passion to absorb knowledge. He currently works with Trapeze Group,
which is a world leader in providing IT solutions. He plans to work with machine learning
books and also on the Corona SDK.

Sergey Kosarevsky is a software engineer with experience in C++ and 3D graphics. He
worked for mobile industry companies and was involved in mobile projects at SPB Software,
Yandex, and Layar. He has more than 12 years of software development experience and more
than 6 years of Android NDK experience. Sergey earned his PhD in the field of mechanical
engineering from St.Petersburg Institute of Machine-Building in Saint-Petersburg, Russia.
He is a coauthor of Android NDK Game Development Cookbook. In his spare time, Sergey
maintains and develops an open source multiplatform gaming engine, Linderdaum Engine
(http://www.linderdaum.com), and a multi-platform open source file manager, WCM
Commander (http://wcm.linderdaum.com).

Raimon Ràfols has been developing for mobile devices since 2004. He has experience
in developing on several technologies, specializing in UI, build systems, and client-server
communications. He is currently working as a mobile software engineering manager
at Imagination Technologies near London. In his spare time, he enjoys programming,
photography, and giving talks at mobile conferences about Android performance
optimization and Android custom views.
I would like to express my gratitude to my beloved girlfriend, Laia, for her
support and understanding.

www.PacktPub.com
Support files, eBooks, discount offers, and more
For support files and downloads related to your book, please visit www.PacktPub.com.
Did you know that Packt offers eBook versions of every book published, with PDF and ePub
files available? You can upgrade to the eBook version at www.PacktPub.com and as a print
book customer, you are entitled to a discount on the eBook copy. Get in touch with us at
service@packtpub.com for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up
for a range of free newsletters and receive exclusive discounts and offers on Packt books
and eBooks.
TM

https://www2.packtpub.com/books/subscription/packtlib

Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book
library. Here, you can search, access, and read Packt's entire library of books.

Why subscribe?
‹‹

Fully searchable across every book published by Packt

‹‹

Copy and paste, print, and bookmark content

‹‹

On demand and accessible via a web browser

Free access for Packt account holders
If you have an account with Packt at www.PacktPub.com, you can use this to access PacktLib
today and view 9 entirely free books. Simply use your login credentials for immediate access.

Table of Contents
Preface
Chapter 1: Setting Up Your Environment
Getting started with Android development
Setting up Windows
Time for action – preparing Windows for Android development
Installing Android development kits on Windows
Time for action – installing Android SDK and NDK on Windows
Setting up OS X
Time for action – preparing OS X for Android development
Installing Android development kits on OS X
Time for action – installing Android SDK and NDK on OS X
Setting up Linux
Time for action – preparing Ubuntu for Android development
Installing Android development kits on Linux
Time for action – installing Android SDK and NDK on Ubuntu
Installing the Eclipse IDE
Time for action – installing Eclipse with ADT on your OS
Setting up the Android emulator
Time for action – creating an Android virtual device
Developing with an Android device
Time for action – setting up an Android device
More about ADB
Summary

Chapter 2: Starting a Native Android Project
Building NDK sample applications
Time for action – compiling and deploying San Angeles sample
Generating project files with Android manager
Compiling native code with NDK-Build
[i]

vii
1
2
2
3
8
8
13
13
16
17
22
23
25
25
30
30
35
35
39
39
42
43

45
46
46
49
51

Table of Contents

Building and packaging an application with Ant
Deploying an application package with Ant
Launching an application with ADB Shell
More about Android tooling
Creating your first native Android project
Time for action – creating a native Android project
Introducing Dalvik and ART

52
52
53
54
55
55
59

Interfacing Java with C/C++
Time for action – calling C code from Java
Debugging native Android applications
Time for action – debugging a native Android application
Defining NDK application-wide settings
NDK-GDB day-to-day
Analyzing native crash dumps
Time for action – analyzing a native crash dump
Deciphering crash dumps
Setting up a Gradle project to compile native code
Time for action – creating a native Android project
Time for action – using your own Makefiles with Gradle
Summary

Chapter 3: Interfacing Java and C/C++ with JNI
Initializing a native JNI library
Time for action – defining a simple GUI
Time for action – initializing the native store
Converting Java strings in native code
Time for action – handling strings in the native store
Native character encoding
JNI String API
Passing Java primitives to native code
Time for action – handling primitives in the native store
Referencing Java objects from native code
Time for action – saving references to Objects in native Store
Local references
Global references
Weak references
Managing Java arrays
Time for action – handling Java arrays in native Store
Primitive arrays
Object arrays
Raising and checking Java exceptions
[ ii ]

60
61
64
64
67
68
69
69
71
73
74
78
80

81
82
82
88
91
91
97
98
99
99
103
103
107
109
110
112
112
121
124
124

Table of Contents

Time for action – raising & catching exceptions in native Store
Executing code in Exception state
Exception handling API
Summary

Chapter 4: Calling Java Back from Native Code
Calling Java back from native code
Time for action – determining JNI method signatures
Time for action – calling back Java from native code
More on the JNI Reflection API
Debugging JNI
Synchronizing Java and native threads
Time for action – allocating an object with JNI
Time for action – running and synchronizing a thread
Synchronizing Java and C/C++ with JNI Monitors
Attaching and detaching native threads
Processing bitmaps natively
Time for action – decoding a camera's feed
Time for action – processing pictures with the Bitmap API
Registering native methods manually
JNI in C versus JNI in C++
Summary

Chapter 5: Writing a Fully Native Application

125
128
130
130

133
134
134
138
142
143
144
144
151
155
156
157
158
165
171
171
172

173

Creating a native Activity
Time for action – creating a basic native Activity
More about the Native App Glue
Handling Activity events
Time for action – stepping the event loop
Time for action – handling Activity events
Accessing window surface natively
Time for action – displaying raw graphics
Measuring time natively
Time for action – animating graphics with a timer
Summary

174
174
180
182
182
187
193
193
204
204
215

Chapter 6: Rendering Graphics with OpenGL ES

217

Initializing OpenGL ES
Time for action – initializing OpenGL ES
Time for action – clearing and swapping buffers
An insight into the OpenGL pipeline
Loading textures using the Asset manager

218
219
223
225
226

[ iii ]

Table of Contents

Time for action – reading assets with the Asset manager
More about the Asset Manager API
Time for action – compiling and embedding libpng module
Time for action – loading a PNG image
Time for action – generating an OpenGL texture
More about textures
Drawing 2D sprites
Time for action – initializing OpenGL ES
Vertex Arrays versus Vertex Buffer Object
Rendering particle effects
Time for action – rendering a star field
Programming shaders with GLSL
Adapting graphics to various resolutions
Time for action – adapting resolution with off-screen rendering
Summary

Chapter 7: Playing Sound with OpenSL ES
Initializing OpenSL ES
Time for action – creating OpenSL ES engine and output
More on OpenSL ES philosophy
Playing music files
Time for action – playing background music
Playing sounds
Time for action – creating and playing a sound buffer queue
Using callbacks to detect sound queue events
Low latency on Android
Recording sounds
Creating and releasing the recorder
Recording a sound
Recording a callback
Summary

Chapter 8: Handling Input Devices and Sensors
Interacting with touch events
Time for action – handling touch events
Detecting keyboard, D-Pad, and Trackball events
Time for action – handling keyboard, D-Pad, and trackball events natively
Probing device sensors
Time for action – handling accelerometer events
Time for action – turning an Android device into a Joypad
More on sensors
Summary
[ iv ]

227
229
232
234
240
244
247
247
268
269
270
280
282
282
289

291
292
293
298
299
299
306
307
320
321
322
324
325
326
326

327
328
329
340
341
347
348
355
362
363

Table of Contents

Chapter 9: Porting Existing Libraries to Android
Activating the Standard Template Library
Time for action – activating GNU STL in DroidBlaster
Time for action – read files with STL stream
Time for action – using STL containers
Porting Box2D to Android
Time for action – compiling Box2D on Android
Time for action – running Box2D physics engine
Diving into the Box2D world
More on collision detection
Collision modes and filtering
Going further with Box2D
Prebuilding Boost on Android
Time for action – prebuilding Boost static library
Time for action – compiling an executable linked to Boost
Mastering module Makefiles
Makefile variables
Enabling C++ 11 support and the Clang compiler
Makefile Instructions
CPU Architectures (ABI)
Advanced instruction sets (NEON, VFP, SSE, MSA)
Summary

Chapter 10: Intensive Computing with RenderScript
What is RenderScript ?
Executing a predefined Intrinsic
Time for action – creating a Java UI
Time for action – running RenderScript Blur intrinsic
Writing a custom Kernel
Time for action – writing a luminance threshold filter
Combining scripts together
Time for action – combining Intrinsics and scripts together
Summary

Afterword
Index

365
366
366
369
373
382
383
387
402
403
404
406
407
407
413
417
417
420
421
424
424
426

427
428
429
429
432
440
440
448
449
457

459
463

[v]

Preface
Android NDK is all about injecting high performance and portable code into your mobile
apps by exploiting the maximum speed of these mobile devices. Android NDK allows you
to write fast code for intensive tasks and port existing code to Android and non-Android
platforms. Alternatively, if you have an application with multiple lines of C code, using NDK
can considerably reduce the project development process. This is one of the most efficient
operating systems for multimedia and games.
This Beginner's Guide will show you how to create applications enabled by C/C++ and
integrate them with Java. By using this practical step-by-step guide, and gradually practicing
your new skills using the tutorials, tips, and tricks, you will learn how to run C/C++ code
embedded in a Java application or in a standalone application.
The books starts by teaching you how to access native API and port libraries used in some
of the most successful Android applications. Next, you will move on to create a real native
application project through the complete implementation of a native API and porting
existing third-party libraries. As we progress through the chapters, you will gain a detailed
understanding of rendering graphics and playing sound with OpenGL ES and OpenSL ES,
which are becoming the new standard in mobility. Moving forward, you will learn how to
access the keyboard and input peripherals, and read accelerometer or orientation sensors.
Finally, you will dive into more advanced topics, such as RenderScript.
By the end of the book, you will be familiar enough with the key elements to start exploiting
the power and portability of native code.

[ vii ]

Preface

What this book covers
Chapter 1, Setting Up Your Environment, covers all the prerequisite packages installed on
our system. This chapter also covers installing the Android Studio bundle, which contains
both the Android Studio IDE and the Android SDK.
Chapter 2, Starting a Native Android Project, discusses how to build our first sample
application using command-line tools and how to deploy it on an Android device. We
also create our first native Android projects using Eclipse and Android Studio.
Chapter 3, Interfacing Java and C/C++ with JNI, covers how to make Java communicate with
C/C++. We also handle Java object references in native code using Global references, and
we learn the differences of Local references. Finally, we raise and check Java exceptions
in native code.
Chapter 4, Calling Java Back from Native Code, calls Java code from native code with the
JNI Reflection API. We also process bitmaps natively with the help of JNI and decode a
video feed by hand.
Chapter 5, Writing a Fully Native Application, discusses creating NativeActivity that
polls activity events to start or stop native code accordingly We also access the display
window natively, such as a bitmap to display raw graphics. Finally, we retrieve time to
make the application adapt to device speed using a monotonic clock.
Chapter 6, Rendering Graphics with OpenGL ES, covers how to initialize an OpenGL ES
context and bind it to an Android window. Then, we see how to turn libpng into a
module and load a texture from a PNG asset.
Chapter 7, Playing Sound with OpenSL ES, covers how to initialize OpenSL ES on Android.
Then, we learn how to play background music from an encoded file and in-memory sounds
with a sound buffer queue. Finally, we discover how to record and play a sound in a way that
is thread-safe and non-blocking.
Chapter 8, Handling Input Devices and Sensors, discusses multiple ways to interact with
Android from native code. More precisely, we discover how to attach an input queue to
the Native App Glue event loop.
Chapter 9, Porting Existing Libraries to Android, covers how to activate the STL with a simple
flag in the NDK makefile system. We port the Box2D library into an NDK module that is
reusable among Android projects.
Chapter 10, Intensive Computing with RenderScript, introduces RenderScript, an advanced
technology to parallelize intensive computation tasks. We also see how to use predefined
RenderScript with built-in Intrinsics, which is currently mainly dedicated to image processing.

[ viii ]

Preface

What you need for this book
To run the examples in the book, the following software will be required:
‹‹

System: Windows, Linux or Mac OS X

‹‹

JDK: Java SE Development Kit 7 or 8

‹‹

Cygwin: On Windows only

Who this book is for
Are you an Android Java programmer who needs more performance? Are you a C/C++
developer who doesn't want to bother with the complexity of Java and its out-of-control
garbage collector? Do you want to create fast, intensive multimedia applications or games?
If you've answered yes to any of these questions, then this book is for you. With some
general knowledge of C/C++ development, you will be able to dive head first into native
Android development.

Sections
In this book, you will find several headings that appear frequently (Time for action,
What just happened?, Pop quiz, and Have a go hero).
To give clear instructions on how to complete a procedure or task, we use these sections
as follows:

Time for action – heading
1.
2.
3.

Action 1
Action 2
Action 3

Instructions often need some extra explanation to ensure they make sense, so they are
followed with these sections:

[ ix ]

Preface

What just happened?
This section explains the working of the tasks or instructions that you just completed.
You will also find some other learning aids in the book, for example:

Have a go hero – heading
These are practical challenges that give you ideas to experiment with what you have learned.

Conventions
You will also find a number of text styles that distinguish between different kinds of
information. Here are some examples of these styles and an explanation of their meaning.
Code words in text, database table names, folder names, filenames, file extensions,
pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "Finally,
create a new Gradle task ndkBuild that will manually trigger the ndk-build command."
A block of code is set as follows:
#include 
…
sleep(3); // in seconds

When we wish to draw your attention to a particular part of a code block, the relevant lines
or items are set in bold:
if (mGraphicsManager.start() != STATUS_OK) return STATUS_KO;
mAsteroids.initialize();
mShip.initialize();
mTimeManager.reset();
return STATUS_OK;

Any command-line input or output is written as follows:
adb shell stop
adb shell setprop dalvik.vm.checkjni true

[x]

Preface

New terms and important words are shown in bold. Words that you see on the screen, in
menus or dialog boxes for example, appear in the text like this: "If everything works properly,
a message Late-enabling – Xcheck:jni appears in the Logcat when your application starts."
Warnings or important notes appear in a box like this.

Tips and tricks appear like this.

Reader feedback
Feedback from our readers is always welcome. Let us know what you think about this
book—what you liked or disliked. Reader feedback is important for us as it helps us
develop titles that you will really get the most out of.
To send us general feedback, simply e-mail feedback@packtpub.com, and mention
the book's title in the subject of your message.
If there is a topic that you have expertise in and you are interested in either writing or
contributing to a book, see our author guide at www.packtpub.com/authors.

Customer support
Now that you are the proud owner of a Packt book, we have a number of things to help
you to get the most from your purchase.

Downloading the example code
You can download the example code files from your account at http://www.packtpub.com
for all the Packt Publishing books you have purchased. If you purchased this book elsewhere,
you can visit http://www.packtpub.com/support and register to have the files e-mailed
directly to you.

[ xi ]

Preface

Errata
Although we have taken every care to ensure the accuracy of our content, mistakes do happen.
If you find a mistake in one of our books—maybe a mistake in the text or the code—we
would be grateful if you could report this to us. By doing so, you can save other readers from
frustration and help us improve subsequent versions of this book. If you find any errata, please
report them by visiting http://www.packtpub.com/submit-errata, selecting your book,
clicking on the Errata Submission Form link, and entering the details of your errata. Once your
errata are verified, your submission will be accepted and the errata will be uploaded to our
website or added to any list of existing errata under the Errata section of that title.
To view the previously submitted errata, go to https://www.packtpub.com/books/
content/support and enter the name of the book in the search field. The required
information will appear under the Errata section.

Piracy
Piracy of copyrighted material on the Internet is an ongoing problem across all media.
At Packt, we take the protection of our copyright and licenses very seriously. If you come
across any illegal copies of our works in any form on the Internet, please provide us with
the location address or website name immediately so that we can pursue a remedy.
Please contact us at copyright@packtpub.com with a link to the suspected
pirated material.
We appreciate your help in protecting our authors and our ability to bring you
valuable content.

Questions
If you have a problem with any aspect of this book, you can contact us at questions@
packtpub.com, and we will do our best to address the problem.

[ xii ]

1

Setting Up Your Environment
Are you ready to take up the mobile challenge? Is your computer switched on,
mouse and keyboard plugged in, and screen illuminating your desk? Then let's
not wait a minute more!
Developing Android applications requires a specific set of tools. You may
already know about the Android Software Development Kit for pure Java
applications. However, getting full access to the power of Android devices
requires more: the Android Native Development Kit.

Setting up a proper Android environment is not that complicated, however it can be rather
tricky. Indeed, Android is still an evolving platform and recent additions, such as Android
Studio or Gradle, are not well supported when it comes to NDK development. Despite these
annoyances, anybody can have a ready-to-work environment in an hour.
In this first chapter, we are going to:
‹‹

Install prerequisites packages

‹‹

Set up an Android development environment

‹‹

Launch an Android emulator

‹‹

Connect an Android device for development

[1]

Setting Up Your Environment

Getting started with Android development
What differentiates mankind from animals is the use of tools. Android developers, the
authentic species you belong to, are no different!
To develop applications on Android, we can use any of the following three platforms:
‹‹

Microsoft Windows (XP and later)

‹‹

Apple OS X (Version 10.4.8 or later)

‹‹

Linux (distributions using GLibc 2.7 or later, such as latest versions of Ubuntu)

These systems are supported on x86 platforms (that is, PCs with processors such as Intel or
AMD) in both 32- and 64-bit versions, except for Windows XP (32-bit only).
This is a good start but, unless you are able to read and write binary code as well as speak
your mother tongue, having a raw OS is not enough. We also need software dedicated to
Android development:
‹‹

A JDK (Java Development Kit)

‹‹

An Android SDK (Software Development Kit)

‹‹

An Android NDK (Native Development Kit)

‹‹

An IDE (Integrated Development Environment) such as Eclipse or Visual Studio (or
vi for hard-core coders). Android Studio and IntelliJ are not yet well-suited for NDK
development, although they provide basic support for native code.

‹‹

A good old command-line shell to manipulate all these tools. We will use Bash.

Now that we know what tools are necessary to work with Android, let's start with the
installation and setup process.
The following section is dedicated to Windows. If you are a Mac or Linux user,
you can jump to Setting up an OS X or Setting up Linux section.

Setting up Windows
Before installing the necessary tools, we need to set up Windows to host our Android
development tools properly. Although it is not the most natural fit for Android development,
Windows still provides a fully functional environment.
The following section explains how to set up the prerequisite packages on Windows 7. The
process is the same for Windows XP, Vista, or 8.

[2]

Chapter 1

Time for action – preparing Windows for Android development
To develop with the Android NDK on Windows, we need to set up a few prerequisites:
Cygwin, a JDK, and Ant.

1.

Go to http://cygwin.com/install.html and download the Cygwin setup
program suitable for your environment. Once downloaded, execute it.

2.

In the installation window, click on Next and then Install from Internet.

Follow the installation wizard screens. Consider selecting a download site from
where Cygwin packages are downloaded in your country.

[3]

Setting Up Your Environment

Then, when proposed, include the Devel, Make, Shells, and bash packages:

Follow the installation wizard until the end. This may take some time depending on
your Internet connection.

3.

Download Oracle JDK 7 from the Oracle website at http://www.oracle.com/
technetwork/java/javase/downloads/index.html (or JDK 8, although it
is not officially supported at the time this book is written). Launch and follow the
installation wizard until the end.

4.

Download Ant from its website at http://ant.apache.org/bindownload.cgi
and unzip its binary package in the directory of your choice (for example, C:\Ant).

5.

After installation, define JDK, Cygwin, and Ant locations in environment variables. To
do so, open Windows Control Panel and go to the System panel (or right-click on the
Computer item in the Windows Start menu and select Properties).
Then, go to Advanced system settings. The System Properties window appears.
Finally, select the Advanced tab and click on the Environment Variables button.

[4]

Chapter 1

6.

In the Environment Variables window, inside the System variables list, add:
‰‰

‰‰
‰‰

The CYGWIN_HOME variable with the Cygwin installation directory as the
value (for example, C:\Cygwin)
The JAVA_HOME variable with the JDK installation directory as the value
The ANT_HOME variable with the Ant installation directory as the value (for
example, C:\Ant)

Prepend %CYGWIN_HOME%\bin;%JAVA_HOME%\bin;%ANT_HOME%\bin;, all
separated by a semicolon, at the beginning of your PATH environment variable.

7.

Finally, launch a Cygwin terminal. Your profile files get created on the first launch.
Check the make version to ensure Cygwin works:
make –version

[5]

Setting Up Your Environment

You will see the following output:

8.

Ensure JDK is properly installed by running Java and checking its version. Check
carefully to make sure the version number corresponds to the newly installed JDK:
java –version

You will see the following output on the screen:

9.

From a classic Windows terminal, check the Ant version to make sure it is
properly working:
ant -version

You will see the following on the terminal:

[6]

Chapter 1

What just happened?
Windows is now set up with all the necessary packages to host Android development tools:
‹‹

Cygwin, which is an open source software collection, allows the Windows platform
to emulate a Unix-like environment. It aims at natively integrating software based
on the POSIX standard (such as Unix, Linux, and so on) into Windows. It can be
considered as an intermediate layer between applications originated from Unix/
Linux (but natively recompiled on Windows) and the Windows OS itself. Cygwin
includes Make, which is required by the Android NDK compilation system to build
native code.
Even if Android NDK R7 introduced native Windows
binaries, which does not require a Cygwin runtime, it is still
recommended to install the latter for debugging purpose.

‹‹

A JDK 7, which contains the runtime and tools necessary to build Java applications
on Android and run the Eclipse IDE as well as Ant. The only real trouble that you may
encounter when installing a JDK is some interferences from a previous installation,
such as an existing Java Runtime Environment (JRE). Proper JDK use can be enforced
through the JAVA_HOME and PATH environment variables.
Defining the JAVA_HOME environment variable is not
required. However, JAVA_HOME is a popular convention
among Java applications, Ant being one of them. It first looks
for the java command in JAVA_HOME (if defined) before
looking in PATH. If you install an up-to-date JDK in another
location later on, do not forget to update JAVA_HOME.

‹‹

Ant, which is a Java-based build automation utility. Although not a requirement,
it allows building Android applications from the command line, as we will see in
Chapter 2, Starting a Native Android Project. It is also a good solution to set up a
continuous integration chain.

The next step consists of setting up the Android development kits.

[7]

Setting Up Your Environment

Installing Android development kits on Windows
Android requires specific development kits to develop applications: the Android SDK and
NDK. Hopefully, Google has thought about the developer community and provides all the
necessary tools for free.
In the following part, we will install these kits to start developing native Android applications
on Windows 7.

Time for action – installing Android SDK and NDK on Windows
The Android Studio bundle already contains the Android SDK. Let's install it.

1.

Open your web browser and download the Android Studio bundle from http://
developer.android.com/sdk/index.html.
Run the downloaded program and follow the installation wizard. When requested,
install all Android components.

Then, choose the installation directories for Android Studio and the Android SDK (for
example, C:\Android\android-studio and C:\Android\sdk).
[8]

Chapter 1

2.

Launch Android Studio to ensure it is properly working. If Android Studio proposes
to import settings from a previous installation, select your preferred option and click
on OK.

The Android Studio welcome screen should then appear. Close it.

[9]

Setting Up Your Environment

3.

Go to http://developer.android.com/tools/sdk/ndk/index.html and
download the Android NDK (not SDK!) suitable for your environment. Extract the
archive inside the directory of your choice (for example, C:\Android\ndk).

4.

To easily access Android utilities from the command line, let's declare the Android
SDK and NDK as environment variables. From now on, we will refer to these
directories as $ANDROID_SDK and $ANDROID_NDK.
Open the Environment Variables system window, as we did previously. Inside the
System variables list, add the following:
‰‰

‰‰

The ANDROID_SDK variable with the SDK installation directory (for example,
C:\Android\sdk)
The ANDROID_NDK variable with the NDK installation directories (for
example, C:\Android\ndk)

Prepend %ANDROID_SDK%\tools;%ANDROID_SDK%\platformtools;%ANDROID_NDK%;, all separated by a semicolon, at the beginning of your
PATH environment variable.

[ 10 ]

Chapter 1

5.

All Windows environment variables should be imported automatically by Cygwin
when launched. Open a Cygwin terminal and list the Android devices connected
to your computer (even if none are currently) with adb to check whether SDK is
working. No error should appear:
adb devices

6.

Check the ndk-build version to ensure that NDK is working. If everything works,
the Make version should appear:
ndk-build -version

7.

Open Android SDK Manager, located in the ADB bundle directory's root.

[ 11 ]

Setting Up Your Environment

In the opened window, click on New to select all the packages and then click on the
Install packages... button. Accept the licenses in the popup that appears and start
the installation of Android development packages by clicking on the Install button.
After a few long minutes, all packages are downloaded and a confirmation message
indicating that the Android SDK manager has been updated appears.
Validate and close the manager.

What just happened?
Android Studio is now installed on the system. Although it is now the official Android IDE,
we are not going to use it much throughout the book because of its lack of support of the
NDK. It is, however, absolutely possible to use Android Studio for Java development, and
command line or Eclipse for C/C++.
The Android SDK has been set up through the Android Studio package. An alternative
solution consists of manually deploying the SDK standalone package provided by Google.
On the other hand, the Android NDK has been deployed manually from its archive. Both
the SDK and NDK are made available through the command line thanks to a few
environment variables.
To get a fully functional environment, all Android packages have been downloaded thanks to
the Android SDK manager, which aims at managing all the platforms, sources, samples, and
emulation features available through the SDK. This tool greatly simplifies the update of your
environment when new SDK API and components are released. There is no need to reinstall
or overwrite anything!
However, the Android SDK Manager does not manage the NDK, which explains why we
downloaded it separately, and why you will need to update it manually in the future.

[ 12 ]

Chapter 1

Installing all Android packages is not strictly necessary. Only the SDK
platform (and possibly Google APIs) releases targeted by your application
are really required. Installing all packages may avoid troubles when
importing other projects or samples though.

The installation of your Android development environment is not over yet. We still need one
more thing to develop comfortably with the NDK.
This is the end of the section dedicated to the Windows setup. The following
section is dedicated to OS X.

Setting up OS X
Apple computers have a reputation for being simple and easy to use. I must say that this
adage is rather true when it comes to Android development. Indeed, as a Unix-based system,
OS X is well adapted to run the NDK toolchain.
The following section explains how to set up the prerequisite packages on Mac OS X Yosemite.

Time for action – preparing OS X for Android development
To develop with the Android NDK on OS X, we need to set up a few prerequisites: a JDK,
Developer Tools, and Ant.

1.

A JDK is preinstalled on OS X 10.6 Snow Leopard and below. On these systems,
Apple's JDK is in version 6. Since this version is deprecated, it is advised to install
an up-to-date JDK 7 (or JDK 8, although it is not officially supported at the time this
book is written).
On the other hand, OS X 10.7 Lion and above does not have a default JDK installed.
Installing the JDK 7 is thus mandatory.

[ 13 ]

Setting Up Your Environment

To do so, download Oracle JDK 7 from the Oracle website at http://www.oracle.
com/technetwork/java/javase/downloads/index.html. Launch the DMG
and follow the installation wizard until the end.

Check the Java version to ensure that the JDK is properly installed.
java -version

[ 14 ]

Chapter 1

To know if a JDK 6 is installed, check Java Preferences.app located by going
to Applications | Utilities on your Mac. If you have JDK 7, check whether
you have the Java icon under System Preferences.

2.

All Developer Tools are included in the XCode installation package (Version 5, at the
time this book is written). XCode is provided on the AppStore for free. Starting from
OS X 10.9, the Developer Tools package can be installed separately from a terminal
prompt with the following command:
xcode-select --install

Then, from the popup window that appears, select Install.

3.

To build native code with the Android NDK, whether XCode or the single Developer
Tools package is installed, we need Make. Open a terminal prompt and check the
Make version to ensure that it correctly works:
make –version

4.

On OS X 10.9 and later, Ant must be installed manually. Download Ant from its
website at http://ant.apache.org/bindownload.cgi and unzip its binary
package in the directory of your choice (for example, /Developer/Ant).
Then, create or edit the file ~/.profile and make Ant available on the system
path by appending the following:
export ANT_HOME="/Developer/Ant"
export PATH=${ANT_HOME}/bin:${PATH}

[ 15 ]

Setting Up Your Environment

Log out from your current session and log in again (or restart your computer)
and check whether Ant is correctly installed by checking its version from the
command line:
ant –version

What just happened?
Our OS X system is now set up with the necessary packages to host Android
development tools:
‹‹

A JDK 7, which contains the runtime and tools necessary to build Java applications
on Android and to run the Eclipse IDE as well as Ant.

‹‹

Developer Tools package, which packages various command-line utilities. It
includes Make, which is required by the Android NDK compilation system to build
native code.

‹‹

Ant, which is a Java-based build automation utility. Although not a requirement,
it allows building Android applications from the command line, as we will see in
Chapter 2, Starting a Native Android Project. It is also a good solution to set up a
continuous integration chain.

The next step consists of setting up the Android Development Kit.

Installing Android development kits on OS X
Android requires specific development kits to develop applications: the Android SDK and
NDK. Hopefully, Google has thought about the developer community and provides all the
necessary tools for free.
In the following part, we are going to install these kits to start developing native Android
applications on Mac OS X Yosemite.

[ 16 ]

Chapter 1

Time for action – installing Android SDK and NDK on OS X
The Android Studio bundle already contains the Android SDK. Let's install it.

1.

Open your web browser and download the Android Studio bundle from http://
developer.android.com/sdk/index.html.

2.

Run the downloaded DMG file. In the window that appears, drag the Android Studio
icon into Applications and wait for Android Studio to be fully copied on the system.

3.

Run Android Studio from Launchpad.
If an error Unable to find a valid JVM appears (because Android Studio cannot find
a suitable JRE when launched), you can run Android Studio from the command line
as follows (using the appropriate JDK path):
export
STUDIO_JDK=/Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk
open /Applications/Android\ Studio.apps

[ 17 ]

Setting Up Your Environment

To solve the Android Studio startup issue, you can also install the
former JDK 6 package provided by Apple. Beware! This version is
outdated and thus, deprecated.

If Android Studio proposes to import settings from a previous installation, select
your preferred option and click on OK.

In the next Setup Wizard screen that appears, select the Standard installation type
and continue the installation.

[ 18 ]

Chapter 1

Complete the installation until the Android Studio welcome screen appears. Then,
close Android Studio.

4.

Go to http://developer.android.com/tools/sdk/ndk/index.html and
download the Android NDK (not SDK!) archive suitable for your environment. Extract
it inside the directory of your choice (for example, ~/Library/Android/ndk).

5.

To easily access Android utilities from the command line, let's declare the Android
SDK and NDK as environment variables. From now on, we will refer to these
directories as $ANDROID_SDK and $ANDROID_NDK. Assuming you use the default
Bash command-line shell, create or edit .profile (which is a hidden file!) in your
home directory and append the following instructions (adapt paths according to
your installation):
export ANDROID_SDK="~/Library/Android/sdk"
export ANDROID_NDK="~/Library/Android/ndk"
export PATH="${ANDROID_SDK}/tools:${ANDROID_SDK}/platformtools:${ANDROID_NDK}:${PATH}"

[ 19 ]

Setting Up Your Environment

6.

Log out from your current session and log in again (or restart your computer). List
the Android devices connected to your computer (even if none currently are) with
adb to check whether Android SDK is working. No error should appear:
adb devices

7.

Check the ndk-build version to ensure that NDK is working. If everything works,
the Make version should appear:
ndk-build -version

8.

Open a terminal and start the Android SDK manager with the following command:
android

[ 20 ]

Chapter 1

In the opened window, click on New to select all the packages and then click on the
Install packages... button. Accept the licenses in the popup that appears and start
the installation of all Android packages by clicking on the Install button.
After a few long minutes, all packages are downloaded and a confirmation message
indicating that the Android SDK manager has been updated appears.
Validate and close the manager.

What just happened?
Android Studio is now installed on the system. Although it is now the official Android IDE,
we will not use it much through the book because of its lack of support of the NDK. It is,
however, absolutely possible to use Android Studio for Java development, and command line
or Eclipse for C/C++.
The Android SDK has been set up through the Android Studio package. An alternative solution
consists of manually deploying the SDK standalone package provided by Google. On the other
hand, the Android NDK has been deployed manually from its archive. Both the SDK and NDK
are made available through the command line, thanks to a few environment variables.

[ 21 ]

Setting Up Your Environment

OS X is tricky when it comes to environment variables. They can be easily
declared in .profile for applications launched from a terminal, as we
just did. They can also be declared using an environment.plist file
for GUI applications, which are not launched from Spotlight.

To get a fully functional environment, all Android packages have been downloaded thanks to
the Android SDK manager, which aims at managing all the platforms, sources, samples, and
emulation features available through the SDK. This tool greatly simplifies the update of your
environment when new SDK API and components are released. There is no need to reinstall
or overwrite anything!
However, the Android SDK manager does not manage the NDK, which explains why we
downloaded it separately, and why you will need to update it manually in the future.
Installing all Android packages is not strictly necessary. Only the SDK
platform (and possibly Google APIs) releases targeted by your application
are really required. Installing all packages may avoid troubles importing
other projects or samples though.

The installation of your Android development environment is not over yet. We still need one
more thing to develop comfortably with the NDK.
This is the end of the section dedicated to the OS X setup. The following
section is dedicated to Linux.

Setting up Linux
Linux is naturally suited for Android development as the Android toolchain is Linux-based.
Indeed, as a Unix-based system, Linux is well adapted to run the NDK toolchain. Beware,
however, that commands to install packages may vary depending on your Linux distribution.
The following section explains how to set up the prerequisite packages on Ubuntu 14.10
Utopic Unicorn.

[ 22 ]

Chapter 1

Time for action – preparing Ubuntu for Android development
To develop with the Android NDK on Linux, we need to set up a few prerequisites: Glibc,
Make, OpenJDK, and Ant.

1.

From Command Prompt, check whether Glibc (the GNU C standard library) 2.7 or
later, usually shipped with Linux systems by default, is installed:
ldd -–version

2.

Make is also required to build native code. Install it from the build-essential package

(requires administrative privilege):
sudo apt-get install build-essential

Run the following command to ensure Make is correctly installed, in which case its
version is displayed:
make –version

3.

On 64-bit Linux systems, install the 32-bit libraries compatibility package, as Android
SDK has binaries compiled for 32 bits only. To do so on Ubuntu 13.04 and earlier,
simply install the ia32-libs package:
sudo apt-get install ia32-libs

On Ubuntu 13.10 64 bits and later, this package has been removed. So, install the
required packages manually:
sudo apt-get install lib32ncurses5 lib32stdc++6 zlib1g:i386 libc6i386

[ 23 ]

Setting Up Your Environment

4.

Install Java OpenJDK 7 (or JDK 8, although it is not officially supported at the time
this book is written). Oracle JDK is also fine:
sudo apt-get install openjdk-7-jdk

Ensure JDK is properly installed by running Java and checking its version:
java –version

5.

Install Ant with the following command (requires administrative privilege):
sudo apt-get install ant

Check whether Ant is properly working:
ant -version

What just happened?
Our Linux system is now prepared with the necessary packages to host Android
development tools:
‹‹

The build-essential package, which is a minimal set of tools for compilation and
packaging on Linux Systems. It includes Make, which is required by the Android NDK
compilation system to build native code. GCC (the GNU C Compiler) is also included
but is not required as Android NDK already contains its own version.

‹‹

32-bit compatibility libraries for 64-bit systems, since the Android SDK still uses
32-bit binaries.

‹‹

A JDK 7, which contains the runtime and tools necessary to build Java applications
on Android and run the Eclipse IDE as well as Ant.

‹‹

Ant, which is a Java-based build automation utility. Although not a requirement,
it allows building Android applications from the command line, as we will see in
Chapter 2, Starting a Native Android Project. It is also a good solution to set up a
continuous integration chain.

The next step consists of setting up the Android development kits.

[ 24 ]

Chapter 1

Installing Android development kits on Linux
Android requires specific development kits to develop applications: the Android SDK and
NDK. Hopefully, Google has thought about the developer community and provides all the
necessary tools for free.
In the following part, we will install these kits to start developing native Android applications
on Ubuntu 14.10 Utopic Unicorn.

Time for action – installing Android SDK and NDK on Ubuntu
The Android Studio bundle already contains the Android SDK. Let's install it.

1.

Open your web browser and download the Android Studio bundle from http://
developer.android.com/sdk/index.html. Extract the downloaded archive in
the directory of your choice (for example, ~/Android/Android-studio).

2.

Run the Android Studio script bin/studio.sh. If Android Studio proposes to
import settings from a previous installation, select your preferred option and click
on OK.

[ 25 ]

Setting Up Your Environment

In the next Setup Wizard screen that appears, select a Standard installation type
and continue installation.

Complete installation until the Android Studio welcome screen. Then, close
Android Studio.

[ 26 ]

Chapter 1

3.

Go to http://developer.android.com/tools/sdk/ndk/index.html and
download the Android NDK (not SDK!) archive suitable for your environment. Extract
it inside the directory of your choice (for example, ~/Android/Ndk).

[ 27 ]

Setting Up Your Environment

4.

To easily access Android utilities from the command line, let's declare the Android
SDK and NDK as environment variables. From now on, we will refer to these
directories as $ANDROID_SDK and $ANDROID_NDK. Edit your .profile file
(beware since this is a hidden file!) in your home directory and add the following
variables at the end (adapt their path according to your installation directories):
export ANDROID_SDK="~/Android/Sdk"
export ANDROID_NDK="~/Android/Ndk"
export PATH="${ANDROID_SDK}/tools:${ANDROID_SDK}/platformtools:${ANDROID_NDK}:${PATH}"

5.

Log out from your current session and log in again (or restart your computer). List
the Android devices connected to your computer (even if none currently are) with
adb to check whether Android SDK is working. No error should appear:
adb devices

6.

Check the ndk-build version to ensure that NDK is working. If everything works,
the Make version should appear:
ndk-build -version

7.

Open a terminal and start the Android SDK manager with the following command:
android

[ 28 ]

Chapter 1

In the opened window, click on New to select all the packages, and then click on the
Install packages... button. Accept the licenses in the popup that appears and start
the installation of all Android package by clicking on the Install button.
After a few long minutes, all packages are downloaded and a confirmation message
indicating that the Android SDK manager has been updated appears.
Validate and close the manager.

What just happened?
Android Studio is now installed on the system. Although it is now the official Android IDE,
we are not going to use it much throughout the book because of its lack of support of the
NDK. It is, however, absolutely possible to use Android Studio for Java development, and the
command line or Eclipse for C/C++.
The Android SDK has been set up through the Android Studio package. An alternative solution
consists of manually deploying the SDK standalone package provided by Google. On the other
hand, the Android NDK has been deployed manually from its archive. Both the SDK and NDK
are made available through the command line, thanks to a few environment variables.

[ 29 ]

Setting Up Your Environment

To get a fully functional environment, all Android packages have been downloaded thanks to
the Android SDK manager, which aims at managing all the platforms, sources, samples, and
emulation features available through the SDK. This tool greatly simplifies the update of your
environment when new SDK API and components are released. There is no need to reinstall
or overwrite anything!
However, the Android SDK manager does not manage the NDK, which explains why we
downloaded it separately, and why you will need to update it manually in the future.
Installing all Android packages is not strictly necessary. Only the SDK
platform (and possibly Google APIs) releases targeted by your application
are really required. Installing all packages may avoid trouble when
importing other projects or samples though.

The installation of not or Android development environment is not over yet. We still need
one more thing to develop comfortably with the NDK.
This is the end of the section dedicated to the Linux setup. The following
section is for all operating systems.

Installing the Eclipse IDE
Because of Android Studio limitations, Eclipse is still one of the most appropriate IDEs to
develop native code on Android. Using an IDE is not required though; command-line lovers
or vi fanatics can skip this part!
In the following section, we will see how to set up Eclipse.

Time for action – installing Eclipse with ADT on your OS
Since the latest Android SDK releases, Eclipse and its plugins (ADT and CDT) need to be
installed manually. To do so execute the following steps:

1.

Go to http://www.eclipse.org/downloads/ and download Eclipse for Java
developers. Extract the downloaded archive in the directory of your choice (for
example, C:\Android\eclipse on Windows, ~/ Android/Eclipse on Linux,
and ~/Library/Android/eclipse on Mac OS X).

[ 30 ]

Chapter 1

Then, run Eclipse. If Eclipse asks for a workspace (which contains Eclipse settings and
projects) when starting up, define the directory of your choice or leave the default
settings and then click on OK.
When Eclipse has finished loading, close the welcome page. The following window
should appear:

[ 31 ]

Setting Up Your Environment

2.

Go to Help | Install New Software…. Enter https://dl-ssl.google.com/
android/eclipse in the Work with: field and validate. After a few seconds, a
Developer Tools plugin appears. Select it and click on the Next button.
In case this step fails while accessing update sites, check your Internet
connection. You may be either disconnected or connected behind a
proxy. In the latter case, you can download the ADT plugin as a separate
archive from the ADT web page and install it manually, or configure
Eclipse to connect through a proxy.

Follow the wizard and accept conditions when asked. On the last wizard page, click
on Finish to install ADT. A warning may appear indicating that the plugin content is
unsigned. Ignore it and click on OK. When finished, restart Eclipse as requested.
[ 32 ]

Chapter 1

3.

Go back to Help | Install New Software…. Open the Work with combobox and
select the item containing the Eclipse version name (here, Luna). Then, check the
Show only software applicable to target environment option. Find Programming
Languages in the plugin tree and unfold it. Finally, check all C/C++ plugins and click
on Next.

Follow the wizard and accept conditions when asked. On the last wizard page, click
on Finish. Wait until the installation is complete and restart Eclipse.

[ 33 ]

Setting Up Your Environment

4.

Go to Windows | Preferences... (Eclipse | Preferences... on Mac OS X) and then
select Android on the left tree. If everything is fine, the SDK Location should be filled
with the Android SDK path.

Then, on the same window, go to Android | NDK. The NDK Location field should be
empty. Fill it with the Android NDK path and validate. If the path is wrong, Eclipse
complains that the directory is not valid.

[ 34 ]

Chapter 1

What just happened?
Eclipse is now up and running with the appropriate SDK and NDK configuration. Since the
ADT package is no longer provided by Google, the Android development plugin ADT and the
C/C++ Eclipse plugin CDT have to be installed manually in Eclipse.
Please note that Eclipse has been deprecated by Google and replaced by Android Studio.
Sadly, Android Studio C/C++ and NDK support is rather limited for the moment. The only way
to build native code is through Gradle, the new Android build system, whose NDK features
are still unstable. If a comfortable IDE is essential to you, you can still use Android Studio for
Java development and Eclipse for C/C++ though.
If you work on Windows, maybe you are Visual Studio adept. In that case, I advise you that a
few projects, shown as follows, bring Android NDK development to Visual Studio:
‹‹

Android++, which is a free extension for Visual Studio that can be found at http://
android-plus-plus.com/. Although still in Beta at the time this book is written,
Android++ looks quite promising.

‹‹

NVidia Nsight, which can be downloaded with a developer account from the Nvidia
developer website at https://developer.nvidia.com/nvidia-nsighttegra (if you have a Tegra device). It packages together the NDK, a slightly
customized version of Visual Studio, and a nice debugger.

‹‹

VS-Android, which can be found at https://github.com/gavinpugh/vsandroid, is an interesting Open Source project, which brings NDK tools to
Visual Studio.

Our development environment is now almost ready. The last piece is missing though: an
environment to run and test our applications.

Setting up the Android emulator
The Android SDK provides an emulator to help developers who want to speed up their
deploy-run-test cycle or want to test, for example, different kinds of resolutions and OS
versions. Let's see how to set it up.

Time for action – creating an Android virtual device
The Android SDK provides everything we need to easily create a new emulator Android
Virtual Device (AVD):

1.

Open Android SDK Manager from a terminal by running the following command:
android

[ 35 ]

Setting Up Your Environment

2.

Go to Tools | Manage AVDs.... Alternatively, click on the dedicated Android Virtual
Device Manager button in the main toolbar of Eclipse.
Then, click on the New button to create a new Android emulator instance. Fill the
form with the following information and click on OK:

3.

The newly created virtual device now appears in the Android Virtual Device
Manager list. Select it and click on Start....
If you get an error related to libGL on Linux, open a
command prompt and run the following command to install
the Mesa graphics library: sudo apt-get install
libgl1-mesa-dev.

[ 36 ]

Chapter 1

4.

The Launch Options window appears. Tweak the display size depending on your
screen size if needed and then click on Launch. The emulator starts up and after
some time, your virtual device is loaded:

5.

By default, the emulator SD card is read only. Although this is optional, you can set it
in write mode by issuing the following command from a prompt:
adb shell
su
mount -o rw,remount rootfs /
chmod 777 /mnt/sdcard
exit
[ 37 ]

Setting Up Your Environment

What just happened?
Android emulators can be easily managed through the Android Virtual Device manager.
We are now able to test the applications we will develop in a representative environment.
Even better, we can now test them in several conditions and resolutions without requiring
a costly device. However, if emulators are useful development tools, take into account
that emulation is not always perfectly representative and lacks some features, especially
hardware sensors, which can be partially emulated.
Android Virtual Device manager is not the only place where we can manage emulators. We
can also use the command-line tool emulator provided with the Android SDK. For example,
to launch the Nexus4 emulator created earlier directly from a terminal prompt, enter the
following:
emulator -avd Nexus4

While creating the Nexus4 AVD, acute readers might have been surprised to see we set CPU/
ABI to Intel Atom (x86), whereas most Android devices run on ARM processors. Indeed, since
Windows, OS X, and Linux all run on x86, only x86 Android emulator images can benefit from
hardware and GPU acceleration. On the other hand, ARM ABI can run rather slow without it,
but it may be more representative of the devices your application may run on.
To benefit from full hardware acceleration with an X86 AVD, you will need to
install the Intel Hardware Accelerated Execution Manager (HAXM) on your
Windows or Mac OS X system. On Linux, you can install KVM instead. These
programs can work only if your CPU benefits from a Virtualization Technology
(which is the case most of the time nowadays).

Acuter readers may be even more surprised that we have not selected the latest Android
platform. The reason is simply that x86 images are not available for all Android platforms.
The Snapshot option allows saving the emulator state before closing it.
Sadly, this open is incompatible with GPU acceleration. You have to select
either one.

As a final note, know that customizing additional options, such as the presence of a GPS,
camera, and so on, is also possible when creating an AVD to test an application in limited
hardware conditions. The screen orientation can be switched with Ctrl + F11 and Ctrl + F12
shortcuts. For more information on how to use and configure the emulator, check out the
Android website at http://developer.android.com/tools/devices/emulator.
html.

[ 38 ]

Chapter 1

Developing with an Android device
Although emulators can be of help, they are obviously nothing compared to a real device. So,
take your Android device in hand, switch it on and let's try to connect it to our development
platform. Any of the following steps may change depending on your manufacturer and
phone language. So, please refer to your device documentation for specific instructions.

Time for action – setting up an Android device
Device configuration is dependent on your target OS. To do so:

1.

Configure your device driver on your OS if applicable:
‰‰

‰‰

‰‰

2.

If you use Windows, installation of a development device is manufacturerspecific. More information can be found at http://developer.
android.com/tools/extras/oem-usb.html with a full list of
device manufacturers. If you have a driver CD with your Android device,
you can use it. Note that the Android SDK also contains some Windows
drivers under $ANDROID_SDK\extras\google\usb_driver. Specific
instructions are available for Google development phones, Nexus One, and
Nexus S at http://developer.android.com/sdk/win-usb.html.
If you use OS X, simply connecting your development device to your Mac
should be enough to get it working! Your device should be recognized
immediately without installing anything. Mac's ease of use is not a legend.
If you are a Linux user, connecting your development device to your
Distribution (at least on Ubuntu) should be enough to get it working too!

If your mobile device runs Android 4.2 or later, from the application list screen, go
to Settings | About phone and tap several times on Build Number at the end of the
list. After some efforts, Developer options will magically appear in your application
list screen.
On Android 4.1 devices and earlier, Developer options should be visible by default.

3.

Still on your device, from the application list screen, go to Settings | Developer
options and enable Debugging and Stay awake.

4.

Plug your device into your computer using a data connection cable. Beware! Some
cables are charge-only cables and will not work for development! Depending on
your device manufacturer, it may appear as a USB disk.
On Android 4.2.2 devices and later, a dialog Allow USB debugging? appears on
the phone screen. Select Always allow from this computer to permanently allow
debugging and then click on OK.

[ 39 ]

Setting Up Your Environment

5.

Open Command Prompt and execute the following:
adb devices

On Linux, if ????????? appears instead of your device name (which is likely), then
adb does not have proper access rights. A solution might be to restart adb as root
(at your own risk!):
sudo $ANDROID_SDK/platform-tools/adb kill-server
sudo $ANDROID_SDK/platform-tools/adb devices

Another solution to find your Vendor ID and Product ID may be needed. Vendor ID
is a fixed value for each manufacturer that can be found on the Android developer
website at http://developer.android.com/tools/device.html (for
example, HTC is 0bb4). The device's Product ID can be found using the result of the
lsusb command in which we look for the Vendor ID (for example, here 0c87 is HTC
Desire product ID):
lsusb | grep 0bb4

Then, with root privilege, create a file /etc/udev/rules.d/51-android.rules
with your Vendor ID and Product ID and change file rights to 644:
sudo sh -c 'echo SUBSYSTEM==\"usb\", SYSFS{idVendor}==\"\", ATTRS{idProduct}=\"\",
GROUP=\"plugdev\", MODE=\"0666\" > /etc/udev/rules.d/52android.rules'
sudo chmod 644 /etc/udev/rules.d/52-android.rules

Finally, restart the udev service and adb:
sudo service udev restart
adb kill-server
adb devices

[ 40 ]

Chapter 1

6.

Launch Eclipse and open the DDMS perspective (Window | Open Perspective |
Other...). If working properly, your phone should be listed in the Devices view.
Eclipse is a compound of many views, such as the Package Explorer
View, the Debug View, and so on. Usually, most of them are already
visible, but sometimes they are not. In that case, open them
through the main menu by navigating to Window | Show View |
Other…. Views in Eclipse are grouped in Perspectives, which store
workspace layout. They can be opened by going to Window | Open
Perspective | Other…. Beware that some contextual menus may be
available only in some perspectives.

What just happened?
Our Android device has been switched into development mode and connected to our
workstation through the Android Debug Bridge daemon. ADB gets started automatically the
first time it is called, either from Eclipse or the command line.
We also enabled the Stay awake option to stop automatic screen shutdown when the phone
charges, or when developing with it! And, more important than anything, we discovered
that HTC means High Tech Computer! Jokes apart, connection process can be tricky on Linux,
although little trouble should be encountered nowadays.
Still having trouble with a reluctant Android device? That could mean any of the following:
‹‹

ADB is malfunctioning. In that case, restart the ADB deamon or execute it with
administrative privilege.

‹‹

Your development device is not working properly. In that case, try restarting your
device or disabling and re-enabling development mode. If that still does not work,
then buy another one or use the emulator.

‹‹

Your host system is not properly set up. In that case, check your device
manufacturer instructions carefully to make sure the necessary driver is correctly
installed. Check hardware properties to see whether it is recognized and turn on
USB storage mode (if applicable) to see whether it is properly detected. Please refer
to your device documentation.
When the charge-only mode is activated, SD card files and
directories are visible to the Android applications installed on
your phone but not to your computer. On the opposite side, when
disk drive mode is activated, those are visible only from your
computer. Check your connection mode when your application
cannot access its resource files on an SD card.

[ 41 ]

Setting Up Your Environment

More about ADB
ADB is a multi-facet tool which is used as a mediator between the development environment
and devices. It is composed of:
‹‹

A background process running on emulators and devices to receive orders or
requests from your workstation.

‹‹

A background server on your workstation communicating with connected devices
and emulators. When listing devices, the ADB server is involved. When debugging,
the ADB server is involved. When any communication with a device happens, the
ADB server is involved!

‹‹

A client running on your workstation and communicating with devices through the
ADB server. The ADB client is what we interacted with to list devices.

ADB offers many useful options among which some are in the following table:
Command
adb help

Description

adb bugreport

To print the whole device state

adb devices

To list all Android devices currently
connected including emulators

adb install [-r] 

To install an application package. Append
-r to reinstall an already deployed
application and keep its data

adb kill-server

To terminate the ADB daemon

adb pull  

To transfer a file to your computer

adb push  

To transfer a file to your device or
emulator

adb reboot

To restart an Android device
programmatically

adb shell

To start a shell session on an Android
device (more on this in Chapter 2, Starting
a Native Android Project)

adb start-server

To launch the ADB daemon

adb wait-for-device

To sleep until a device or emulator is
connected to your computer (for example,
in a script)

To get an exhaustive help with all options
and flags available

[ 42 ]

Chapter 1

ADB also provides optional flags to target a specific device when several are connected
simultaneously:
-s 

To target a specific device by its name (device name can
be found with adb devices)

-d

To target the current physical device if only one is
connected (or an error message is raised)

-e

To target the currently running emulator if only one is
connected (or an error message is raised)

For example, to dump the emulator state when a device is connected at the same time,
execute the following command:
adb -e bugreport

This is only an overview of what ADB can do. More information can be found on the Android
developer website at http://developer.android.com/tools/help/adb.html.

Summary
Setting up our Android development platform is a bit tedious but is hopefully performed
once and for all!
In summary, we installed all the prerequisite packages on our system. Some of them are
specific to the target OS, such as Cygwin on Windows, Developer Tools on OS X, or buildessential packages on Linux. Then, we installed the Android Studio bundle, which contains
both the Android Studio IDE and the Android SDK. The Android NDK has to be downloaded
and set up separately.
Even if we will not use it much throughout this book, Android Studio remains one of the best
choices for pure Java development. It is guaranteed to be maintained by Google and may
become a good choice when Gradle NDK's integration gets more mature.
Meanwhile, the simplest solution is to go with Eclipse for NDK development. We installed
Eclipse with the ADT and CDT plugin. These plugins integrate well together. They allow
combining the power of Android Java and native C/C++ code into one single IDE.

[ 43 ]

Setting Up Your Environment

Finally, we launched an Android emulator and connected an Android device to our
development platform through the Android Debug Bridge.
With the Android NDK being "open", anybody can build its own version. The
Crystax NDK is a special NDK package built by Dmitry Moskalchuk. It brings
advanced features unsupported by the NDK (latest toolchains, Boost out
of the box… exceptions were first supported by the CrystaxNDK). Advanced
users can find it on the Crystax website at https://www.crystax.
net/en/android/ndk.

We now have the necessary tools in our hands to shape our mobile ideas. In the next
chapter, we will tame them to create, compile, and deploy our first Android project!

[ 44 ]

2

Starting a Native Android Project
A man with the most powerful tools in hand is unarmed without the knowledge
of their usage. Make, GCC, Ant, Bash, Eclipse…—any new Android programmer
needs to deal with this technological ecosystem. Luckily, some of these names
may already sound familiar. Indeed, Android is based on many open source
components, laid together by the Android Development Kits and their specific
tool-set: ADB, AAPT, AM, NDK-Build, NDK-GDB... Mastering them will give us
the power to create, build, deploy and debug our own Android applications.

Before diving deeper into native code in the next chapter, let's discover these tools by
starting a new concrete Android project that includes native C/C++ code. Despite Android
Studio being the new official Android IDE, its lack of support for native code encourages us
to focus mainly on Eclipse.
Therefore, in this chapter, we are going to:
‹‹

Build an official sample application and deploy it on an Android device

‹‹

Create our first native Android project using Eclipse

‹‹

Interface Java with C/C++ using Java Native Interfaces

‹‹

Debug a native Android application

‹‹

Analyze a native crash dump

‹‹

Set up a Gradle project with native code

By the end of this chapter, you should know how to start a new native Android project on
your own.

[ 45 ]

Starting a Native Android Project

Building NDK sample applications
The simplest way to get started with your new Android development environment is to
compile and deploy some of the samples provided with the Android NDK. A possible (and
polygonful!) choice is the San Angeles demo, created in 2004 by Jetro Lauha and later
ported to OpenGL ES (more information at http://jet.ro/visuals/4k-intros/sanangeles-observation/).

Time for action – compiling and deploying San Angeles sample
Let's use Android SDK and NDK tools to build a working APK:

1.

Open a command-line prompt and go to the San Angeles sample directory inside the
Android NDK. All further steps have to be performed from this directory.
Generate San Angeles project files with the android command:
cd $ANDROID_NDK/samples/san-angeles
android update project -p ./

You may get the following error upon executing this command:
Error: The project either has no target set or the target is
invalid.
Please provide a --target to the 'android update' command.

This means that you have not installed all the Android SDK platforms as specified
in Chapter 1, Setting Up Your Environment. In which case, either install them
using the Android manager tool or specify your own project target, for
example, android update project --target 18 -p ./.

[ 46 ]

Chapter 2

2.

Compile San Angeles native library with ndk-build:

3.

Build and package San Angeles application in Debug mode:
ant debug

[ 47 ]

Starting a Native Android Project

4.

Make sure your Android device is connected or the emulator is started. Then deploy
the generated package:
ant installd

5.

Launch SanAngeles application on your device or emulator:
adb shell am start -a android.intent.action.MAIN -n
com.example.SanAngeles/com.example.SanAngeles.DemoActivity

Downloading the example code
You can download the example code files from your account at
http://www.packtpub.com for all the Packt Publishing
books you have purchased. If you purchased this book
elsewhere, you can visit http://www.packtpub.com/
support and register to have the files e-mailed directly to you.

[ 48 ]

Chapter 2

What just happened?
The old-school San Angeles demo, full of flat-shaded polygons and nostalgia, is now running
on your device. With only a few command lines, involving most of the tools needed for the
Android development, a full application including native C/C++ code has been generated,
compiled, built, packaged, deployed, and launched.

Let's see this process in detail.

Generating project files with Android manager
We generated project files from an existing code base thanks to the Android manager. The
following bullet points give more information regarding this process:
‹‹

build.xml: This is the Ant file that describes how to compile and package the
final application APK file (which stands for Android PacKage). This build file contains
mainly links to properties and core Android Ant build files.

‹‹

local.properties: This file contains the Android SDK location. Every time your

SDK location changes, this file should be regenerated.
‹‹

proguard-project.txt: This file contains a default configuration for Proguard,
a code optimizer and obfuscator for Java code. More information about it can be
found at http://developer.android.com/tools/help/proguard.html.

[ 49 ]

Starting a Native Android Project
‹‹

project.properties: This file contains the application target Android SDK
version. This file is generated by default from a pre-existing default.properties
file in the project directory. If no default.properties exists, then an
additional –target  flag (for example, --target 4 for Android 4
Donut) must be appended to the android create command.
Target SDK version is different from the minimum SDK version. The first
version describes the latest Android version for which an application
is built, whereas the latter indicates the minimum Android version on
which the application is allowed to run. Both can be declared optionally
in AndroidManifest.xml file (clause ) but only the
target SDK version is "duplicated" in project.properties.

When creating an Android application, choose carefully the minimum
and target Android API you want to support, as this can dramatically
change your application capabilities as well as your audience wideness.
Indeed, as a result of fragmentation, targets tend to move a lot and
faster in Android!
An application that does not target the latest Android version does not
mean it will not run on it. However, it will not have access to all the
latest features nor all of the latest optimizations.

The Android manager is the main entry point for an Android developer. Its responsibilities
are bound to SDK version updates, virtual devices management, and projects management.
They can be listed exhaustively from the command line by executing android –help.
Since we have already looked at SDK and AVD management in Chapter 1, Setting Up Your
Environment, let's focus on its project management capabilities:
1. android create project allows creating new Android projects ex-nihilo from
the command line. Generated projects contain only Java files but no NDK-related
files. A few additional options must be specified to allow for proper generation,
such as:
Option
-a

Description

-k

Application package

-n

Project name

-p

Project path

-t

Target SDK version

-g and -v

To generate Gradle build file instead of
Ant and specifying its plugin version

Main activity name

[ 50 ]

Chapter 2

An example of command line to create a new project is as follows:
android create project -p ./MyProjectDir -n MyProject -t android-8
-k com.mypackage -a MyActivity

2. android update project creates project files from existing sources, as shown in
the previous tutorial. However, if they already exist it can also upgrade the project
target to new SDK versions (that is, the project.properties file) and update the
Android SDK location (that is, the local.properties file). The available flags are
slightly different:
Option
-l

Description

-n

Project name

-p

Project path

-t

Target SDK version

-s

To update projects in subfolders

Library projects to add

We can also append a new library project with the -l flag, for example:
android update project -p ./ -l ../MyLibraryProject

3. android create lib-project and android update lib-project manage
library projects. These kinds of projects are not well adapted for native C/C++
development, especially when it comes to debugging, since NDK has its own way of
reusing native libraries.
4. android create test-project, android update test-project, and
android create uitest-project manage unit test and UI test projects.
More details about all these options can be found on the Android developer website at
http://developer.android.com/tools/help/android.html.

Compiling native code with NDK-Build
After generating project files, we then compile our first native C/C++ library (also called
module) using ndk-build. This command, the most essential one to know for NDK
development, is basically a Bash script, which:
‹‹

Sets up the Android native compilation toolchain based on either GCC or CLang.

‹‹

Wraps Make to control native code construction with the help of user-defined
Makefiles: Android.mk and optional Application.mk. By default, NDK-

‹‹

Build looks for in the jni project directory, where native C/C++ are often located
by convention.
[ 51 ]

Starting a Native Android Project

NDK-Build generates intermediate object files from C/C++ source files (in the obj directory)
and produces the final binary library (.so) in the libs directory. NDK-related build files can
be erased with the following command:
ndk-build clean

For more information about NDK-Build and Makefiles, see Chapter 9, Porting Existing
Libraries to Android.

Building and packaging an application with Ant
An Android application is not composed of native C/C++ code only, but also of Java code.
Thus, we have:
‹‹

Built Java sources located in the src directory with Javac(Java Compiler).

‹‹

Dexed generated Java bytecode, that is, transforming it into Android Dalvik or ART
bytecode with DX. Indeed, both Dalvik and ART Virtual Machines (more about these
later in this chapter) operate on a specific bytecode, which is stored in an optimized
format called Dex.

‹‹

Packaged Dex files, Android manifest, resources (images, and so on), and
native libraries in the final APK file with AAPT, also known as the Android Asset
Packaging Tool.

All these operations are summarized in one call to Ant: ant debug. The result is an APK
packaged in debug mode and generated in the bin directory. Other build modes are
available (for example, release mode) and can be listed with ant help. If you would like to
erase temporary Java-related build files (for example, the Java .class), then simply run
the following command line:
ant clean

Deploying an application package with Ant
A packaged application can be deployed as is with Ant through ADB. The available options
for deployment are as follows:
‹‹

ant installd for debug mode

‹‹

ant installr for release mode

Beware that an APK cannot overwrite an older APK of the same application if they come
from a different source. In such a case, remove the previous application first by executing
the following command line:
ant uninstall

[ 52 ]

Chapter 2

Installation and uninstallation can also be performed directly through ADB, for example:
‹‹

adb install : For installing an application for the first
time (for example, bin/DemoActivity-debug.apk for our sample).

‹‹

adb install -r : For reinstalling an application and to

keep its data stored on the device.
‹‹

adb uninstall : For uninstalling an application
identified by its Application package name (for example, com.example.
SanAngeles for our sample).

Launching an application with ADB Shell
Finally, we launched the application thanks to the Activity Manager (AM). AM command
parameters that are used to start San Angeles come from the AndroidManifest.xml file:
‹‹

com.example.SanAngeles is the application package name (the same we use to
uninstall an application as previously shown).

‹‹

com.example.SanAngeles.DemoActivity is the launched Activity canonical
class name (that is, a simple class name concatenated to its package). Here is a brief
example of how these are used:


...


Because it is located on your device, AM needs to be run through ADB. To do so, the latter
features a limited Unix-like shell, which features some classic commands such as ls, cd, pwd,
cat, chmod, or ps as well as a few Android specific ones as shown in the following table:
am

The Activity Manager which not only starts Activities but
can also kill them, broadcast intent, start/stop profiler, and
so on.

dmesg

To dump kernel messages.

dumpsys

To dump the system state.

logcat

To display device log messages.

[ 53 ]

Starting a Native Android Project

run-as  

To run a command with the user id privilege. user
id can be an application package name, which gives
access to application files (for example, run-as com.
example.SanAngeles ls).

sqlite3 

To open an SQLite Database (it can be combined with
run-as).

ADB can be started in one of the following ways:
‹‹

With a command in parameter, as shown in step 5 with AM, in which case Shell runs
a single command and immediately exits.

‹‹

With the adb shell command without a parameter, in which case you can use it as
a classic Shell (and, for example, call am and any other command).

ADB Shell is a real 'Swiss Army knife', which allows advanced manipulations on your device,
especially with the root access. For example, it becomes possible to observe applications
deployed in their "sandbox" directory (that is, the /data/data directory) or to list and kill
the currently running processes. Without root access to your phone, possible actions are
more limited. For more information, have a look at http://developer.android.com/
tools/help/adb.html.
If you know a bit about the Android ecosystem, you may have heard about
rooted phones and non-rooted phones. Rooting a phone means getting
administrative privilege, generally using hacks. Rooting a phone is useful to
install a custom ROM version (optimized or modified, for example, Cyanogen)
or to perform any sort of (especially dangerous) manipulations that a root
user can do (for example, accessing and deleting any file). Rooting is not an
illegal operation as such, as you are modifying YOUR device. However, not all
manufacturers appreciate this practice, which usually voids the warranty.

More about Android tooling
Building San Angeles sample application gives you a glimpse of what Android tools can do.
However, behind their somewhat 'rustic' look, more is possible. Information can be found
on the Android developer website at http://developer.android.com/tools/help/
index.html.

[ 54 ]

Chapter 2

Creating your first native Android project
In the first part of the chapter, we saw how to use Android command-line tools. However,
developing with Notepad or VI is not really attractive. Coding should be fun! And to make
it so, we need our preferred IDE to perform boring or unpractical tasks. So now we will see
how to create a native Android project using Eclipse.
The resulting project is provided with this book under the
name Store_Part1.

Time for action – creating a native Android project
Eclipse provides a wizard to help us set up our project:

1.
2.

Launch Eclipse. In the main menu, go to File | New | Project….

3.

In the next screen, enter project properties as follows and click on Next again:

Then, in the opened New project wizard, go to Android | Android Application
Project and click on Next.

[ 55 ]

Starting a Native Android Project

4.

Click on Next twice, leaving default options, to go to the Create activity wizard
screen. Select Blank activity with Fragment and click on Next.

5.

Finally, in the Blank Activity screen, enter activity properties as follows:

6.

Click on Finish to validate. After a few seconds, the wizard disappears and the
project Store is displayed in Eclipse.

7.

Add native C/C++ support to the project. Select the project Store in the Package
Explorer view and from its right-click context menu, go to Android Tools | Add
Native Support....

8.

In the opened Add Android Native Support popup, set the library name to
com_packtpub_store_Store and click on Finish.

[ 56 ]

Chapter 2

9.

The jni and obj directories are created in the project directory. The first directory
contains one makefile Android.mk and one C++ source file com_packtpub_
store_Store.cpp.
After adding native support, Eclipse may automatically switch
your perspective to C/C++. Therefore, in case your development
environment does not look as usual, simply check your perspective
in the Eclipse's top-right corner. You can work on an NDK project
from either a Java or C/C++ perspective without any trouble.

10.

Create a new Java class Store in src/com/packtpub/store/Store.java. From
within a static block, load the com_packtpub_store_Store native library:
package com.packtpub.store;
public class Store {
static {
System.loadLibrary("com_packtpub_store_Store");
}
}

11.

Edit src/com/packtpub/store/StoreActivity.java. Declare and initialize
a new instance of Store in activity's onCreate(). Since we do not need them,
remove the onCreateOptionsMenu() and onOptionsItemSelected()
methods that may have been created by the Eclipse project creation wizard:
package com.packtpub.store;
...
public class StoreActivity extends Activity {
private Store mStore = new Store();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_store);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container,
new PlaceholderFragment())
.commit();
}

[ 57 ]

Starting a Native Android Project
}
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_store,
container, false);
return rootView;
}
}
}

12.

Connect your device or emulator and launch the application. Select Store in the
Package Explorer view and then navigate to Run | Run As | Android Application
from the Eclipse main menu. Alternatively, click on the Run button in the
Eclipse toolbar.

13.

Select the application type Android Application and click on OK to get the
following screen:

[ 58 ]

Chapter 2

What just happened?
In only a few steps, our first native Android project has been created and launched thanks
to Eclipse.
1. The Android project creation wizard helps get you started quickly. It generates the
minimum code for a simple Android application. However, by default, new Android
projects support Java and only Java.
2. With the help of ADT, an Android Java project is easily turned into a hybrid project
with native C/C++ support. It generates the minimum files necessary for an
NDK-Build to compile a native library:
Android.mk is a Makefile describing which source files to compile and how to

generate the final native library.
com_packtpub_store_Store.cpp is an almost empty file containing a single

include. We are going to explain this in the next part of this chapter.
3. Once the project is set up, dynamically loading a native library is done in a single
call to System.loadLibrary(). This is easily done in a static block, which ensures
that the library is loaded once and for all, before a class is initialized. Beware that
this works only if the container class is loaded from a single Java ClassLoader (which
is usually the case).
Working with an IDE like Eclipse really offers a huge productivity boost and makes
programming much more comfortable! But if you are a command-line aficionado or would
like to train your command-line skills, the first part, Building NDK sample applications, can
easily be applied here.

Introducing Dalvik and ART
It is not possible to talk about Android without mentioning a few words about Dalvik
and ART.
Dalvik is a Virtual Machine on which the Dex bytecode is interpreted (not native code!). It
is at the core of any application running on Android. Dalvik has been conceived to fit the
constrained requirements of mobile devices. It is specifically optimized to use less memory
and CPU. It sits on top of the Android kernel, which provides the first layer of abstraction
over the hardware (process management, memory management, and so on).

[ 59 ]

Starting a Native Android Project

ART is the new Android runtime environment, which has replaced Dalvik since the Android
5 Lollipop. It has improved performances a lot compared to Dalvik. Indeed, where Dalvik
interprets bytecode Just-In-Time upon application startup, ART, on the other hand,
precompiles bytecode Ahead-Of-Time into native code during application installation. ART
is backward compatible with applications packaged for former Dalvik VMs.
Android has been designed with speed in mind. Because most users do not want to
wait for their application to be loaded while others are still running, the system is able
to instantiate multiple Dalvik or ART VMs quickly, thanks to the Zygote process. Zygote,
(whose name comes from the very first biologic cell of an organism from which daughter
cells get reproduced), starts when the system boots up. It preloads (or "warms up") all
core libraries shared among applications as well as the Virtual Machine instance. To launch
a new application, Zygote is simply forked and the initial Dalvik instance gets copied as a
consequence. Memory consumption is lowered by sharing as many libraries as possible
between processes.
Dalvik and ART are themselves made of native C/C++ code compiled for the target Android
platform (ARM, X86, and so on). This means that interfacing these VMs with native C/C++
libraries is easily possible provided that it is compiled with the same Application Binary
Interface (ABI) (which basically describes the application or library binary format). This is
the role devoted to the Android NDK. For more information, have a look at the Android
Open Source Project (AOSP), that is, the Android source code at https://source.
android.com/.

Interfacing Java with C/C++
Native C/C++ code has the ability to unleash the power of your application. To do so, Java
code needs to invoke and run its native counterpart. In this part, we are going to interface
Java and native C/C++ code together.
The resulting project is provided with this book under the
name Store_Part2.

[ 60 ]

Chapter 2

Time for action – calling C code from Java
Let's create our first native method and call it from the Java side:

1.

Open src/com/packtpub/store/Store.java and declare one native method
to query the Store. This method returns int with the number of entries in it. There
is no need to define a method body:
package com.packtpub.store;
public class Store {
static {
System.loadLibrary("com_packtpub_store_Store");
}
public native int getCount();
}

2.

Open src/com/packtpub/store/StoreActivity.java and initialize the store.
Use its getCount() method value to initialize the application title:
public class StoreActivity extends Activity {
...
public static class PlaceholderFragment extends Fragment {
private Store mStore = new Store();
...
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_store,
container, false);
updateTitle();
return rootView;
}
private void updateTitle() {
int numEntries = mStore.getCount();
getActivity().setTitle(String.format("Store (%1$s)",
numEntries));
}
}
}

[ 61 ]

Starting a Native Android Project

3.

Generate a JNI header file from the Store class. Go to the Eclipse main menu and
go to Run | External Tools | External Tools Configurations…. Create a new Program
configuration with the following parameters described in the following screenshot:

Location refers to the javah absolute path, which is OS specific. On Windows, you
can enter ${env_var:JAVA_HOME}\bin\javah.exe. On Mac OS X and Linux, it is
usually /usr/bin/javah.

4.

In the Refresh tab, check Refresh resources upon completion and select Specific
resources. Using the Specify Resources… button, select the jni folder. Finally, click
on Run to execute javah. A new file jni/com_packtpub_store_Store.h will
then be generated. This contains a prototype for the native method getCount()
expected on the Java side:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_packtpub_store_Store */
#ifndef _Included_com_packtpub_store_Store

[ 62 ]

Chapter 2
#define _Included_com_packtpub_store_Store
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:
com_packtpub_store_Store
* Method:
getCount
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_packtpub_store_Store_getCount
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

5.

We can now implement jni/com_packtpub_store_Store.cpp so that it returns
0 when invoked. The method signature originates from the generated header file
(you can replace any previous code) except that the parameter names have been
explicitly specified:
#include "com_packtpub_store_Store.h"
JNIEXPORT jint JNICALL Java_com_packtpub_store_Store_getCount
(JNIEnv* pEnv, jobject pObject) {
return 0;
}

6.

Compile and run the application.

What just happened?
Java now talks C/C++! In the previous part, we created a hybrid Android project. In this part,
we interfaced Java with native code. This cooperation is established through Java Native
Interfaces (JNI). JNI is the bridge, which binds Java to C/C++. This occurs in three main steps.
Defining native method prototypes on the Java side, marked with the native keyword.
Such methods have no body, like an abstract method, because they are implemented on
the native side. Native methods can have parameters, a return value, visibility (private,
protected, package protected, or public), and can be static: such as the usual Java methods.

[ 63 ]

Starting a Native Android Project

Native methods can be called from anywhere in Java code, provided that containing a native
library has been loaded before they are called. Failure to do so results in an exception of type
java.lang.UnsatisfiedLinkError, which is raised when the native method is invoked
for the first time.
Using javah to generate a header file with corresponding native C/C++ prototypes. Although
it is not compulsory, the javah tool provided by the JDK is extremely useful to generate
native prototypes. Indeed, the JNI convention is tedious and error-prone (more about this in
Chapter 3, Interfacing Java and C/C++ with JNI). The JNI code is generated from the .class
file, which means your Java code must be compiled first.
Writing native C/C++ code implementation to perform expected operations. Here, we
simply return 0 when the Store library is queried. Our native library is compiled in the
libs/armeabi directory (the one for ARM processors) and is named libcom_packtpub_
store_Store.so. Temporary files generated during compilation are located in the obj/
local directory.
Despite its apparent simplicity, interfacing Java with C/C++ is much more involved than what
it seems superficially. How to write JNI code on the native side is explored in more detail in
Chapter 3, Interfacing Java and C/C++ with JNI.

Debugging native Android applications
Before diving deeper into JNI, there is one last important tool that any Android developer
needs to know how to use: the Debugger. The official NDK one is the GNU Debugger also
known as GDB.
The resulting project is provided with this book under the
name Store_Part3.

Time for action – debugging a native Android application
1.

Create file jni/Application.mk with the following content:
APP_PLATFORM := android-14
APP_ABI := armeabi armeabi-v7a x86

These are not the only ABIs provided by the NDK; more processor
architectures such as MIPS or variants such as 64 bits or hard
floats exist. The ones used here are the main ones you should be
concerned with. They can easily be tested on an emulator.

[ 64 ]

Chapter 2

2.

Open Project Properties, go to C/C++ Build, uncheck Use default build command
and enter ndk-build NDK_DEBUG=1:

3.

In jni/com_packtpub_store_Store.cpp, place a breakpoint inside the
Java_com_packtpub_store_Store_getCount()method by double-clicking
on the Eclipse editor gutter.
Select the Store project in the Package Explorer or Project Explorer view and go to
Debug As | Android Native Application. The application starts, but you will probably
find that nothing happens. Indeed, the breakpoint is likely to be reached before the
GDB Debugger could attach to the application process.

4.

[ 65 ]

Starting a Native Android Project

5.

Leave the application and reopen it from your device application menu. This time,
Eclipse stops at the native breakpoint. Look at your device screen. The UI should be
frozen because the main application thread is paused in native code.

6.

Inspect variables in the Variables view and check the call stack in the Debug view. In
the Expressions view, enter *pEnv.functions and open result expression to see
the various functions provided by the JNIEnv object.

7.

Step Over current instruction from the Eclipse toolbar or with the shortcut,
F6 (you can also use Step Into with the shortcut, F7). The following instructions
will be highlighted:
‰‰

‰‰

Resume the execution from the Eclipse toolbar or with the shortcut, F8.
The application screen is displayed on your device again.
Terminate the application from the Eclipse toolbar or with the shortcut,
Ctrl+F2. The application is killed and the Debug view is emptied.

What just happened?
This useful productivity tool that is a debugger is now an asset in our toolbox. We can
easily stop or resume program execution at any point, step into, over or out of native
instructions, and inspect any variable. This ability is made available to developers thanks to
NDK-GDB, which is a wrapper script around the command-line debugger GDB (which can be
cumbersome to use by hand). Hopefully, GDB is supported by Eclipse CDT and by extension
Eclipse ADT.

[ 66 ]

Chapter 2

On Android, and more generally on embedded devices, GDB is configured in client/server
mode, while a program runs on a device as a server (gdbserver, which is generated by
NDK-Build in the libs directory). A remote client, that is, a developer's workstation with
Eclipse, connects and sends remote debugging commands to it.

Defining NDK application-wide settings
To help NDK-Build and NDK-GDB do their work, we created a new Application.mk file.
This file should be considered as a global Makefile defining application-wide compilation
settings, such as the following:
‹‹

APP_PLATFORM: Android API that the application targets. This information should
be a duplication of minSdkVersion in the AndroidManifest.xml file.

‹‹

APP_ABI: CPU architectures that the application targets. An Application Binary
Interface specifies the binary code format (instruction set, calling conventions, and
so on) that makes executable and library binaries. ABIs are thus strongly related to
processors. ABI can be tweaked with additional settings such as LOCAL_ARM_CODE.

The main ABIs that are currently supported by the Android NDK are as shown in the
following table:
armeabi

This is the default option, which should be compatible with all
ARM devices. Thumb is a special instruction set that encodes
instructions on 16 bits instead of 32 to improve code size
(useful for devices with constrained memory). The instruction
set is severely restricted compared to ArmEABI.

armeabi

(Or Arm v5) Should run on all ARM devices. Instructions are
encoded on 32 bits but may be more concise than Thumb
code. Arm v5 does not support advanced extensions such as
floating point acceleration and is thus slower than Arm v7.

with LOCAL_ARM_CODE = arm
armeabi-v7a

Supports extensions such as Thumb-2 (similar to Thumb
but with additional 32-bit instructions) and VFP, plus some
optional extensions such as NEON. Code compiled for Arm V7
will not run on Arm V5 processors.

armeabi-v7a-hard

This ABI is an extension of the armeabi-v7a that supports
hardware floats instead of soft floats.

arm64-v8a

This is dedicated to the new 64-bit processor architecture.
64-bit ARM processors are backward compatible with
older ABIs.

[ 67 ]

Starting a Native Android Project

x86 and x86_64

For "PC-like" processor architectures (that is, Intel/AMD).
These are the ABIs used on the emulator in order to get
hardware acceleration on a PC. Although most Android
devices are ARM, some of them are now X86-based. The
x86 ABI is for 32-bit processors and x86_64 is for 64-bit
processors.

mips and mips 64

For processors made by MIPS Technologies, now property
of Imagination Technologies well-known for the PowerVR
graphics processors. Almost no device uses these at the time
of writing this book. The mips ABI is for 32-bit processors and
mips64 is for 64-bit processors.

all, all32 and all64

This is a shortcut to build an ndk library for all 32-bit or
64-bit ABIs.

Each library and intermediate object file is recompiled for each ABI. They are stored in their
own respective directory which can be found in the obj and libs folders.
A few more flags can be used inside Application.mk. We will discover more about this in
detail in Chapter 9, Porting Existing Libraries to Android.
The Application.mk flags are not the only ones necessary to ensure the NDK debugger
work; NDK_DEBUG=1 must also be passed manually to NDK-Build so that it compiles Debug
binaries and generates GDB setup files (gdb.setup and gdbserver) correctly. Note that
this should probably be considered more as a defect in Android development tools rather
than a real configuration step, since it should normally handle the debugging flag
automatically.

NDK-GDB day-to-day
Debugger support in the NDK and Eclipse is quite recent and has improved a lot among NDK
releases (for example, debugging purely native threads was not working before). However,
although it is now quite usable, debugging on Android can sometimes be buggy, unstable,
and rather slow (because it needs to communicate with the remote Android device).
NDK-GDB might sometimes appear crazy and stop at a breakpoint with a
completely unusual stack trace. This could be related to GDB not being able
to correctly determine current ABI while debugging. To fix this issue, put
only your corresponding device ABI in the APP_ABI clause and remove or
comment any other.

[ 68 ]

Chapter 2

NDK Debugger can also be tricky to use, such as when debugging native startup code.
Indeed, GDB does not start fast enough to activate breakpoints. A simple way to overcome
this problem is to make native code sleep for a few seconds when an application starts. To
leave GDB enough time to attach an application process, we can do, for example,
the following:
#include 
…
sleep(3); // in seconds.

Another solution is to launch a Debug session and then simply leave and re-launch the
application from your device, as we have seen in the previous tutorial. This is possible
because the Android application life cycle is such that an application survives when it is in
the background, until the memory is needed. This trick only works if your application does
not crash during startup though.

Analyzing native crash dumps
Every developer has one day experienced an unexpected crash in its application. Do not be
ashamed, it has happened to all of us. And as a newcomer in Android native development,
this situation will happen again, many times. Debuggers are a tremendous tool to look for
problems in your code. Sadly, however they work in "real-time", when a program runs. They
become sterile with fatal bugs that cannot be reproduced easily. Hopefully, there is a tool for
that: NDK-Stack. NDK-Stack helps you read a crash dump to analyze an application's stacktrace at the moment it crashed.
The resulting project is provided with this book under the
name Store_Crash.

Time for action – analyzing a native crash dump
Let's make our application crash to see how to read a crash dump:

1.

Simulate a fatal bug in jni/com_packtpub_store_Store.cpp:
#include "com_packtpub_store_Store.h"
JNIEXPORT jint JNICALL Java_com_packtpub_store_Store_getCount
(JNIEnv* pEnv, jobject pObject) {
pEnv = 0;
return pEnv->CallIntMethod(0, 0);
}

[ 69 ]

Starting a Native Android Project

2.

Open the LogCat view in Eclipse, select the All Messages (no filter) option, and then
run the application. A crash dump appears in the logs. This is not pretty! If you look
carefully through it, you should find a backtrace section with a snapshot of the
call-stack at the moment the application crashed. However, it does not give the line
of code involved:

3.

From a command-line prompt, go to the project directory. Find the line of code
implied in the crash by running NDK-Stack with logcat as the input. NDK-Stack
needs the obj files corresponding to the device ABI on which the application
crashed, for example:
cd 
adb logcat | ndk-stack -sym obj/local/armeabi-v7a

[ 70 ]

Chapter 2

What just happened?
NDK-Stack utility provided with the Android NDK can help you locate the source of an
application crash. This tool is an inestimable help and should be considered as your first-aid
kit when a bad crash happens. However, if it can point you toward the where, it is another
kettle of fish to find out the why.
Stack-trace is only a small part of a crash dump. Deciphering the rest of a dump is rarely
necessary but understanding its meaning is good for general culture.

Deciphering crash dumps
Crash dumps are not only dedicated to overly talented developers seeing a red-dressed girl
in binary code, but also to those who have a minimum knowledge of assemblers and the
way processors work. The goal of this trace is to give as much information as possible on the
current state of the program at the time it crashed. It contains:
‹‹

1st line: Build Fingerprint is a kind of identifier indicating the device/Android release
currently running. This information is interesting when analyzing dumps from
various origins.

‹‹

3rd line: The PID or process identifier uniquely identifies an application on the Unix
system, and the TID, which is the thread identifier. The thread identifier can be the
same as the process identifier when a crash occurs on the main thread.

‹‹

4th line: The crash origin represented as a Signal is a classic segmentation
fault (SIGSEGV).

[ 71 ]

Starting a Native Android Project
‹‹

Processor Register values. A register holds values or pointers on which the
processor can work immediately.

‹‹

Backtrace (that is the stack-trace) with the method calls that lead to the crash.

‹‹

Raw stack is similar to the backtrace but with stack parameters and variables.

‹‹

Some Memory Words around the main register (provided for ARM processors only).
The first column indicates memory-line locations, while others columns indicate
memory values represented in hexadecimal.

Processor registers are different between processor architectures and versions. ARM
processors provide:
rX

Integer Registers where a program puts values it works on.

dX

Floating Point Registers where a program puts values it works on.

fp (or r11)

Frame Pointer holds the current stack frame location during a routine call (in
conjunction with the Stack Pointer).

ip (or r12)

Intra Procedure Call Scratch Register may be used with some sub-routine calls;
for example, when the linker needs a veneer (a small piece of code) to aim at a
different memory area when branching. Indeed, a branch instruction to jump
somewhere else in memory requires an offset argument relative to the current
location, allowing a branching range of a few MB only, not the full memory.

sp (or r13)

Stack Pointer holds the location of the top of the stack.

lr (or r14)

Link Register saves a program counter value temporarily so that it can restore it
later. A typical example of its use is as a function call, which jumps somewhere in
the code and then goes back to its previous location. Of course, several chained
sub-routine calls require the Link Register to be stacked.

pc (or r15)

Program Counter holds the address of the next instruction to be executed. The
program counter is just incremented when executing a sequential code to fetch
the next instruction but it is altered by branching instructions (if/else, a C/C++
function calls, and so on).

cpsr

Current Program Status Register contains a few flags about the current processor
working mode and some additional bit flags for condition codes (such as N for an
operation that resulted in a negative value, Z for a 0 or equality result, and so on),
interrupts, and instruction sets (Thumb or ARM).
Remember that the use of registers is mainly a convention. For example,
Apple iOS uses r7 as a Frame Pointer instead of r12 on ARMs. So always
be very careful when writing or reusing assembly code!

[ 72 ]

Chapter 2

On the other hand, X86 processors provide:
eax

Accumulator Register is used, for example, for arithmetic or I/O operations.

ebx

Base Register is a data pointer for memory access.

ecx

Counter Register is used for iterative operations such as loop counter.

edx

Data Register is a secondary Accumulator Register used in conjunction with eax.

esi

Source Index Register is used for memory array copying in conjunction with edi.

edi

Destination Index Register is used for memory array copying in conjunction with esi.

eip

Instruction Pointer holds offset of the next instruction.

ebp

Base Pointer holds the current stack frame location during a routine call (in
conjunction with the Stack Pointer).

esp

Stack Pointer holds the location of the top of the stack.

xcs

Code Segment helps in addressing the memory segment in which the program runs.

xds

Data Segment helps addressing a data memory segment.

xes

Extra Segment is an additional register to address a memory segment.

xfs

Additional Segment which is a general purpose data segment.

xss

Stack segment holds the Stack memory segment.
Many X86 registers are a legacy, which means that they lost the
initial purpose they were created for. Take their descriptions with
some caution.

Deciphering stack-traces is not an easy task and requires time and expertise. Don't bother
too much if you do not understand every part of it yet. This is necessary as a last resort only.

Setting up a Gradle project to compile native code
Android Studio is now the new officially supported Android IDE, in place of Eclipse. It comes
with Gradle, which is the new official Android build system. Gradle introduces a Groovy-based
specific language to define the project configuration easily. Although its support of the NDK is
still preliminary, it keeps improving and is becoming more and more useable.
Let's now see how to create an Android Studio project with Gradle that compiles native code.
The resulting project is provided with this book under the
name Store_Gradle_Auto.

[ 73 ]

Starting a Native Android Project

Time for action – creating a native Android project
Gradle-based projects can be created easily through Android Studio:

1.

Launch Android Studio. On the welcome screen, select New Project… (or go to
File | New Project… if a project is already opened).

2.

From the New Project wizard, enter the following configuration and click on Next:

3.

Then, select the minimum SDK (for example, API 14: Ice Scream Sandwich) and click
on Next.

4.
5.

Select Blank Activity with Fragment and click on Next.
Finally, enter Activity Name and Layout Name names as follows and click on Finish:

[ 74 ]

Chapter 2

6.

Android Studio should then open the project:

[ 75 ]

Starting a Native Android Project

7.

Modify StoreActivity.java and create Store.java in the same way as we did
in the Interfacing Java with C/C++ section in this chapter (Step 1 and 2).

8.

Create the app/src/main/jni directory. Copy the C and Header files we created
in the Interfacing Java with C/C++ section in this chapter (Step 4 and 5).

9.

Edit app/build.gradle that has been generated by Android Studio. In
defaultConfig, insert a ndk section to configure the module (that is, a library)
name:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.packtpub.store"
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
ndk {
moduleName "com_packtpub_store_Store"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.
txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}

10.

Compile and install the project on your device by clicking on installDebug in the
Gradle tasks view of Android Studio.

[ 76 ]

Chapter 2

If Android Studio complains that it cannot find the NDK, make
sure the local.properties file in the project's root
directory contains both sdk.dir and ndk.dir properties
that can point to your Android SDK and NDK location.

What just happened?
We created our first Android Studio project that compiles native code through Gradle. NDK
properties are configured in a section specific to ndk in the build.gradle file (for example,
the module name).
Multiple settings are available as shown in the following table:
Property

Description

abiFilter

The list of ABIs to compile for; by default, all.

cFlags

Custom flags to pass to the compiler. More about this in Chapter 9,
Porting Existing Libraries to Android.

ldLibs

Custom flags to pass to the linker. More about this in Chapter 9,
Porting Existing Libraries to Android.

moduleName

This is the name of the module to be built.

stl

This is the STL library to use for compilation. More about this in
Chapter 9, Porting Existing Libraries to Android.

You might have noticed that we have not reused the Android.mk and Application.mk
files. This is because Gradle generates the build files automatically if given an input to ndkbuild at compilation time. In our example, you can see the generated Android.mk for the
Store module in the app/build/intermediates/ndk/debug directory.
NDK automatic Makefile generation makes it easy to compile native NDK code on simple
projects. However, if you want more control on your native build, you can create your own
Makefiles like the ones created in the Interfacing Java with C/C++ section in this chapter.
Let's see how to do this.
The resulting project is provided with this book under the
name Store_Gradle_Manual.

[ 77 ]

Starting a Native Android Project

Time for action – using your own Makefiles with Gradle
Using your own handmade makefiles with Gradle is a bit tricky but not too complicated:

1.

Copy the Android.mk and Application.mk files we created in the Interfacing
Java with C/C++ section in this chapter into the app/src/main/jni directory.

2.
3.

Edit app/build.gradle.
Add an import for the OS "Class" and remove the first ndk section we created in
the previous section:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.packtpub.store"
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.
txt'), 'proguard-rules.pro'
}
}

4.

Still in the android section of app/build.gradle., insert a sourceSets.main
section with the following:
‰‰

‰‰

jniLibs.srcDir, which defines where Gradle will find the
generated libraries.
jni.srcDirs, which is set to an empty array to disable native code

compilation through Gradle.
...
sourceSets.main {
jniLibs.srcDir 'src/main/libs'
jni.srcDirs = []
}

[ 78 ]

Chapter 2

5.

Finally, create a new Gradle task ndkBuild that will manually trigger the
ndk-build command, specifying the custom directory src/main as the
compilation directory.
Declare a dependency between the ndkBuild task and the Java compilation
task to automatically trigger native code compilation:
...
task ndkBuild(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
} else {
commandLine 'ndk-build', '-C', file('src/main').absolutePath
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}

6.

Compile and install the project on your device by clicking on installDebug in the
Gradle tasks view of Android Studio.

What just happened?
The Makefile generation and native source compilation performed by the Android Gradle
plugin can easily be disabled. The trick is to simply indicate that no native source directory is
available. We can then use the power of Gradle, which allows defining easily custom build tasks
and dependencies between them, to execute the ndk-build command. This trick allows using
our own NDK makefiles, giving us more flexibility in the way we build native code.

[ 79 ]

Starting a Native Android Project

Summary
Creating, compiling, building, packaging, and deploying an application project are not
the most exciting tasks, but they cannot be avoided. Mastering them will allow you to be
productive and focused on the real objective: producing code.
In summary, we built our first sample application using command-line tools and deploying
it on an Android device. We also created our first native Android project using Eclipse and
interfaced Java with C/C++ using Java Native Interfaces. We debugged a native Android
application with NDK-GDB and analyzed a native crash dump to find its origin in the source
code. Finally, we created a similar project using Android Studio and built it with Gradle.
This first experiment with the Android NDK gives you a good overview of the way native
development works. In the next chapter, we are going to focus on the code and dive more
deeply into the JNI protocol.

[ 80 ]

3

Interfacing Java and C/C++ with JNI
Android is inseparable from Java. Its kernel and core libraries are native, but
the Android application framework is almost entirely written in Java or at least
wrapped inside a thin layer of Java. Do not expect to build your Android GUI
directly in C/C++! Most APIs are available only from Java. At best, we can hide
it under the cover... Thus, native C/C++ code on Android would be nonsense if it
was not possible to tie Java and C/C++ together.
This role is devoted to the Java Native Interface API. JNI is a standardized
specification allowing Java to call native code and native code to call Java back.
It is a two-way bridge between the Java and native side; the only way to inject
the power of C/C++ into your Java application.
Thanks to JNI, one can call C/C++ functions from Java like any Java method,
passing Java primitives or objects as parameters and receiving them as result
of native calls. In turn, native code can access, inspect, modify, and call Java
objects or raise exceptions with a reflection-like API. JNI is a subtle framework
which requires care as any misuse can result in a dramatic ending…

In this chapter, we will implement a basic key/value store to handle various data types. A
simple Java GUI will allow defining an entry composed of a key (a character string), a type (an
integer, a string, and so on), and a value related to the selected type. Entries are retrieved,
inserted, or updated (remove will not be supported) inside a simple fixed size array of
entries, which will reside on the native side.

[ 81 ]

Interfacing Java and C/C++ with JNI

To implement this project, we are going to:
‹‹

Initialize a native JNI library

‹‹

Convert Java Strings in native code

‹‹

Pass Java primitives to native code

‹‹

Handle Java object references in native code

‹‹

Manage Java Arrays in native code

‹‹

Raise and check Java exceptions in native code.

By the end of this chapter, you should be able perform native calls with any Java type and
use exceptions.
JNI is a very technical framework that requires care, as any misuse can result in a dramatic
ending. This chapter does not pretend to cover it exhaustively but rather focuses on the
essential knowledge to bridge the gap between Java and C++.

Initializing a native JNI library
Before accessing their native methods, native libraries must be loaded through a Java call
to System.loadLibrary(). JNI provides a hook, JNI_OnLoad(), to plug your own
initialization code. Let's override it to initialize our native store.
The resulting project is provided with this book under the
name Store_Part4.

Time for action – defining a simple GUI
Let's create a Java Graphical User Interface for our Store and bind it to the native store
structure that we will create:

1.

Rewrite the res/fragment_layout.xml layout to define the graphical interface
as follows. It defines:
‰‰

A Key TextView label and EditText to enter the key

‰‰

A Value TextView label and EditText to enter the value matching the key

‰‰

A Type TextView label and Spinner to define the type of the value

[ 82 ]

Chapter 3
‰‰

A Get Value and a Set Value Button to retrieve and change a value in
the store


















Source Exif Data:
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.6
Linearized                      : No
Create Date                     : 2015:04:28 16:01:15+05:30
Creator                         : Adobe InDesign CS6 (Windows)
Modify Date                     : 2015:04:28 16:11:54+05:30
XMP Toolkit                     : Adobe XMP Core 5.4-c005 78.147326, 2012/08/23-13:03:03
Instance ID                     : uuid:800f999e-4402-4a70-88bb-fd65aee22956
Original Document ID            : adobe:docid:indd:7c2210fe-d03b-11df-b78d-ab1f91ee47f1
Document ID                     : xmp.id:855894D390EDE411907B97A1144F46A8
Rendition Class                 : proof:pdf
Derived From Instance ID        : xmp.iid:644DBB5A90EDE411907B97A1144F46A8
Derived From Document ID        : xmp.did:D581C88534E7E411A6E6F3540EDECCAA
Derived From Original Document ID: adobe:docid:indd:7c2210fe-d03b-11df-b78d-ab1f91ee47f1
Derived From Rendition Class    : default
History Action                  : converted
History Parameters              : from application/x-indesign to application/pdf
History Software Agent          : Adobe InDesign CS6 (Windows)
History Changed                 : /
History When                    : 2015:04:28 16:01:17+05:30
Metadata Date                   : 2015:04:28 16:11:54+05:30
Creator Tool                    : Adobe InDesign CS6 (Windows)
Format                          : application/pdf
Producer                        : Adobe PDF Library 10.0.1
Trapped                         : False
Page Count                      : 494
EXIF Metadata provided by EXIF.tools

Navigation menu