Android Internals
Mark Veltzer
CTO, Hinbit
mark.veltzer@gmail.com
Who am I?
CTO of Hinbit which is a service company for open
source platforms.
We move people from legacy (Windows, big UNIX)
to future (Linux) platforms.
I do kernel coding, driver development, real time
design and more.
I teach lots of languages and technologies.
Free source (as opposed to open source)
evangelist.
http://veltzer.net, mailto:mark.veltzer@gmail.com
Introduction
We will cover:
Android overview
Smart phones
Android versions
Which version should I develop to?
What makes Android special?
Google Android strategy
Android features
Examples of Android applications
Android Overview
Mobile OS, with middle ware and key applications
based on Linux kernel and open source stack.
Initially developed by Android INC, which was
acquired by Google in 2005, and later by the
Open handset alliance.
Android lets developers write code in the Java
programming language, controlling the mobile
device.
Most of the Android code was released by Google
under the Apache 2 license.
Smart phones
There is no industry definition regarding what a
smart phone is.
The best one is miniature computer which can
also be used as a phone.
Once a phone is used as a computer security
becomes a big concern.
Once a phone is used as a computer reliability
and OS level protection becomes a big concern
(embedded kernels are no longer an option).
Applications, applications
The key to smart phones are the applications.
Much like Bill Gates in the 90's success is
creating a new ecosystem around building
applications to the device.
Backwards compatibility becomes a major
issue if the ecosystem is to thrive.
The higher the programming language, the
easier it is to maintain backwards compatibility.
Other smart phones in the industry
Nokia - Symbian
Research In Motion BlackBerry
Apple IPhone
Microsoft/Nokia Windows Mobile
Other Linux based Operating Systems.
All are protected operating systems
Sales Q4 2010
Android versions
1.5, Cupcake, Apr 2009, API level 3
1.6, Donut, Sep 2009, API level 4
2.0/2.1, Eclair, Jan 2010, API level 7
2.2, Froyo, May 2010, API level 8
2.3, Gingerbread, Dec 2010, API level 9
3.0, Honeycomb, Feb 2011, API level 11
3.1, Honeycomb, Mar 2011, API level 12
3.2, Honeycomb, Apr 2011, API level 13
Version 1.5 - Highlights
User Interface Refinements
System-wide:
Refinement of all core UI elements
Animated window transitions (off by default)
Accelerometer-based application rotation
UI polish for:
In-call experience, Contacts, Call log, Favorites, SMS &
MMS, Browser, Gmail, Calendar, Email, Camera &
Gallery, Application management
Version 1.5 - Highlights
Performance improvements
Faster camera start-up and image capture
Much faster acquisition of GPS location
Smoother page scrolling in Browser
Speedier Gmail conversation list scrolling
New Features
On-screen soft keyboard, Home screen (Widgets,
Live folders), Camera & Gallery, Blue tooth,
Browser, Contacts, System, Google applications.
Version 1.5 - Highlights
New APIs and Manifest Elements:
UI framework
AppWidget framework
Media framework
Input Method framework
Application-defined hardware requirements
Speech recognition framework
Miscellaneous API additions
Platform Highlights:
http://developer.android.com/sdk/android-1.5highlights.html
Version 1.6 - Highlights
New User Features:
Quick Search Box for Android
Camera, Camcorder and Gallery
VPN, 802.1x, allows users to configure and connect to:
L2TP/IPSEC pre-shared key based VPN
L2TP/IPSEC certificate based VPN
L2TP only VPN
PPTP only VPN
Battery usage indicator
Accessibility
Version 1.6 - Highlights
Android Market Updates
Improved overall user experience.
Makes it easier for users to discover apps & games
from developers:
At the home-screen, users can choose among Apps,
Games and Downloads.
Inside a category, users can explore titles that are top
paid, top free and just in.
For each title, users can see screenshots submitted by
developers in addition to reviews by other users.
Version 1.6 - Highlights
New Platform Technologies:
Expanded Search Framework
Text-to-speech engine
Gestures
Accessibility
Expanded support for screen densities and resolutions
Telephony support for CDMA
New version of OpenCore
2.6.29 Linux kernel
New Framework APIs
Platform Highlights: http://developer.android.com/sdk/android1.6-highlights.html
Version 2.0/2.1 - Highlights
New User Features:
Contacts and accounts
Email
Messaging
Camera
Android virtual keyboard
Browser
Calendar
Version 2.0/2.1 - Highlights
New Platform Technologies:
Media Framework
Bluetooth
New Framework APIs
Platform Highlights:
http://developer.android.com/sdk/android-2.0highlights.html
Version 2.2 - Highlights
New User Features:
Home Screen Improved (tips widget,
browser+phone shortcuts)
Exchange Support
Camera Application Improved
Portable Wi-Fi hot spot
Improved Performance
Version 2.2 - Highlights
New Platform Technologies:
Media Framework
Bluetooth, voice dialing and contact sharing
2.6.32 kernel upgrade
Platform Highlights:
http://developer.android.com/sdk/android-2.2highlights.html
Version 2.3 - Highlights
New User Features:
Home Screen Improved (black notification bar)
Improved soft keyboard
Copy and Paste support
Improved power management
Multiple cameras support
Near Field Communication support
Downloads management
Version 2.3 - Highlights
New Platform Technologies:
SIP Stack
New audio/video support (+sound effects)
Support for extra large screen
New sensors support
Concurrent garbage collector
2.6.35 kernel upgrade
Platform Highlight:
http://developer.android.com/sdk/android-2.3highlights.html
Version 3.0 - Highlights
New User Features:
UI designed from the ground up for tablets
System bar for global status and notification
Action Bar for application control
Customizable Home screens
Recent Apps, for easy visual multitasking
Redesigned keyboard
Improved text selection, copy and paste
New connectivity options
Updated set of standard apps
Version 3.0 - Highlights
New Developer Features:
New UI Framework for creating tablet apps
Activity fragments
Resigned UI widgets
Expanded Home Screen widgets
Persistent Action Bar
Richer notification
Multi select, clipboard and Drag-and-drop.
New animation framework
Hardware accelerated 2D graphics
Renderscript 3D graphics engine
Support for multicore processor architectures
Enterprise features
Pluggable DRM framework
Digital media file transfer
Bluetooth connectivity improvements
Platform Highlights: http://developer.android.com/sdk/android-3.0-highlights.html
Version 3.1 - Highlights
New User Features:
UI refinements
Connectivity for USB accessories
Expanded Recent Apps list
Resizeble Home Screen widgets
Support for external keyboards and pointing devices
Support for joysticks and gamepads
Robust wi-fi networking
Updated set of standard apps
Version 3.1 - Highlights
New Developer Features:
Open Accessory API
USB Host API
Input from mice, joysticks and gamepads
Resizable Home Screen widgets
MTP API for external cameras
RTP API for streaming audio
Performance optimizations
Platform Highlights:
http://developer.android.com/sdk/android-3.1highlights.html
Version 3.2 - Highlights
New User Features:
Optimization for a wider range of tablets
Compatibility zoom for fixed-sized apps
Media sync from SD card
New Developer Features:
Extended API for managing screens
Platform Highlights:
http://developer.android.com/sdk/android3.2.html#highlights
Which version should I develop to? distribution
A major factor in the decision is platform
distribution amongst users.
This could be either at the present or
projections about the future (when your project
will be ready).
Statistics could be found at:
http://developer.android.com/resources/dashboard/platform-versions.html
These statistics are collected by Google in real
time and represent the market at any point in
time. You can also see graphs of trends there.
Which version should I develop to? Snapshot
Which version should I develop to? Application vendors
At the Java level the platforms are (mostly)
backwards compatible for application developers.
Application developers would choose the lowest API
level that can carry their application in order to reach
the widest audience.
Testing on all platform should still be conducted but in
practice, for standard applications, is sometimes
skipped for some versions.
Still, newer versions carry new API and performance
and hardware support that may be required by new
applications.
Which version should I develop to? native coders
NDK (user space C/C++ support) is also improving and expanding with each new
version. New codecs are supported, new openGL features, new version of bionic
(important for every native coder) and more.
New versions are much less backwards compatible for native code writers than for
Java application writers.
This partly stems from the fact that C and C++ are worse at backwards compatibility.
Partly because the Android platform cares more about compatibility at the Java layer
(which the majority of it's application coders need) and less about compatibility for
native coders (who are a minority).
Native code writers may choose a version for other reasons. For instance: some C+
+ exception handling for user space was added in version 2.0.
Sometimes native coders would switch versions because some kernel feature is
required and since changing kernel means changing Android version the native
layer switches too.
You may be forced to use #ifdef or other tricks in your code to support multiple
Android versions.
Which version should I develop to? platform vendors
Platform vendors usually want latest since they want
to deliver cutting edge features and outdo their
competition.
Kernel version is very important for platform vendors
since newer kernel versions utilize more hardware
features at the platform level and carry more drivers.
Platform vendors are the most sensitive to Android
version and must compile, test and QA each version.
Because kernel coding is the most sensitive to
changes platform vendors may even have a fork of
their kernel code per Android version.
What makes Android special?
Not tied to a specific hardware platform (this is a benefit
of Linux and the Open Source stack) well, sort of...
Open Source.
Can be modified by the platform vendors.
Development can be tracked by the platform vendors
(well, until latest versions).
Lots of development power split over the industry.
Very high level of abstraction for applications.
Not owned by anyone which makes everyone less
scared to jump aboard.
What makes Android special? (cont)
Allows root access (or at least does not block it).
Is not inherently protected by various DRM mechanisms
(although vendors may choose to use DRM). This makes it
much more user friendly.
Is a much more open platform in terms of application vending.
Is much more open in terms of end user usage (playing mp3
and using Android as USB storage, for example).
Vendors have access, are allowed, and sometimes must,
change the OS kernel to adjust it to new devices, pieces of
hardware and more.
Is based on Linux and therefore keeps advancing at rapid pace
even if Google doesn't put a cent into kernel development.
What makes Android special? - The
killer reasons
Threatens to unify the mobile market like no
other operating system.
Threatens to drive costs of appliances down
down down down like no other operating
system.
Google Android strategy
Some of the services (like Google maps) are money
makers for Google.
Browser is WebKit based which helps Google in the
browser wars (chrome) which, in turn, help Google in
the remote application (cloud) market which also helps
Google in the operating system market (chrome OS)
Part of the idea is to benefit from the tension between
application vendors and the platform makers
Control of popular image, audio and video codecs
(along with you-tube and Picasa) which has patent
and hardware income possibilities.
Android features
Application Framework
Enabling reuse and component placement
Java VM Optimized for Mobile Devices (Dalvik)
Integrated Browser, Based on WebKit.
Like Chrome and Safari
Graphic libraries
SQLite Database
Media support (audio, video, image files)
GSM Telephony
Bluetooth, EDGE, 3D, Wi-Fi
Camera, GPS, Compass, Accelerometer
IDE (Eclipse Based)
Examples of Android applications
Seesmic: twitter application better than twitters
own version
Facebook for Android: obvious
Astro: File management. Really allows you to drag
and drop files.
AppBrain: Allows to queue applications to be
installed on your mobile device from your PC
Google sky map: point it at the sky and it will tell
you what stars you are looking at and stats about
them
Examples of Android applications
(cont)
Foursquare: Twitter on a map.
Wordpress for Android: manage wordpress blogs
from an Android device.
Google googles: show it a photo and it will try to
tell you what you are looking at.
AppMonster: lets you manage your applications
more easily and gives you one click backup of all
your applications to your SD card.
Task Manager/Advanced Task Killer: let you
monitor and kill tasks easily.
Examples of Android applications
(cont)
Evernote: note, image, file or audio note taking
application.
Google Maps Navigation: GPS navigation via
Google maps.
Astrid Task/Todo list: GTD type apps
Skifta: turns your Android phone into an official
DLNA device.
Dropbox: well, dropbox.
Meebo IM: instant messaging.
Examples of Android applications
(cont)
Amazon Kindle: read your Amazon books on
your Android phone or tablet.
RD Mute: shuts your phone up when you've
turned it upside down (uses accelerometer).
EasyTether (paid): lets you use your phone as a
3G modem
Beautiful Widgets (paid): obvious
Vignette (paid): makes the photos you take look
beautiful.
Android Framework
We will cover...
Overview of the Android framework
The Linux kernel at the heart of Android
The NDK Native libraries
The NDK tools
The NDK Native applications
Overview of the Android runtime environment
The Dalvik VM (overview)
The Application framework
What is an Android application?
Android framework
Android Stack Linux kernel
Based on the 2.6 (and now the 3.0) version.
Used for platform/hardware independence (Linux is a portable
operating system)
Security.
Hardware abstraction (/dev).
Networking.
Memory management.
Process management.
Storage and file system.
Driver model.
Standard Android application vendors never access this layer directly.
A few notes about the Linux kernel...
The Linux kernel is not, contrary to public opinion, an
operating system kernel.
It is the source code from which many many many
different operating system kernels can be built, for
many different hardware platforms and many
different end uses...
The difference is huge.
Some kernels that come out from building a Linux
kernel do not even qualify as UNIX systems! (Android is
one, BTW!)
Demo of building the Linux kernel.
Android Stack NDK Native
Libraries
Wraps the kernel API (this is needed since the kernel API is quite hard to deal
with).
Exposes API to the java layer via JNI.
Written in C and C++.
Various abstractions in the form of open source libraries
Bionic: a super fast and small BSD libc library optimized for embedded use.
Surface Manager: for composing window manager with off-screen buffering
2D and 3D graphics using opengl/es: hardware support or software simulation.
SQLite database
Media codecs
webkit (fast HTML rendering engine)
FreeType, font and bitmap rendering.
Lots more
Android Stack NDK tools
The NDK also supplies you the toolchain that
enables you to code native libraries and
executables for the Android target platform.
These tools include gdbserver which enables
you to remote debug an application running on
a remote device/target.
These tools are accompanied by
documentation in the /docs folder.
Android Stack NDK Native
applications
The NDK also include more infrastructure in the
form of native applications (scripts, binaries)
that run in real Android devices and supply core
services on the platform.
Examples could be ueventd (that handles
kernel->userspace events), adbd (that allows
you to inspect and debug the platform), init (that
initializes the system)
Android runtime
The heart is the Dalvik VM which runs the
applications.
Lots of other natives services are also included
like remote access, debugging, logging, event
handling and more.
You can see all of these by using the adb shell
and looking at the processes running on the
android machine.
Dalvik
Google's implementation of a Java virtual machine.
Sun Java has a problematic license and quite on the
heavy side.
One of the most innovative aspects of the Android
platform.
Register based versus stack based.
Leaner byte code.
Runs .dex (Dalvik Executable) files instead of .jar files.
The .dex format was optimized for small memory
footprint.
Dalvik - cont
The set of libraries of Dalvik is much more compact and
targeted for embedded.
Implements the core of the Java programming language
API (IO, Collections and more).
AWT/Swing is gone, new UI framework is in.
Requires another step to compile/translate Java bytecode
to Dalvik bytecode.
Don't worry Eclipse or some other IDE will do this step for
you.
So Dalvik is not a Java compiler (that is too big a job )
This means you can use any Java compiler.
Dalvik - cont
Dalvik relies on the Linux Kernel for underlying
functionality like threading and low-level
memory management
Every Android application runs in it's own VM
process and every application has it's own
Dalvik VM instance. This ensure stability.
This does not consume much ram since all the
Dalvik instances are forks without exec one of
the other which means that in RAM Dalvik lives
only once.
Application framework
Arguably, the most important part of Android.
Mostly Java API that make application development easy.
Many services location manager, resource manager, window
manager, Wi-Fi services, Notification manager for events, GSM
and more
Applications consume these services and may provide their own.
Content providers encapsulate data fetching and provisioning
between applications.
Some content providers are provided out of the box.
As a developer of an Android application you have access to the
same services and the same content providers that the vendors
of the platforms have.
Application framework - cont
Some of the more important components are:
Activity Manager: manages the life cycle of
applications and provides common application
back-stack
Notification Manager: enables all applications to
display alerts in the status bar
Resource Manager: provides access to non-code
resources (strings, graphics, audio/video etc.)
Content Providers: Enable applications to access
data from other applications
Application Layer
Is where your Java based Android applications
live
Contains many built-in applications:
Email, phone, web-browser, calendar, contacts,
home screen and more
The set of built-in application vendors can
change not only between various Android
versions but also between various Android
platform vendors.
The Application framework and the
application vendor code
If you write Android applications the application framework is both on top
of you and below you.
This means that regular UI based Android applications are callback based
which means that the framework is on top of you.
But when you want to do something you call some API which below you.
This API will call some Java code, which will call some C code, which will
call some kernel code, which will access the hardware.
You can run your own threads in an Android application using regular Java
threading API and in your own threads you are the boss (topmost layer).
But this can also lead to problems (how to terminate the thread gracefully,
CPU over utilization) and is not advisable for regular applications.
In any case the platform protects itself from abuse in various ways: allows
users to kill application that consume too many resources,
lowmemorykiller and more.
An Android Application
Is an .apk file
An android market is thousands of apk files made by a
multitude of Android app developers.
Usually generated automatically for you by development
environments. Eclipse+ADT which puts it usually in the bin
folder of your project.
Comprised of 3 things:
Dalvik exe (.dex) which are basically classes.
Resources (strings, layout, icons, xml files, audio, video)
Native libraries (optional)
It is actually a zip file and can be manipulated with zip tools.
The Android Java SDK
We will cover...
A note about Eclipse
Setting up the Environment.
Eclipse Plug-ins
SDK Tools hightlights
A note about Eclipse
Eclipse is not, contrary to public opinion, a development
environment.
Eclipse is a scalable software delivery platform.
One of it's most common incarnations is a Java
development environment.
Every time you are using Eclipse you are using hundreds of
plug-ins made by dozens of organizations and integrated
using the Eclipse framework.
That is also why Android uses Eclipse for development:
Eclipse can be easily customized and most stuff that you
need in a development environment are already in Eclipse.
Setting up the development
environment - basics
If you are going to do NDK or lower level development also then
I recommend Linux as the environment. But for regular Java
applications windows will work just as well (well, at least as well
as Microsoft defines the word well).
You'll need Eclipse versions 3.4, 3.5 or 3.6 (later is usually
better)
Sun's JDK5 or JDK6.
On Linux simply install the relevant packages, for instance on Ubuntu
use:
sudo apt-get install sun-java6-jdk
On Windows download an installer, yes, yes, I agree, reboot, reboot
again, and you're done (reboot just in case).
You can also use openjdk but sun is preferred.
Setting up the development
environment - ADT
ADT Android Development Tools, a special
eclipse plug-in
To install ADT, just use the Eclipse plug-in
installation facility and point it to:
https://dl-ssl.google.com/android/eclipse
If you have no Internet connection download the
plug-in as a zip file and install it as an archive (in
previous versions of eclipse it was better to just
unzip it into the eclipse folder).
Setting up the development
environment - SDK
Download the SDK from:
http://developer.android.com/sdk/index.html and
install it.
The downloaded packages are per platform.
After installation of the SDK tools, run the SDK
setup tool.
Under windows SDK Setup.exe.
Under Linux $SDK/tools/android.
When you first run it it is empty.
Setting up the development
environment SDK empty image
Setting up the development
environment - SDK
Just select the Android repository and install support for the
versions of the Android platforms that you need.
Go drink some coffee.
You can install as many different emulated Android platforms
as you like. These are called AVD (Android Virtual Device).
After installing selected platforms you need to define some
virtual devices.
Each virtual device is based on an Android platform + a few
definitions.
After you have a virtual device just select it and click start to
run it. You will get a phone. It takes some time. Be patient.
You also have to tell ADT where your SDK is at (some
versions of ADT also require that you restart Eclipse after you
do that...).
Setting up the development
environment - SDK
The emulator (first run)
The emulator
During your development you will test your work on an emulator.
The emulator knows how to emulate the entire Android handset or
device with or without additional features like GPS/PC connectivity and
more.
The emulator knows how to emulate different versions of the
Android platform.
Always test your application on several versions of the Android
platform (different emulator setups).
Always test your application on real devices as well this is
especially true if your application is not a pure data application
and has some integration with hardware or with other
application (in the form of content providers for instance).
Deploying to a real device
In order to deploy, run and debug an application on a real
device you'll want to connect to it. This is done via USB.
On the host you will need some USB configuration:
On Windows you will need USB drivers from:
http://developer.android.com/sdk/oem-usb.html
On Linux you don't need drivers but you may need to tweak
permissions of the USB device
http://developer.android.com/guide/developing/device.html#setting-up
On the device/target you will need to:
Allow debugging.
Allow installing applications from unknown sources.
The ADT Eclipse Plug-in
ADT: Android Development Tools
It is a meta eclipse plug-in much like the JDT or CDT.
As of July 2011 it's version is 12.0.0.
Makes Eclipse a development environment for Android
applications.
Add a new Android project project type
Adds an Android XML file editor and creator wizard
Add a WYSIWYG UI design tool
Has DDMS integration which allows you to Debug, profile and
see the logs of your Android applications, both on the
emulator or on a real device.
SDK tools
The Android SDK comes with a large set of
tools
Most of them are at $ANDROID_SDK/tools/*
Emulator: emulates an Android device.
Hierarchy viewer: shows the layout hierarchy of
a user interface in real time.
Draw 9-patch: drawing application for 9-patch
images (images used in the Android UI).
SDK tools (cont)
mksdcard: creates an image to emulate sdcard in the
emulator.
dx: generate Dalvik byte-code from Java byte-code.
aidl: Android Interface definition language tool used to
create remote interfaces for Android application that
want to provide new services on the Android platform.
aapt: asset packaging tool used to create Android
packages.
There are some more tools but the ones covered are
the most important.
IDE
The main tool used to develop Android
application is Eclipse.
With ADT Eclipse becomes a powerful
environment.
ADT adds Android related perspectives, views
and XML editors to Eclipse.
See the demo.
The Emulator
Part of the SDK. Resides in $ANDROID_SDK/tools and is called
emulator.
The idea is for you to be able to run a full Android device without
needing a physical one, as a process in your own operating system.
In order to launch it from the command line you have to give it an AVD
(Android Virtual Device) name: ./tools/emulator my2.2. This requires
you to prepare an AVD beforehand. You can also launch an image
directly (for professionals).
Could also be launched and configured graphically from the android UI
tool in $ANDROID_SDK/tools.
Usually there is no need to launch it directly since both Eclipse and the
android command line tools give a graphical UI to launch it.
When it is launched directly it is either by experts during development
or to do automatic testing.
The Emulator - technical
Supports many command line arguments, too many to
cover here. Some of them are:
Limiting resources (memory, network bandwidth)
Cache configuration.
Code profiling.
Enable/Disable hardware (audio, gps).
Configure hardware (screen resolution).
Configure timezone.
Debug and networking.
Passing arguments to underlying qemu (it has tons of
arguments too!)
The Emulator - technical
The emulator is built on top of qemu which is a
platform emulator.
It emulates everything up to CPU core.
This means that after running the emulator you
have a full android system.
That runs at the speed of an elderly turtle.
That is very far from real time performance.
And which lacks in hardware.
The Emulator - technical
The SDK provides two underlying CPU
emulators: one for x86 and one for ARM.
They are called emulator-x86 and emulator-arm.
emulator is just a gateway to one of these and so
is the UI (according to the selection of the AVD).
Qemu has support for other architectures
(PowerPC, microblaze) but these are not
supported by the SDK.
Its demo time again.
ADB: Android Debug Bridge
versatile command line tool that lets you communicate with an
emulator instance or connected Android-powered device.
Is provided with the SDK at $ANDROID_SDK/platform-tools/adb.
adb funny in that it is both a client and a server on your host
machine. When you first run it, it spawns the server part, so it has
persistent state and keeps the connection with the targets.
On the target machine (or emulator) it has a server counterpart
/sbin/adbd.
The adb command line actually talks via a TCP port (5037) to the
adb server that was run the first time. The server talks to the
clients in pairs of ports: one for console and one for adb.
ADB (cont)
adb devices lists all devices you are
monitoring.
Each device is listed by it's console port.
The adb server finds the devices auto magically
by scanning ports 5555 to 5585 (the standard
ports used by Android devices and emulators).
adb supports many command.
Direct a command to a specific target using:
adb -s <serialNumber> <command>
ADB: capabilities
With adb you can:
Drop into a shell (adb shell). This is a low capability shell but is enough
to explore the file system and do basic debugging. You can also go into
SQLite databases using the sqlite3 command.
Issue one shell command.
View device log.
Install/uninstall applications (apk files) on the device.
Get info from the device for bug reports.
Wait until the device is on-line.
Reboot the device.
Start/stop/restart the adb daemon on the target.
Copy files from/to the device.
Much more.
ADB: uses
Common every-day debug, explore,
code/run/debug cycles.
Writing testing scripts.
Automating development tasks.
Understanding the platform.
Low level debugging (/proc, /sys, ).
Viewing logs on the command line at host.
Demo time again.
DDMS
DDMS: Dalvik Debug Monitor Server.
provides port-forwarding services, screen capture on the device,
thread and heap information on the device, logcat, process, and radio
state information, incoming call and SMS spoofing, location data
spoofing, and more
Is both integrated into Eclipse and a standalone application.
Is provided with the SDK at $ANDROID_SDK/tools/ddms
Preferences for ddms are saved to $HOME/.ddmsrc.
DDMS provides a File Explorer tab that allows you to view, copy, and
delete files on the device.
The Threads tab in DDMS shows you the currently running threads for
a selected process.
You can also see logcat (logs) from DDMS.
DDMS: finding memory leaks
First, what type of memory leaks does Java have?
Second, how do you find them?
In the Devices tab, select the process that you want to see the
heap information for.
Click the Update Heap button to enable heap information for the
process.
In the Heap tab, click Cause GC to invoke garbage collection,
which enables the collection of heap data. When the operation
completes, you will see a group of object types and the memory
that has been allocated for each type.
Click on an object type in the list to see a bar graph that shows the
number of objects allocated for a particular memory size in bytes.
DDMS: Heap view
In the Devices tab, select the process that you want to see
the heap information for.
Click the Update Heap button to enable heap information
for the process.
In the Heap tab, click Cause GC to invoke garbage
collection, which enables the collection of heap data.
When the operation completes, you will see a group of
object types and the memory that has been allocated for
each type.
Click on an object type in the list to see a bar graph that
shows the number of objects allocated for a particular
memory size in bytes.
DDMS: Case Study Methodology
In the Devices tab, select the process that you want to
enable allocation tracking for.
In the Allocation Tracker tab, click the Start Tracking button
to begin allocation tracking.
Click Get Allocations to see a list of objects that have been
allocated since you clicked on the Start Tracking button.
To stop tracking or to clear the data and start over, click the
Stop Tracking button.
Click on a specific row in the list to see more detailed
information such as the method and line number of the
code that allocated the object.
DDMS: Profiling
Warning: 1.5, 2.0/2.1 devices have issues with
profiling read the docs.
On the Devices tab, select the process that you
want to enable method profiling for.
Click the Start Method Profiling button.
Interact with your application to start the methods
that you want to profile.
Click the Stop Method Profiling button.
A Traceview UI is started which shows method run
times (inclusive and exclusive).
DDMS: Misc
DDMS can also be used to:
Change network state (on/off), speed and latency.
Trigger a call or SMS.
Change the location of the phone.
These are more rarely used by people who
build applications that respond to such triggers
or who are sensitive to location or networking
state or latency.
Its demo time again.
The Android native layer - NDK
We will cover...
A word of warning...
A little bit of git.
Who should work with the NDK.
Toolchain issues.
The Android kernel and how to build it (+demo).
How to build a standalone module for the Android kernel
(+demo).
How to build the entire Android platform (+demo, sort of).
How to build a native library or application will be
explained in a later chapter.
A word of warning
Anything that can be done at the Java layer
should be done at the Java layer.
This means that for 99% of Android application vendors the Java
layer is the right choice.
So no NDK knowledge needed, no C, no C++, no kernel, no
problems, no heartache, no weird bugs that crash your system
once every two weeks and you don't know why.
Hardware devices in Android are exposed to the Java layer with
carefully thought of API that provide utilization of the hardware
but keep it running efficiently. This means that accessing the
hardware is not a good excuse to go native.
Consider yourself warned!
A few notes about git...
Git is a beautiful source management application developed by
Linus Torvalds for the Linux kernel.
It is distributed, small, full featured, fast and reliable.
It made a revolution in source management thinking.
Github and other, much more strange, services are based on it.
It is what is used for Android development.
It is a good idea to use git for low level Android development and
the Linux kernel.
You may need it if you want to submit patches to the Android
system or kernel.
In any case it is a good idea to get to know git.
Demo video or git now
Who should work with the NDK?
People who believe they can get higher speed by utilizing
lower level facilities (GPU, specialized machine instructions,
the speed of C/C++)
People who write implementations for core Android services
which are missing or not implemented in the Android stack
and are appropriate to code natively.
Kernel developers who would like to add features to the
Android kernel.
Platform vendors that see like to wrap kernel device drivers
they write in user land sugar.
Platform vendors for which the Android platform does not
provide support in user land.
Toolchain - definition
Toolchain is the complete set of tools that enable
one to build software for the target platform.
This usually includes: compiler, linker,
assembler, remote debugger and more.
In Linux it is usually a folder in which you have a
set of binaries.
The name of the folder as well as the name of
the binaries reflect the architecture for which
these are made.
Toolchain - notes
In Linux, because of ABI changes between
compilers, the compiler version is an integral part
of the platform name.
In plain terms it means that saying architecture x86
in Linux is not enough. Instead you have to say
x86 with gcc 4.3.2 compatibility. Together these
make up the platform.
In Linux (and Android here is a prime example of
Linux), all user space binaries should be compiled
using the same or ABI compatible compiler.
What can I do with a toolchain?
You use the toolchain on the host.
(On the host) Build libraries and applications to
run on the target platform.
(On the host) Debug the remote target platform
using a debugger.
(On the host) Analyze profile information from
the target.
(On the host) Analyze core dumps from the
target.
How do I get a toolchain?
A couple of options:
Conventional: You install a downloaded pre built NDK
from the Android developers site. You use one of the pre
built tool chains. (the download and installation part will be
explained later).
Conventional: You download the source for the entire
Android platform. You get pre built tool chains with it.
Unconventional: You build you own tool chain (will not be
explained)
Unconventional: You just download a compiler to the
target (apt-get install in Ubuntu) and use it. Don't forget to
make sure that it is ABI compatible with the Android ABI.
The Android kernel
Is 2.6 based.
Quite heavily hacked.
Technically, a Linux kernel fork.
A lot of controversy about Google's policy regarding the Android
source code.
Version 2.6.36 in latest version but contains code from 37 and 38. 3.0
stuff already in development.
Each different Android platform uses a different kernel version.
All layers of the kernel are modified.
New modules added.
New kernel features added.
Lots of kernel features removed.
Building the Android kernel
Is very similar to building standard Linux kernels
The kernel is not part of the Android source code (although
it once was)
Because it is huge and complicated to build
And because most user land developers (Java and C) do
not need it
Android source does provide kernel headers which are
pretty standard and required for userspace.
This means that if you build your own kernel you have to
make sure that you don't break standard features
Only do this on Linux!
Building the Android kernel why?
Adding module support and modules (module
support is enabled in later versions of the
android kernel but not in earlier ones).
Change boot code.
Port to another platform.
Doing core Android development.
Doing core system changes.
Making a kernel to run under an emulator
(eases development).
Building the Android kernel how?
mkdir kernel; cd kernel
git clone git://android.git.kernel.org/kernel/common.git androidkernel
Go for coffee
cd android-kernel
Optionally: export ARCH=arm
Optionally use a predefined configuration and bring it over to
.config.
make menuconfig
Optionally: export CROSS_COMPILE=[your cross compiler]
make
Building the Android kernel configuration
Stick with defaults unless you know what you
are doing
Tune to your specific hardware (add, remove
drivers to fit your hardware precisely)
Keep any configuration you build with in source
control
Changing configuration should be regarded as
a trigger to redo QA all over
Building the Android kernel
toolchain
For cross compilation make sure you have a cross
compiler installed
Android sources provide you with a cross compiler
under: $ANDROID_SOURCES/prebuilt/linuxx86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-*
Android downloaded NDK gives you cross
compilers under:
$ANDROID_NDK/toolchains/arm-linuxandroideabi-4.4.3/prebuilt/linux-x86/bin/arm-linuxandroideabi-*
Building the Android kernel
toolchain
You can also use your own cross compiler.
For instance, on Ubuntu you can use:
sudo apt-get install gcc-4.5-arm-linux-gnueabi
gcc-4.4-arm-linux-gnueabi
Once you install this you get /usr/bin/arm-linuxgnueabi-* executables which are you arm
toolchain.
This is not recommended but is used by some
advanced users.
Building the Android kernel - demo
It's demo time
Building an Android kernel module
Earlier Android kernels did not support loadable
modules. Currently they do.
You will need kernel headers to build a module so
compiling a kernel (covered previously) will do the trick.
Some make(1) knowledge is good to have
Assume that you have a toolchain
Create your own kernel module (assume main.c).
Create a makefile in which you point to your toolchain
and the kernel directory for that toolchain.
Build (make)
Building Android from source
Android is an open source platform.
All source code is available from android.git.kernel.org.
Only do this on Linux!
Have 10-15 GB of free space for the build folder.
Install the sun JDK:
$ sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
$ sudo add-apt-repository "deb-src http://archive.canonical.com/ubuntu lucid partner"
$ sudo apt-get update
$ sudo apt-get install sun-java6-jdk
In oder for the build to work you have to have lots of tools that are needed by the long
build process.
These include: git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev
lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev
libgl1-mesa-dev g++-multilib mingw32 tofrodos
The above list is possibly incomplete (sorry...).
If any of the tools are missing then the long build will fail in the middle (ergh!).
Building Android from source
mkdir ~/bin
PATH=~/bin:$PATH
curl http://android.git.kernel.org/repo > ~/bin/repo
chmod a+x ~/bin/repo
mkdir WORKING_DIRECTORY
cd WORKING_DIRECTORY
repo init -u git://android.git.kernel.org/platform/manifest.git
repo sync
Get coffee
gpg --import (imported the huge key)
source build/envsetup.sh
Lunch (select target)
make/make -j4
Coffee time again (about 200 cups of coffee)
Building Android from source
It's demo time
After the build the results are in
$ANDROID_SOURCE/out/target/product/generi
c/*.img
Now you can either run the emulator to emulate
the target that you created by running emulator.
Or you can flash a device with the new images.
Flashing a device
To flash the device you need to put it in fastboot mode in
which it will receive an image to flash.
This could be done by key combination ([Hang Up] +
[Sound Down] + [Power] on some models check yours).
Or if the device is currently running Android and an adb
server (usually it does and it will be discussed later) then
issue: adb reboot bootloader to put the device into fastboot
mode.
To flash the device: fastboot flashall -w
-w will erase the /data folder and could be skipped in most
instances. Use only if you really want a 'clean' device.
Application fundamentals
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Application Fundamentals
Overview
Android Applications are written in the Java
Programming Language
The compiled code along with the resources files are
bundled into Android package (.apk file)
All code in one android package is considered as one
application
Application Fundamentals
Overview
Each application live in his own Linux process, by
default
Each Linux process has it's own VM. so two
applications are isolated.
By default each application has it's own unique user id
relate to permissions
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Main Types
Android application have four primary building
blocks components:
Activities
Services
Broadcast Receivers
Content Providers
Main Types
Broadcast receivers:
Components that listen to events
Content Providers:
Component that make application data available for
other applications
Intent:
Asynchronous messaging system
Activities, services and broadcast receivers are
triggered by intents
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Activities
Activities:
A visual user interface component that interact with
the user
Activity is the window or the view or the form
that the user is working on
Application can have more then one activity, and
although usually they work together to form
application cohesive user interface, each activity is
independent from the other.
Activities
One of the activities typically marked as the
main activity (the first one that should be
presented to the user)
note that android application doesn't have a main
method, instead we have activities that can be
launched, one of the will be launched by default.
Activity extends the android.app.Activity class
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Services
A service that doesn't have visual user interface
runs in the background for indefinite period of time
Service extends the android.app.Service class
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Broadcast Receiver
A component that the receives and react to
broadcast announcements from other
applications or from android system services
For instance, android system can announce (raise
event) about low-battery or phone call started, or
user changed preferences and more
Receiver extends the
android.content.BroadcastReceiver class.
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Content Provider
A component that make specific set of data
from one application available for other
applications
A content provider uses a URI to identify the
provider
for instance: content://contacts/people
Content Provider extends the
android.content.ContentProvider class
When component want to activate content provider it
use a ContentResolver
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Intents
To Activate Activity, Service of Broadcast
Receiver in android, we use the Intent Object.
Intent is an object that extends the
android.content.Intent class
Intent holds the message information regarding what
is it that we would like to activate
Intents are asynchronous mechanism
If one activity would like to start a service, or to
display a different activity to the user,
Intents
Intents cont.
The created intent is passed to methods from the
Context class (explained in the next slide).
Intent extends the android.content.Intent class.
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Context
Both Activity and Service extends the
android.content.Context class.
The Context class is implemented by the Android
system.
It allow access to application specific resources and
classes.
It allow sending intents to activities, services and
broadcast receivers
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Application Lifecycle
Android application doesn't have a main()
method
The system can instantiate one of the main four
components
For instance, when the user open the launch the
application, one of the activities is instantiate
Application Components have a lifecycle, start
when Android instantiate them (due to an intent)
and ends when the system doesn't instance is
destroyed.
Application Lifecycle
Between, they can be activated or deactivated,
become visible or invisible, start and stop etc
lifecycle of components in android is reflected in
the component API, we have lifecycle methods
for the components
Application Fundamentals
Application Fundamentals Overview
Main Types
Activities
Services
Broadcast Receiver
Content Provider
Intents
Context
Application Lifecycle
Components Lifecycle
Components Lifecycle
Components Lifecycle Activity Lifecycle
Components Lifecycle Service Lifecycle
Components Lifecycle Broadcast Receiver
Lifecycle
LifeCycle Methods
Components Lifecycle content providers
Components Lifecycle
Activity Lifecycle:
Activity have 3 states
Active or running, when the activity is in the
foreground (and in focus)
Paused, if it lost focus another activity is on top of
it, but part of it can still be seen
Stopped, no longer visible to the user
Components Lifecycle
Activity Lifecycle:
The transition between these states is reflected in the
lifecycle methods
onCreate and onDestory, entire lifetime of the activity
All initialization and destroy of references are created
in these methods
onStart and onStop (onRestart), visible lifetime of the
activity, between these methods the user can see the
activity
onResume and onPause, foreground lifetime of the
activity, between these methods the activity is in-front
of all other activities, and the user can interact with it
Components Lifecycle
Activity Lifecycle:
The following
diagram explain it
Components Lifecycle
Service Lifecycle:
Service also have lifecycle methods
onCreate & onDestory, entire lifetime of the service.
onStart, service is running
service doesn't have a corresponding onStop method
onBind, onUnbind, when clients bind and unbind to
the service (will be explain later)
Components Lifecycle
Service Lifecycle:
Components Lifecycle
Broadcast Receiver Lifecycle:
Broadcast receiver has on one lifecycle method
onReceive, when broadcast messaged arrive to the
receiver android calls onReceive with the intent
information
Components Lifecycle
LifeCycle Methods:
Important, when you implement lifecycle method,
don't forget to call super.on<Method> first!
Components Lifecycle
content providers:
Content providers are activated when they're
targeted by a request from a ContentResolver
Will be discussed in later chapters
Key Points
Activity, UI related
Service, background process
Each as a life-cycle reflected in the class
methods.
Intent, start activity or service
The NDK in depth
Bionic
Is a standard C library which is needed on Linux (why?)
Originally developed by Google for Android.
Has Linux specific features (hard to port to other
systems).
Currently is an independent project.
Small size compared to other standard C libraries and
especially compared to glibc (273K in Android 9/arm).
Has more arbitrary limits and less features than glibc.
As a result is faster to initialize and do the things which
are needed in Android.
Bionic (cont)
Designed for CPUs at relatively low clock
frequencies
BSD licensed which protects you from Linux kernel
license (not really needed)
Android core developers usually change Bionic via
the Android building process rather than via the
Bionic project itself (reasons?)
Source at $ANDROID_SRC/bionic
Products at $NDK/platforms/
$ANDROID_VERSION/$ARCH/usr/{lib,include}
Bionic (cont)
Made up of several libraries: c, m, dl,
pthread_db, stdc++
SYSV IPC is not implemented (denial of service
issue, size of library). Neither is pipe(2).
Growing in size with each version of Android
Some real time support as well (timers etc).
See $BIONIC/docs for info
Bionic (cont)
Once did not support wide characters. Today it
does.
Some parts are built using Jam
http://www.perforce.com/documentation/jam
Supplies clean kernel header files to user land
applications (in addition to standard headers)
Only a subset of the standard Linux system
calls are supported.
Bionic - architectures
Today (2011) supports 3 architectures: sh, arm
and x86
Other ports do exist but not in the main tree
Parts of the architecture code is written in
assembly for speed (memcpy, memmove etc)
Look under $BIONIC/libc/arch-$ARCH/
Bionic - pthread
Subset of pthread API is supported in libc.so
and not in pthread.so
Does not support pthread cancellation (why?)
Futexes are supported (yes!)
No process shared mutexes and no condition
variables
Readers/writer locks recently added.
Bionic C++ support
Traditionally did not support C++ exceptions.
Current exception support is better.
You may use exceptions in pure C++ code but in some cases if
you call C code exceptions will be lost.
In practice this means that writing C++ with exceptions is difficult.
Traditionally no support for STL.
Latest version of Android provide STLPort (beta). Use at your
own risk.
You may supply STL with your application (SGI implementation is
freely available)
Other C++ API also lacking (c++0x for instance).
cutils
Is a user space library provided by the NDK to help in
various topics.
Most importantly it wraps some of the peculiar kernel level
features of android (binder, ashmem, logger and more).
Also provides general programming utils: strings, unicode,
configuration, process name, scheduling policy setting,
hashmap implementation, a little multi-threading support,
utilities to help with java to/from C string conversion,
abortable socket and more.
Resides in
$ANDROID_SOURCE/system/core/include/cutils
Android kernel peculiarities
Android kernel
Fork of the Linux kernel.
Has some embedded features.
Most interesting changes can be found in
$ANDROID_KERNEL/drivers/staging/android/
The reason for this mess is the assumption that
the standard kernel is not good enough for
embedded systems.
This assumption is challenged by the standard
kernel developers.
Binder
Android kernel does not support SYSV IPC.
Binder is quite an advanced IPC replacement and also
handles remote method invocation.
Code is in:
$ANDROID_KERNEL/drivers/staging/android/binder.{c,h}
Java communication goes through binder
(ActivityManager, Intents and more).
cutils offers mq.h which is a native level API for a message
queue.
Binder allows passing of file descriptors between unrelated
processes (much like BSD sockets).
Binder - layers
If you are a Java level coder then the Intent
concept is easy to use and good enough for
most cases.
If you want more power you can go down to the
AIDL layer but then you need to handle multithreading concerns.
Binder is below AIDL and requires C or IO
programming.
Interface is via /dev/binder and is done via ioctls
(not reads or writes).
Binder - design
Binder is somewhat like COM in that it allows method
invocation between processes.
Binder is not an easy to use API but rather a low level
kernel driver which can be used as the basis of higher
level API.
It is targeted to C++ and C as base-line languages.
The idea is to have bindings to other (scripting) languages
as well.
It is not network aware. The communication is just within
processes on the same machine.
It has references counting features and debugging built in.
ashmem - design
The problems with SYSV IPC shared memory...
Implemented in $ANDROID_KERNEL/mm/ashmem.c
and $ANDROID_KERNEL/include/linux/ashmem.h.
Has a file based API (simple?) via /dev/ashmem.
Has reference counting and automatic destruction.
Better supports low memory devices because it can
discard shared memory units under memory pressure.
ashmem sources claim that SYSV IPC is prone to
denial of service attacks.
ashmem direct usage
open(/dev/ashmem)
mmap(2) it (size is the size you want).
Use various ioctls on the file descriptor:
ASHMEM_SET/GET_NAME
ASHMEM_SET/GET_SIZE
ASHMEM_SET/GET_PROT_MASK
ASHMEM_PIN/UNPIN
ASHMEM_GET_PIN_STATUS
ASHMEM_PURGE_ALL_CACHES
ashmem cutils
Example:
fd = ashmem_create_region("my_shm_region", size);
if(fd < 0)
return -1;
data = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if(data == MAP_FAILED)
goto out;
Now you pass the fd to the other process via binder
and the other processes mmaps the same way and
you have shared memory.
pmem - design
Process memory allocator
Not to be confused with some other older drivers that were
called pmem.
Sources at $ANDROID_KERNEL/drivers/misc/pmem.c and
$ANDROID_KERNEL/include/linux/android_pmem.h.
The idea is to allow user space applications to allocate
large physically contiguous memory.
This is usually used to communicate with hardware via
large DMA transfers for performance or to deal with
hardware that cannot cope with scatter-gather DMA.
Has file based API.
pmem direct usage
open(/dev/pmem_{camera|adsp})
Ioctl it:
PMEM_GET_PHYS
PMEM_MAP
PMEM_UNMAP
PMEM_GET_SIZE
PMEM_ALLOCATE
PMEM_CONNECT
PMEM_GET_TOTAL_SIZE
PMEM_CACHE_FLUSH
logger design
The problems with printk.
printk is not available to user space.
Requires extra daemon for log to reach final destination.
Only has one log.
Designed primarily for kernel use.
Can lose messages because of that.
Embedded systems need a log that:
Survives application crashes.
Could be slower than printk at the cost of reliability.
Possibly more than one log buffer.
Does not lose message.
Could be controlled, cleared, trasmitted from user space.
Logger was designed to solve all of these.
logger design (cont)
The source is at
$ANDROID_KERNEL/drivers/staging/android/logger.{c,h}
The code supports 4 logging buffers, named "main",
"events", "radio", and "system" for different types of
events.
The are device nodes /dev/log/{main,events,radio,system}
API is regular open(2),write(2),close(2)
A command line called logcat(1) is supplied which is the
Android equivalent of tail -f /var/log/syslog.
The adbd daemon also knows how to read the log and
supply it to a remote adb client.
logger design (cont)
The four log buffers are:
main the main application log.
events for system event information.
radio for radio and phone-related debugging.
system a log for low-level system messages and
debugging.
All of these are textual except events which
consists of binary data for compactness.
logger native logging
liblog.so is a library to encapsulate writing to the
log.
Source is at
$ANDROID_SOURCE/system/core/liblog
Header is in
$ANDROID_SOURCE/core/include/android/log.h
API is very similar to syslog(3).
You can also print to standard output or error in
which case your messages do not reach kernel
land log buffers.
logger Java layer
Application or Java layer programmers use
android.util.{Log,EventLog,Slog} classes to log.
Messaged are accompanied by severity levels.
Log messages are passed to the liblog library
and from there onto the kernel.
Logging system overview
logger capturing stdout
It is sometimes useful to capture stdout from
native applications into a log.
logwrapper(1) does this for you.
It allows you to run a native application which is
supplied to it on the command line and captures
it's standard output turning it into a log
messages.
Source is at
$ANDROID_SOURCE/system/core/logwrapper/l
ogwrapper.c.
Wake locks - definition
Wake locks are locks which keep the system awake.
Actually, because there are different ways in which the
system can go to sleep there are different types of
wake locks to prevent these different types of sleep.
The standard Linux kernel also has some of these
features but the Android people went ahead and wrote
them anyway.
The code is in
$ANDROID_KERNEL/kernel/power/wakelock.c and
$ANDROID_KERNEL/include/linux/wakelock.h
Wake locks types of sleep
System suspend: Entire system is suspended,
CPU turns off, power consumption is down,
only hardware (button) can wake it up.
System idle: Some interrupts are disabled,
some may wake the system, CPU power
consumption is down, even if an interrupt
occurs it is handled with large latency.
These are also the types of wake locks.
Wake locks kernel usage
#include <linux/wakelock.h>
wake_lock_init(struct wakelock *lock, int type,
const char *name);
void wake_lock(struct wake_lock *lock);
void wake_lock_timeout(struct wake_lock *lock,
long timeout);
void wake_unlock(struct wake_lock *lock);
Wake locks user space usage
Only suspend locks can be taken from user
space.
Writing a name to /sys/power/wake_lock
establishes a lock with that name.
Writing the same name to
/sys/power/wake_unlock releases the lock.
Wake locks Java API
PowerManager pm = (PowerManager)
getSystemService(Context.POWER_SERVICE)
;
PowerManager.WakeLock
wl=pm.newWakeLock(PowerManager.SCREE
N_DIM_WAKE_LOCK, "My Tag");
wl.acquire();
..screen will stay on during this section..
wl.release();
Wake locks - controversy
Documentation says: Device battery life will be
significantly affected by the use of this API. Do
not acquire WakeLocks unless you really need
them, use the minimum levels possible, and be
sure to release it as soon as you can.
The Jury is still out on whether this API should
be given to developers at all...
Lowmemorykiller
Kernel feature allowing kernel to kill processes
which consume too much memory.
Originally developed by Google (Android)
deveoper Arve Hjonevag.
Initial values set in /etc/init.rc by utilizing /proc.
Code in Java adjusts the parameters at run
time (see ActivityManagerService.java).
Linux has such a feature too...:(
alarm
Kernel implementation to support Java level
AlarmManager API.
Essential since if system goes to sleep no wake
up would be possible (remember that user space
cannot prevent all power downs).
Source is in
$ANDROID_KERNEL/drivers/rtc/alarm.c.
Header is in
$ANDROID_KERNEL/include/linux/android_alar
m.h.
timed output/timed gpio
$ANDROID_KERNEL/drivers/staging/android/time
d_{gpio,output}.{c,h}
Allows user space to access GPIO registers.
Sort of uncomplicated driver in user space
solution.
Controversy also surrounds this API because it
gives too much power to user space.
The timed version ensures that the register value
returns to it's original state after a certain time has
passed and is considered safer to use.
ram_console
Intended to ease kernel development.
ram_console allows kernel printk message to
be saved to a buffer in RAM.
This is useful for crash debugging.
After the system reboots you can find the log
in /proc/last_kmsg.
Some developers go further and rewrite printk
to deliver all messages to external hardware...
Android file system
File system implementation
Most Android devices used YAFFS Yet Another Flash File
System (actually most used YAFFS2).
This file system is light weight, single threaded, and optimized
for flash storage.
This means it cannot make use of dual core devices.
It is also not very scalable (long explanation here...).
Platform vendors were free to choose other file systems but
rarely did so.
SD card is usually vfat to allow sharing data between devices.
Some devices, like Samsung Galaxy S, use proprietary file
systems (Samsung RFS in this case). Why? Well because
they can and they are allowed to.
File system implementation
Starting with Gingerbread Android was shipped
with ext4 support as well.
Ext4 is much more scalable (explanation here...).
Ext4 is multi-threaded (kernel thread per CPU).
Ext4 has sync issue (intentionally) but that is
rarely a problem for application developers.
If you are a C developer remember to fsync(2) if
you want to guarantee your data reaches it's
destination.
Mount points - virtual
Obviously there are many virtual file systems
even in Android:
/dev, /sqlite_stmt_journals tmpfs
/dev/pts devpts
/proc proc
/sys sys
/dev/cpuctl cgroup
These are standard Linux virtual file systems.
Mount points - physical
Usually these exist:
/system, /data, /cache yaffs2
/sdcard vfat
Again, yaffs2 is not always the case.
/system is where the, well, system is.
/data is for applications.
/cache is for application caches which are non
essential.
Data for applications
Applications running in Android may save data to persistent storage.
Several API exist:
File system access using standard java.io packages or Android wrappers.
SD card storage.
Preferences system.
Database API (SQLite).
Cache.
Network connections (this is not really storage on your own system).
Content providers.
The first 4 methods discussed above store data in:
/data/data/package.of.the.application
This directory is private to the application this means that only the
application can read and write this folder (and of-course the system).
The fifth method stores data in: /cache/cache/package.of.the.application
Applications and files
Applications do not need any special permissions to write to their own
storage folder.
Standard java.io interfaces exist for application to read and write files
from their own application data directory.
The SDK provides some sugar wrappers for regular java.io interfaces for
easy access of an application to it's own files.
The permission system is quite simple: every file is either
MODE_PRIVATE, MODE_WORLD_READABLE,
MODE_WORLD_WRITABLE or MODE_WORLD_READABLE |
MODE_WORLD_WRITABLE
This means you don't have lots of permission control.
When the application is un installed it's data directory goes away.
This is also why some basic applications cannot be removed (so that
users don't loose their contacts/photos/videos by mistake).
SD card access
First, remember that the SD card is not always
there physically.
Even if the SD card is there, when the device is
connected via USB to a computer the SD card
is not available (the idea is to prevent
concurrent access issues).
All files and directories on the SD card are
readable and writable by all applications.
SD card access
To write to the SD card applications need the
android.permission.WRITE_EXTERNAL_STORA
GE permission.
To check if the SD card is there use:
Environment.getExternalStorageState().equals(E
nvironment.MEDIA_MOUNTED).
To get the path to the SD card use:
Environment.getExternalStorageDirectory().
After all this you use standard java.io or Android
wrappers to write to the SD card.
The cache
Application authors may want to store data which is not crucial
to their correct working but which may take lots of space.
The right way to store these files is in the application cache.
To get the path to the cache use: getCacheDir()
Then use standard java.io or Android wrappers to do io in that
folder.
This folder is private to your application and usually lives in:
/cache/cache/package.of.your.application.
The application cache folder goes away when the application is
un installed.
Files in the application cache may be removed by the system
when it's running low on internal storage space.
Sharing data between applications
Several ways exists:
File system data.
SD card.
Content providers.
Each method has it's own distinct advantages
and disadvantages.
Best way is probably content providers.
Sharing data between applications
file system
Applications can create sub folders in their own data folder.
On these sub folders applications may grant read or even write
access as discussed.
No fine grained access control.
There is no lock protecting against concurrent access by two
applications, or even two threads of the same application, to the
same file at the same time.
On the other hand this means that an application can access
another applications data when that application is not alive.
This method is usually used for large pieces of data: photos,
videos, music which do not have lots of structure to them and
rarely need lots of concurrent access protection.
Sharing data between applications
database
When an application creates an SQLite
database it is saved under it's application folder,
in a directory called databases.
This directory is readable and writable only by
the creating application.
It is a bad practice to change these permissions
(although you are allowed to do so).
This means that sharing databases directly is
not recommended.
Android init
On the target the init configuration is at /init.rc.
The init language itself is documented at:
$ANDROID_SOURCE/system/core/init/readme.
txt.
At the heart of android
Android initialization
Android built-in native services
ueventd
User space daemon handling kernel notifications
about devices connect/disconnect and other
messages in user space.
Does it by polling a netlink socket.
Is run early in the Android boot process from init.rc
Configuration is in $ROOT/ueventd.rc
Quite simple configuration file format
Is the Android lightweight version of udev which is
See files $ROOT/init.rc, $ROOT/ueventd.rc.
Advanced
JNI
Java Native Interface
Advanced JNI
Copyright 2003-2004 InterBit LTD.
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
202
JNI Recap
JNI allows Java code to operate with
applications and libraries written in
other languages, such as C, C++, and
assembly.
JNI Allows Java programmers to
integrate with native (not Java)
components and applications.
Advanced JNI
203
JNI Recap
JNI is the glue between Java and
native applications.
Advanced JNI
204
Java App with Native Methods
The following steps are needed (in this
example, Java + C):
Write the Java code.
Compile the Java class (using javac).
Create a header file (using javah).
Write the native code (C).
Create a shared library (using native compiler).
Run the Java application that calls the native
code.
Advanced JNI
205
Mapping Java and Native Types
Java primitives mapping:
Java Type
Native Type
Size in bits
boolean
jboolean
8, unsigned
byte
jbyte
char
jchar
16, unsigned
short
jshort
16
int
jint
32
long
jlong
64
float
jfloat
32
double
jdouble
64
void
void
n/a
Advanced JNI
206
Mapping Java and Native Types
All objects are passed by reference.
All references have a super type of
jobject.
Advanced JNI
207
Mapping Java and Native Types
Example:
public
public native
native String
String
loopPrint(String
loopPrint(String name,int
name,int num)
num)
JNIEXPORT
JNIEXPORT jstring
jstring JNICALL
JNICALL
Java_MyClass_loopPrint(JNIEnv*,jobject
Java_MyClass_loopPrint(JNIEnv*,jobject
,jstring,
,jstring, jint)
jint)
Advanced JNI
208
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
209
Local & Global References
JNI supports three types of references:
Local references
Global references
Weak global references
These types behave differently with regards to
garbage collection and lifetimes
Advanced JNI
210
Local References
A local reference is valid only:
Within the context of the native method that
creates it and within a certain invocation of the
method.
In the thread that creates the reference.
Once the native method returns, all local
references will be freed.
Never store a local reference in a static
variable. The reference might not be valid.
Advanced JNI
211
Local References - Example
Never keep local references in static variables
jstring
jstring MyNewString
MyNewString (JNIEnv
(JNIEnv *env,
*env, jchar*chars,
jchar*chars, jint
jint len)
len)
{{
static
static jclass
jclass stringClass
stringClass == NULL;
NULL;
if(stringClass
if(stringClass ==
== NULL)
NULL)
//this
//this is
is wrong
wrong
{{
stringClass
stringClass == (*env)->findClass(env,
(*env)->findClass(env, java/lang/String);
java/lang/String);
if
if (stringClass
(stringClass ==
== NULL)
NULL)
{{
return
return NULL;
NULL;
}}
}}
cid
cid == (*env)->GetMethodID(env,
(*env)->GetMethodID(env, stringClass
stringClass ...
...
Advanced JNI
Any use of the stringClass here is
problematic since it may be invalid. The
stringClass might have been freed, so the
call might lead to memory corruption or
system crashes
212
GC & Local References
A local reference keeps the referenced object
from being garbage-collected until the local
reference is invalidated.
If you wish to invalidate the local references
beforehand, you may explicitly do it using the
JNI function: DeleteLocalRef.
jcharArray
jcharArray elemArr
elemArr == (*env)NewCharArray(env,
(*env)NewCharArray(env, len);
len);
result
result == (*env)->NewObject
(*env)->NewObject (env,
(env, stringClass,
stringClass, cid,
cid, elemArr);
elemArr);
(*env)->DeleteLocalRef(env,
(*env)->DeleteLocalRef(env, elemArr);
elemArr);
Advanced JNI
213
Global References
Global references can be used
Across multiple invocations
Across multiple threads
A global reference ensures that the referenced
object will not be GC.
Global references are Created by the JNI
function:
jobject NewGlobalRef(JNIEnv *env, jobject obj);
Global references are deleted by the JNI
function:
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
Advanced JNI
214
Global References - Example
Creating a global reference
jstring
jstring MyNewString
MyNewString (JNIEnv
(JNIEnv *env,
*env, jchar*chars,
jchar*chars, jint
jint len)
len)
{{
static
static jclass
jclass stringClass
stringClass == NULL;
NULL;
if(stringClass
if(stringClass ==
== NULL)
NULL)
//this
//this is
is OK
OK now
now
{{
jclass
jclass localRefClass
localRefClass == (*env)->findClass(env,
(*env)->findClass(env, java/lang/String);
java/lang/String);
stringClass
stringClass == (*env)->NewGlobalRef(env,
(*env)->NewGlobalRef(env, localRefClass);
localRefClass);
(*env)->DeleteLocalRef(env,
(*env)->DeleteLocalRef(env, localRefClass);
localRefClass);
if(stringClass==NULL){
if(stringClass==NULL){
return
return NULL;
NULL;
//free
//free local
local reference
reference
Creates a global
reference
}}
}}
cid
cid == (*env)->GetMethodID(env,
(*env)->GetMethodID(env, stringClass
stringClass ...
...
Advanced JNI
215
Weak Global References
Like Global references, remain valid across
method calls and threads.
Unlike Global references, Weak Global
References do not keep the underlying object
from GC.
Use Weak Global References when a reference
cached by the native code must not keep the
underlying object from being garbage collected.
Advanced JNI
216
Weak Global References - Example
Creating a weak global reference
...
...
static
static jclass
jclass cachedClass
cachedClass == NULL;
NULL;
if(cachedClass
if(cachedClass ==
== NULL)
NULL)
{{
jclass
jclass localRefClass
localRefClass == (*env)->findClass(env,
(*env)->findClass(env, ClassToCreate);
ClassToCreate);
cachedClass
cachedClass == (*env)->NewWeakGlobalRef(env,
(*env)->NewWeakGlobalRef(env, localRefClass);
localRefClass);
(*env)->DeleteLocalRef(env,
(*env)->DeleteLocalRef(env, localRefClass);
localRefClass);
//free
//free local
local reference
reference
}}
cid
cid == (*env)->GetMethodID(env,
(*env)->GetMethodID(env, stringClass
stringClass ...
...
Creates a weak
global reference
Advanced JNI
217
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
218
Memory Management
Each JNI reference consumes a certain amount
of memory in addition to the memory taken by
the referred object.
You must be aware of the number of references
your program uses at a given time.
Dont count on the automatic clearing of local
references excessive reference creation can
lead to memory exhaustion!
Advanced JNI
219
Memory Management
Freeing local references is crucial in the
following scenarios:
Creating a large number of local references in a
single local method may result in an overflow
in the internal JNI local reference table.
Within a native method that does not return (for
example, goes to infinite loop).
A local reference to a large object (keeping it
longer than needed prevents the object from
being GC).
Advanced JNI
220
Lifetime functions
Each native method can create at least 16 local
references.
If there is a need to create additional local
references, a native method may call:
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
This function ensures that at least a given
number of local references is created in the
current thread.
The function Returns 0 on success; otherwise
returns a negative number and throws an
OutOfMemoryError.
Advanced JNI
221
EnsureLocalCapcaity - Example
Suppose we need to create objects in a loop:
if((*env)->EnsureLocalCapacity
if((*env)->EnsureLocalCapacity (env,
(env, len))
len)) << 0){
0){
//this
//this is
is an
an OutOfMemory
OutOfMemory situation
situation
}}
for
for (i=0;i<len;i++){
(i=0;i<len;i++){
jstring
jstring jstr
jstr == (*env)->GetObjectArrayElement(env,arr,
(*env)->GetObjectArrayElement(env,arr, i);
i);
//DeleteLocalRef
//DeleteLocalRef is
is not
not necessary
necessary here
here
}}
Remember, however, that it is preferred to free local
references inside loops
Advanced JNI
222
PushLocalFrame & PopLocalFrame
PushLocalFrame Creates a new local
reference frame, in which at least a given
number of local references can be created
jint PushLocalFrame(JNIEnv *env, jint capacity);
PopLocalFrame destroys the topmost scope,
freeing all local references in that scope
jobject PopLocalFrame(JNIEnv *env, jobject result);
The use of these functions lets you free a bulk of
references, without worrying about every single
reference that might have been created.
Advanced JNI
223
EnsureLocalCapcaity - Example
Suppose we need to create objects in loop:
#define
#define NUMBER_OF_REFERENCES
NUMBER_OF_REFERENCES 30
30
...
...
for(i=o;i<len;i++){
for(i=o;i<len;i++){
if
if ((*env)->PushLocalFrame
((*env)->PushLocalFrame (env,
(env, NUMBER_OF_REFERENCES)
NUMBER_OF_REFERENCES) << 0){
0){
//out
//out of
of memory
memory
}}
jstr
jstr == (*env)->GetObjectArrayElement
(*env)->GetObjectArrayElement (env,
(env, arr,
arr, i);
i);
...work
...work with
with jstr
jstr
(*env)->PopLocalFrame(env,
(*env)->PopLocalFrame(env, NULL);
NULL);
If the computation that processes jstr creates
additional local references, these local
references will be freed after PopLocalFrame
returns
}}
The call to PopLocalFrame should be
done in all function exit paths
Advanced JNI
224
Memory Management Rules
Be careful about excessive local reference
creation.
It is acceptable to leave up to 16 local
references to be deleted by the virtual machine.
Native method calls must not cause global
references to accumulate.
When possible, manage the lifetime of local
references by using Push/PopLocalFrame.
Advanced JNI
225
Memory Management Rules
Utility functions rules (functions that dont
directly implement native methods):
A utility function should free all the local references it
creates.
A utility function that returns a reference must:
Not accumulate any extra reference.
Return always the same type of reference (local,
global), so the caller will manage it correctly [call
DeleteLocalRef, DeleteGlobalRef]
Advanced JNI
226
Caching Field and Method IDs
Obtaining field and method IDs uses lookups,
which are relatively expensive.
You might cache these IDs to reduce the overall
overhead.
Caching can be done in static variables so the
IDs need not be recomputed upon each
invocation of the method.
Advanced JNI
227
Caching field id - Example
...
...
static
static jfieldID
jfieldID field_id
field_id == NULL;
NULL; //this
//this is
is the
the cache
cache
jclass
jclass the_class
the_class == (*env)->GetObjectClass(env,obj);
(*env)->GetObjectClass(env,obj);
Jstring
Jstring jstr;
jstr;
if(field_id
if(field_id ==
== NULL){
NULL){
field_id=(*env)->
field_id=(*env)->
GetFieldID(env,the_class,fieldToAccess,Ljava/lang/String;);
GetFieldID(env,the_class,fieldToAccess,Ljava/lang/String;);
if(field_id==NULL){
if(field_id==NULL){
return;
return; //exception
//exception
The GetFieldId is called only if we
did not cache the id before
}}
}}
jstr
jstr == (*env)->GetObjectField(env,
(*env)->GetObjectField(env, obj,
obj, field_id);
field_id);
...
...
Caching might be done for method IDs as well.
Advanced JNI
228
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
229
JNI &Threads
One must always assume the possibility of
multiple threads of control executing a native
method at any given time (unless it is definitely
known not to be the case).
Native methods must not modify sensitive
global variables in unprotected ways.
Advanced JNI
230
Thread Constrains
JNI interface pointer (JNIEnv *) is only valid in
the current thread.
You must not pass local references from one
thread to another.
Check the use of global variables carefully.
Multiple threads might be accessing these
global variables at the same time. Make sure
you put in appropriate locks to ensure safety.
Advanced JNI
231
Monitor Entry and Exit
The synchronized block in Java:
synchronized(obj){
synchronized(obj){
..protected
..protected code
code goes
goes here
here
}}
The equivalent JNI monitor functions are :
if
if ((*env)->MonitorEnter
((*env)->MonitorEnter (env,
(env, obj)
obj) !=
!= JNI_OK){
JNI_OK){
...error
...error hanling
hanling
}}
..protected
..protected code
code goes
goes here
here
if
if ((*env)->MonitorExit(env,obj)
((*env)->MonitorExit(env,obj) !=
!= JNI_OK){
JNI_OK){
...error
...error hanling
hanling
}}
Advanced JNI
232
Monitor Entry and Exit
The MonitorEnter operation takes a jobject as an
argument and blocks if another thread has
already entered the monitor associated with the
jobject.
Never call MonitorExit when the current thread
does not hold the monitor
(IllegalMonitorStateException will be raised).
Failure to call MonitorExit will most likely lead to
deadlocks.
It is preferable to use static synchronized
native methods (inside Java) for simplicity.
Advanced JNI
233
Monitor Wait and Notify
No JNI functions correspond directly to wait(),
notify() and notifyAll() methods in the Object
class.
Native code may use the JNI method call
mechanism to invoke the methods in the java
API.
void
void JNU_MonitorWait
JNU_MonitorWait (JNIEnv
(JNIEnv *env,
*env, jobject
jobject object,
object, jlong
jlong timeout){
timeout){
(*env)->CallVoidMethod(env,object,
(*env)->CallVoidMethod(env,object, MID_Object_wait,
MID_Object_wait, timeout);
timeout);
}}
The method id has been
calculated elsewhere
Advanced JNI
234
Thread Models
JNI programmers must pay attention to the
thread model of the operating system.
Different JVMs may implement different thread
models:
Native thread model The operating system
manages all the essential thread operations.
User thread model The application code
implements the thread operations.
Advanced JNI
235
Thread Models
Native supporting JVMs - You can use the
native thread synchronization primitives (such
as mutex_lock), or other thread functions (such
as creating threads - thr_create on solaris).
User thread model JVMs - Native code should
either link with the JVM package or use thread
operations within java code.
Advanced JNI
236
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
237
Exceptions Handling
Two types of errors exist when dealing with
native code:
Errors that occur as result of issuing JNI function
calls.
Regular errors that happen in native code.
This chapter will focus on the first type: JNI
related errors.
Advanced JNI
238
Exceptions Handling
A pending exception raised through JNI does
not immediately disrupt the native method
execution.
Notice This behavior is different from
exceptions behavior in Java immediate
transfer of the flow control to the catch block.
You must explicitly implement the control flow
after an exception has occurred.
Advanced JNI
239
Exceptions Handling
The JNI provides functions that allow your
native methods to throw Java exceptions:
jint ThrowNew (JNIEnv *env, jclass clazz, const char* message);
Most JNI functions use a combination of error
codes and Java exceptions to report error
conditions.
For example, to check an error condition after
invoking GetFieldID function, you might:
Check if the return value is 0.
Call the JNI function ExceptionOccurred.
Advanced JNI
240
Exceptions Handling - Example
Check for the return code
...
...
jclass
jclass cls
cls == (*env)->GetObjectClass(env,
(*env)->GetObjectClass(env, obj);
obj);
jmethodID
jmethodID mid
mid == (*env)->GetMethodID(env,
(*env)->GetMethodID(env, cls,
cls, "callback",
"callback", "()V");
"()V");
jthrowable
jthrowable exc;
exc;
if
if (mid
(mid ==
== 0)
0) {{
return;
return;
//error
//error occurred
occurred
}}
Advanced JNI
241
Exceptions Handling - Example
Use ExceptionOccurred
(*env)->CallVoidMethod(env,
(*env)->CallVoidMethod(env, obj,
obj, mid);
mid);
exc
exc == (*env)->ExceptionOccurred(env);
(*env)->ExceptionOccurred(env);
if
if (exc)
(exc) {{
jclass
jclass newExcCls;
newExcCls;
Print a Debug Message
(*env)->ExceptionDescribe(env);
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
(*env)->ExceptionClear(env);
newExcCls
newExcCls == (*env)->FindClass(env,"java/lang/IllegalArgumentException");
(*env)->FindClass(env,"java/lang/IllegalArgumentException");
if
if (newExcCls
(newExcCls ==
== 0)
0) {{
return;
return;
}}
(*env)->ThrowNew(env,
(*env)->ThrowNew(env, newExcCls,
newExcCls, "thrown
"thrown from
from CC code");
code");
}}
Advanced JNI
242
Exceptions Handling
When the native code catches and handles an
exception, it can either:
Clear the pending exception (Exception clear) and
execute its own handling code.
Return immediately.
It is extremely important to check, handle and
clear a pending exception before calling any
subsequent JNI functions. Failure to do so leads
to unexpected results.
Advanced JNI
243
Exceptions Handling
Functions for checking exceptions:
ExceptionCheck(env) returns JNI_TRUE when
there is a pending exception (or JNI_FALSE).
ExceptionOccured(env) Returns a reference to
jboolean
== (*env)->ExceptionCheck(env);
jboolean
hasException
(*env)->ExceptionCheck(env);
thehasException
exception
objec.t
jthrowable
jthrowable exc
exc == (*env)->ExceptionOccurred(env);
(*env)->ExceptionOccurred(env);
*hasException
*hasException == exc
exc !=
!= NULL;
NULL;
(*env)->DeleteLocalRef(env,
(*env)->DeleteLocalRef(env, exc);
exc);
//local
//local reference
reference management
management
Advanced JNI
244
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
245
Encoding & Internationalization
The Java Virtual Machine represents strings in
Unicode format.
Most native platforms represent strings in locale
specific encoding.
In order to convert properly between strings
certain rules apply:
Use GetStringUTFChars and GetStringUTFRegion
to convert between jstrings and locale-specific
strings, only if UTF-8 happens to be the native
encoding on the platform.
Advanced JNI
246
Creating jstrings from Native Strings
For converting a native string into a jstring use
this String constructor:
public String (byte[] bytes)
jstring JNU_NewString (JNIEnv *env, const char *str)
jstring JNU_NewString (JNIEnv *env, const char *str)
{
{
jstring result;
jstring result;
jbyteArray bytes = 0;
jbyteArray bytes = 0;
int len;
int len;
A global reference to
len = strlen(str);
len = strlen(str);
java.lang.String class
bytes = (*env)->NewByteArray(env, len);
bytes = (*env)->NewByteArray(env, len);
if(bytes != NULL){
if(bytes != NULL){
(*env)->SetByteArrayRegion (env, bytes, 0, len, (jbyte*)str);
(*env)->SetByteArrayRegion (env, bytes, 0, len, (jbyte*)str);
result = (*env)->NewObject (env, Class_java_lang_String, MID_String_init, bytes);
result = (*env)->NewObject (env, Class_java_lang_String, MID_String_init, bytes);
(*env)->DeleteLocalRef(env, bytes);
(*env)->DeleteLocalRef(env, bytes);
return result;
return result;
}
}
return NULL;
The method
return NULL;
}
}
constructor
Advanced JNI
id of the String
247
Translating jstrings to Native Strings
For converting a jstring into the native encoded
string use the String.getBytes method.
char
char ** JNU_GetStringNativeChars
JNU_GetStringNativeChars (JNIEnv
(JNIEnv ** env,
env, jstring
jstring jstr)
jstr)
{{
jbyteArray bytes = 0;
jbyteArray bytes = 0;
char
char ** result
result == 0;
0;
Error handling code
was removed for
clarity
bytes
bytes == (*env)->CallObjectMethod(env,
(*env)->CallObjectMethod(env, jstr,
jstr, MID_String_getBytes);
MID_String_getBytes);
jint
jint len
len == (*env)->GetArrayLength(env,
(*env)->GetArrayLength(env, bytes);
bytes);
result
result == (char*)malloc(len+1);
(char*)malloc(len+1);
(*env)->GetByteArrayRegion(env,bytes,0,len,(jbyte*)result);
(*env)->GetByteArrayRegion(env,bytes,0,len,(jbyte*)result);
result[len]
result[len] == 0;
0; /*Null
/*Null termination*/
termination*/
return
return result;
result;
}}
Advanced JNI
248
Converting to UTF-8 Strings
Unicode strings represent characters as 16-bit
values, whereas UTF-8 strings use an encoding
schema that is upward compatible with 7-bit
ASCII strings.
GetStringUTFChars function converts the
jstring reference (Unicode) into a C string (UTF8).
GetStringUTFChars might throw an
OutOfMemoryError when the allocation failed.
Advanced JNI
249
UTF-8 Strings - Example
jbyte*
jbyte* Convert
Convert (JNIEnv
(JNIEnv *env,
*env, jobject
jobject obj,
obj, jstring
jstring prompt)
prompt)
{{
char
char buf[128];
buf[128];
const
const jbyte
jbyte *str;
*str;
str
str == (*env)->GetStringUTFChars
(*env)->GetStringUTFChars (env,
(env, prompt,NULL);
prompt,NULL);
if(str==NULL)
if(str==NULL)
{{
return
return NULL;
NULL; //OutOfMemory
//OutOfMemory already
already thrown
thrown
}}
(*env)->ReleaseStringUTFChars
(*env)->ReleaseStringUTFChars (env,
(env, prompt,
prompt, str);
str);
return
return str;
str;
}}
Indicates that the native method no longer
needs the UTF-8 string
Advanced JNI
250
Construct a New String
To construct a new java.lang.String you can use
the JNI function NewStringUtf.
This function works only on UTF-8 format.
The newly constructed java.lang.String
represents the same sequence of Unicode
characters as the given UTF-8 string.
Notice if the operating system supports
Unicode as the native string format, you can
use: GetStringChars, ReleaseStringChars
functions.
Advanced JNI
251
Chapter Contents
JNI Recap
Local & Global References
Memory Management & GC
Threads
Handling Exceptions
Encoding & Internationalization
Ten JNI Best Practices
Advanced JNI
252
1. Dont Forget Error Checking
JNI does not rely on any particular native
exception mechanism.
Programmers are required to perform explicit
checks after every JNI function call that could
possibly raise an exception.
Exception checks are necessary to ensure that
the application is robust.
Advanced JNI
253
2. Cache Field and Method IDs
Native code obtains field and method IDs from
the virtual machine.
However, Field and method lookups using name
and type strings are slow.
Caching IDs may lead to a performance gain.
Advanced JNI
254
3. Check the Validity of Arguments
JNI functions do not attempt to detect or recover
from invalid arguments.
Passing NULL or oxFFFFFFFF to a JNI function
that expects a reference leads to incorrect
results or virtual machine crashes.
Code that uses the library is responsible to
make sure that all the arguments are valid.
Advanced JNI
255
4. Terminate Unicode Strings
Unicode strings obtained from GetStringChars
or GetStringCritical are not NULL terminated.
In order to know the number of 16-bit Unicode
characters call GetStringLength.
Notice some operating systems, like Windows
NT, expect two trailing zero byte values to
terminate Unicode strings.
Advanced JNI
256
5. Dont Violate Access Control Rules
JNI does not enforce access control
restrictions that are expressed in java
through the use of modifiers such as
private, final
Native code may bypass these access
checks (it might modify any memory).
However, bypassing might lead to
undesirable results (like changing
immutable objects).
Advanced JNI
257
6. Pay Attention to Encoding
Strings in the JVM consist of Unicode
characters.
Native strings are usually in a local-specific
encoding.
Use dedicated functions to translate between
Unicode jstrings and locale specific native
strings.
Advanced JNI
258
7. Free Virtual Machine Resources
Forgetting to free JVM resources may cause
objects to be pinned indefinitely.
This might lead to memory fragmentation or to a
memory leak.
Be particularly careful in code paths that are
only executed when there is an error.
Advanced JNI
259
8. Avoid Excessive Local References
Excessive local reference creation causes the
program to hold memory unnecessarily.
An unnecessary local reference wastes memory
both for the referenced object and the reference
itself.
Pay special attention to long running native
methods, loops, and utility functions.
Advanced JNI
260
9. Use the JNIEnv in Its Thread
The JNIEnv can be used only in the thread with
which it was associated.
Never use the pointer from one thread by
another thread.
Advanced JNI
261
10. Avoid Using Invalid References
Local references are valid only inside a single
invocation of a native method.
Native code should not store a local reference
in a global variable and expect to use it in a
later invocations of the native methods.
Local references are valid only within the thread
in which they are created.
Advanced JNI
262
Key Points
JNI enables a JVM-independent
integration of Java and native code.
For using JNI properly you must take
care of these issues:
Exception handling.
Multiple threads.
Memory management.
Encoding issues.
Advanced JNI
263