Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

Androiding in Parallel

, 12 Dec 2013
Parallel processing in Android native code

Editorial Note

This article is in the Product Showcase section for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.

Parallel processing in Android native code

For those who have been residing underneath particularly large chunks of mineral deposits, it has become fashionable recently to build games and other entertainment applications for mobile devices. In fact, a very good argument can be made that the multi-billion (if not –trillion, by this point) dollar industry that comprises the mobile computing space is largely driven by the entertainment industry. The ease with which users could purchase games for their devices, carry those devices around with them everywhere they went, and play them in what my mother used to call the "quiet little moments of life"—such as standing in lines, riding in vehicles, or waiting for one’s dinner date to show up—is a huge part of why consumers are parting with large amounts of cash in small amounts at a time.

But only if the games don’t suck.

Building smoothly-animated, responsive, well-performing games on mobile devices is key to developers (and their companies) tapping in to this lucrative revenue stream—the consumer patience for games that lag, struggle, or simply run slowly is minimal. (That same ease by which consumers can acquire your application also means it’s trivial for them to switch away from your application and go buy somebody else’s.) And while this isn’t true solely for games, most business applications simply don’t make use of the CPU horsepower that a game often requires.

For developers on the Android platform, getting things to run quickly will sometimes mean having to drop out of Java and write native code. In fact, conventional wisdom holds that most, if not all, Android games should be written such that the "core" of the game is written in native code, if the game has any sort of even moderate animation requirements. However, for a lot of developers, dropping down to native code means writing in C++, and for a lot of developers, writing code in C++, particularly really fast code in C++, means spending a lot of time in the debugger. Throw in a need to write that code such that it can execute across multiple threads simultaneously, and it becomes tempting to simply wait for the next generation of Android hardware, on the grounds that "it’ll run great on that new hardware (and then I won’t have to debug it)".

Fortunately, Intel has stepped up, and provided the Android community with a version of their Threading Building Blocks (TBB) library for the Android platform. Armed with that, and the Google Native Development Kit, it’s a lot less frightening to write parts of your Android app in C++, accessed from Java via the JNI interface, as a way of getting the best of both worlds. If you’re not familiar with said library, Intel maintains a website that contains all of the TBB documentation at http://software.intel.com/en-us/intel-tbb/, and the download itself has a wide range of samples on how to use TBB, in the "samples" directory off the root of the install. In this article, we’re just going to focus on the TBB/Android integration.

By the way, Intel’s investment into Android certainly doesn’t end here—they’ve also recently released a revamped Android emulator for Intel-based CPU host platforms, so if you haven't already updated your Android SDK Manager to pull it down, either do so, or download the new emulator directly here. The speed difference is remarkable, and given the cost (free), it seems a pretty easy win.

Getting Started

As with all libraries, the starting point for using TBB begins with downloading the latest version from the open source website, available at http://software.intel.com/en-us/intel-tbb/. From the top menu, "Download" and then "Stable Releases", and the three versions of TBB (Windows, Linux, Mac OSX) await the mouse click. Having said that, though, the version the Android developer wants, regardless of the platform on which they’re writing their Android application code, is the Linux version. The TBB site points this out on the Linux download link, but developers download so much stuff for their chosen development platform that sometimes it takes a moment to realize that the TBB library is for the target platform—Android—and not the developer host platform.

Once downloaded, open up the archive and store it somewhere convenient. Inside the archive’s "lib" folder, the "android" directory contains the Android-compatible binaries that will be needed to link in the TBB libraries, and the header files live (as is typical) in the archive’s "include" directory. Specifically, the TBB includes are in the "include/tbb" directory, but since common C++ practice is to use the directory name as part of the header include (so that the include looks like "#include <tbb/parallel_for.h>", for example) as a way of figuring out which headers come from which library, it’s better to just put the "<TBB_SDK>/include" directory on the include path for the C++ compiler.

Basics

Architecturally, an Android application that uses TBB is going to be something of a split personality: parts of it written in typical Java/Android, and parts of it written in C++ and accessed via JNI. Technically, it’s impossible to write a full C++ application for Android, though there are "hacks" that get around this restriction. This means that any developer looking to get started with TBB for Android is going to need to be familiar with the JNI tools and API along with Java and C++, or else (more likely) the work will be done split across developers—some familiar with Java, some with C++, using the JNI layer as a "black box". Make no mistake, this will complicate the development process some, but the performance benefits of both native code and taking full advantage of the device hardware can more than offset the costs.

Creating an Android project that uses JNI is trickier than a "normal" Java-only Android project; it requires the use of the Android Native Development Kit (NDK), which also then in turn requires native tools and build scripts (Makefile). Thus, demonstrating the TBB here is going to be an extremely simple demo, to keep things as simple as possible.

Step 1: "Push me!"

To start, we need an Android application, one which will "do something" in response to a button press, and display the results of that button press in a Toast message. Thus, after creating the project in your tool set of choice (Eclipse, IDEA, or, my favorite, the venerable command-line), add a big ol’ button to the main activity layout, a la:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="Push Me!"
    android:onClick="onButtonPushed" />
</LinearLayout>

And remember, add a message-handler named "onButtonPushed" to the activity, as well:

package com.tedneward.tbbdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.*;
import android.widget.*;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void onButtonPushed(View view)
    {
        Toast.makeText(this, "Pushed me!",
Toast.LENGTH_SHORT).show();
    }
}

Nothing much to see, yet. Well, not entirely true: build it, install it, run it, and it does exactly what it appears to do: display a button, and when pushed, pops the "Pushed me!" Toast to the user. Hardly impressive, but it’s a working scaffold from which to add JNI functionality, and then the TBB bits.

Step 2: "Go Native!"

Next, we need to integrate a native JNI library (and the NDK) as part of the build. The Android NDK has a number of samples, not to mention docs, describing how to use JNI as part of an Android project, but a brief recap/summary always helps. Assuming that the NDK is already installed and on the PATH, integrating JNI code into an Android project is remarkably similar to how it would work for any Java/JNI project: a Java class contains the native-decorated static Java methods that will be the entry into the native code library, a separate directory contains the C/C++ source and headers that are generated by the "javah" Java utility, and a separate build script (an Android.mk Makefile) describes the necessary pieces required by the "ndk_build" tool to do the actual native compilation.

First, we create the Java class that will contain the native calls:

package com.tedneward.tbbdemo;

public class TBBNative
{
    static
    {
        System.loadLibrary("tbb-native");
    }

    public static native int calculate();
}

While it’s possible to create non-static native methods, it’s usually easier and clearer to treat the native calls as entirely static, maintaining no internal per-instance state. Note, also, the static initialization block that calls System.loadLibrary(); which loads the specified native library using whatever platform decorations are appropriate for the underlying platform, whether that’s suffixing ".dll" (for Windows) or prefixing "lib" and suffixing ".so" (for Linux and, in this case, Android).

Next, we need to write the C/C++ source (which the NDK expects to be in a "jni" directory as a peer to the Android "src" directory, so create that if you’ve not done so yet), but getting the exact declarations for the code that will be linked from the JVM can be tricky, which is why the JDK provides the "javah" command: once the Java class is compiled, "javah" takes a class name at the command-line and generates a skeleton C header and implementation file. Because it takes a Java class name (not source file) as its input, the Java parts of the project need to be built before we can run "javah":

javah -classpath ../bin/classes com.tedneward.tbbdemo.TBBNative

The "-classpath" argument is necessary to point to the temporary "classes" directory used as part of the Android build, and it spits out a C-style header file, so we run it from the "jni" directory to get the resulting header file in the right place. The header technically isn’t necessary, but it does contain the declaration for the C implementation, and based on the examples above, that declaration looks like:

/*
 * Class:     com_tedneward_tbbdemo_TBBNative
 * Method:    calculate
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_tedneward_tbbdemo_TBBNative_calculate
  (JNIEnv *, jclass);

All of this is described in excruciating detail in the Java JNI documentation, so if all of this is brand-new, make sure to check that out or the Sheng Liang book (http://www.amazon.com/The-Java-Native-Interface-Specification/dp/0201325772) on the subject.

Implementing the native library is what TBB will be about, but for now, let’s just make sure the build process works, so a simple C/C++ stub suffices:

#include "com_tedneward_tbbdemo_TBBNative.h"

JNIEXPORT jint JNICALL Java_com_tedneward_tbbdemo_TBBNative_calculate
                       (JNIEnv* jniEnv,
                        jclass jniClass)
{
    return 0;
}

The NDK needs to know how to build this, and expects an Android.mk Makefile to help it with the per-application-specific details:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := tbb-native
LOCAL_SRC_FILES := com_tedneward_tbbdemo_TBBNative.cpp

include $(BUILD_SHARED_LIBRARY)

The LOCAL_MODULE setting must correspond (in both spelling and case) to the value passed to the System.loadLibrary() call in the Native.java source file—this is the name of the native library that will be generated. And, of course, the name of the source file can be whatever the C/C++ compiler accepts as a legitimate filename—the javah-generated filenames are often a bit awkward to work with over time.

Assuming the header, source and Android.mk files have no typos, and that NDK is on the PATH, issuing an "ndk-build" from the "jni" directory should result in something like the following:

Ted-Newards-MacBook-Pro:jni ted$ ndk-build
[armeabi] Compile++ thumb: tbb-native <= com_tedneward_tbb_Native.cpp
[armeabi] StaticLibrary  : libstdc++.a
[armeabi] SharedLibrary  : libtbb-native.so
[armeabi] Install        : libtbb-native.so =>
libs/armeabi/libtbb-native.so
Ted-Newards-MacBook-Pro:jni ted$ ls ../libs/
armeabi/
Ted-Newards-MacBook-Pro:jni ted$ ls ../libs/armeabi/
libtbb-native.so*

Once the native library is built, running an "ant debug install" again should compile cleanly, and install the new application—this time with native code included—onto the device.

Step 3: "Parallelize It!"

The obvious next steps are to integrate TBB itself, which means modifying the native code to use the TBB library to do some kind of calculation in parallel. In a game, for example, with multiple pieces on the field that all need to calculate their next steps, this is an easy case for TBB’s "parallel_for", by putting the work into each leg of the parallelized for loop.

The TBB library needs to be built with particular settings in place as part of the C++ compile, so some changes to the Android.mk file are required, shown below:

LOCAL_PATH := $(call my-dir)
TBB_PATH := /opt/local/tbb42_20131003oss/

include $(CLEAR_VARS)

LOCAL_MODULE    := tbb-native
LOCAL_SRC_FILES := com_tedneward_tbbdemo_TBBNative.cpp
LOCAL_CFLAGS += -DTBB_USE_GCC_BUILTINS -std=c++11 –I$(TBB_PATH)/include
LOCAL_LDLIBS := -ltbb -L./
-L$(TBB_PATH)/<path_to_libtbb_so>
include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(TBB_PATH)/lib/android

include $(CLEAR_VARS)
LOCAL_MODULE    := libtbb
LOCAL_SRC_FILES := libtbb.so
include $(PREBUILT_SHARED_LIBRARY)

Correspondingly, the native code now includes the TBB headers, and uses "parallel_for" to do a rather pointless calculation. The calculation itself isn’t what’s important—it’s the fact that we’ve got parallel calculations going on. From here, it shouldn’t be hard to adapt whatever parallel/concurrent calculations your game needs to do, whatever that may be.

Summary

Intel’s gone to some great lengths to support native coding on the Android platform, and the Threading Building Blocks are a perfect example of that. Getting the necessary parts in place to build a hybrid native/Java Android app aren’t trivial, but once in place, the rest of the story gets a lot easier. Enjoy!

To learn more about Intel tools for the Android developer, visit Intel® Developer Zone for Android.

Other Related Articles

To learn more about Intel tools for the Android developer, visit Intel® Developer Zone for Android.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ted Neward
Web Developer
United States United States
Ted Neward is an independent consultant specializing in high-scale enterprise systems, working with clients ranging in size from Fortune 500 corporations to small 10-person shops. He is an authority in Java and .NET technologies, particularly in the areas of Java/.NET integration (both in-process and via integration tools like Web services), back-end enterprise software systems, and virtual machine/execution engine plumbing.
 
He is the author or co-author of several books, including Effective Enterprise Java, C# In a Nutshell, SSCLI Essentials, Server-Based Java Programming, and a contributor to several technology journals. Ted is also a Microsoft MVP Architect, BEA Technical Director, INETA speaker, former DevelopMentor instructor, frequent worldwide conference speaker, and a member of various Java JSRs. He lives in the Pacific Northwest with his wife, two sons, and eight PCs.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 12 Dec 2013
Article Copyright 2013 by Ted Neward
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid