Introduction
Recently we posted the "Windows* 8 Tutorial: Writing a Multithreaded Application for the Windows Store* using Intel® Threading Building Blocks". There we stated that the parallel calculation engine can be ported easily to other mobile or desktop platforms. Android is a good example of such a mobile platform.
In a recently posted stable release of Intel Threading Building Blocks (Intel® TBB), we have added experimental support for Android applications; i.e., building Intel TBB libraries for use in Android applications via the JNI interface. You can download this release from threadingbuildingblocks.org.
To start the process on a Linux* host, unpack the Intel TBB source distribution, source the <unpacked_dir>/build/android_setup.csh script, and build the libraries. Building the libraries is necessary because development releases are distributed in source form only. The <unpacked_dir>/build/index.android.html file contains instructions to configure the environment and build the library on Linux.
Assuming that gnu make 3.81 is available in the %PATH% (on a Microsoft Windows* host platform) and $PATH (on a Linux host) we need to issue the following command in the NDK environment to build the Intel TBB libraries for Android:
gmake tbb tbbmalloc target=android
That’s all that is needed for the library build; we can now move to build the example using Eclipse*. For the example below, I’ll use Android SDK Tools Rev.21 and Android NDK Rev 8C on Windows* to illustrate the process of cross-platform development.
Create a new project using a default template «New Android Application». For simplicity, we name it "app1", the same as in the previous post:
![Image 1](/KB/android/819599/android1.png)
Select FullscreenActivity
as the Activity. That’s it for the template. Please note that com.example* is not an acceptable package naming for Google Play* but it is good enough for our example.
Then add a couple of buttons to the main frame. After adding these, the XML file of the main frame (app1/res/layout/activity_fullscreen.xml) will look like this:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0099cc"
tools:context=".FullscreenActivity" >
<TextView
android:id="@+id/fullscreen_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:keepScreenOn="true"
android:text="@string/dummy_content"
android:textColor="#33b5e5"
android:textSize="50sp"
android:textStyle="bold" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true" >
<LinearLayout
android:id="@+id/fullscreen_content_controls"
style="?buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="74dp"
android:layout_gravity="bottom|center_horizontal"
android:background="@color/black_overlay"
android:orientation="horizontal"
tools:ignore="UselessParent" >
<Button
android:id="@+id/dummy_button1"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dummy_button1"
android:onClick="onClickSR" />
<Button
android:id="@+id/dummy_button2"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dummy_button2"
android:onClick="onClickDR" />
</LinearLayout>
</FrameLayout>
</FrameLayout>
And the string file (app1/res/values/strings.xml) will look like
="1.0"="utf-8"
<resources>
<string name="app_name">Sample</string>
<string name="dummy_content">Reduce sample</string>
<string name="dummy_button1">Simple Reduce</string>
<string name="dummy_button2">Deterministic Reduce</string>
</resources>
Then add buttons handlers:
private native float onClickDRCall();
private native float onClickSRCall();
public void onClickDR(View myView) {
TextView tv=(TextView)(this.findViewById(R.id.fullscreen_content));
float res=onClickDRCall();
tv.setText("Result DR is n" + res);
}
public void onClickSR(View myView) {
TextView tv=(TextView)(this.findViewById(R.id.fullscreen_content));
float res=onClickSRCall();
tv.setText("Result SR is n" + res);
}
and library loads to the FullscreenActivity.java file:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
System.loadLibrary("gnustl_shared");
System.loadLibrary("tbb");
System.loadLibrary("jni-engine");
}
In the case of the "tbb" library everything should be clear, and the "gnustl_shared" library is required to support the C++ language features of TBB. However, for the "jni-engine" library we need to go into more details.
"jni-engine" is a С++ library that implements a calculation engine and exports C-interfaces for JNI calls named onClickSRCall()
and onClickSRCall()
.
According to NDK development rules, create folder "jni" inside the workspace and create 3 files there specific for our "jni-engine" library.
These files are:
Android.mk
(text in <> brackets there is something that should be replaced with actual values)
LOCAL_PATH := $(call my-dir)
TBB_PATH := <path_to_the_package>
include $(CLEAR_VARS)
LOCAL_MODULE := jni-engine
LOCAL_SRC_FILES := jni-engine.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)
include $(CLEAR_VARS)
LOCAL_MODULE := libtbb
LOCAL_SRC_FILES := libtbb.so
include $(PREBUILT_SHARED_LIBRARY)
Application.mk
APP_ABI := x86
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti
APP_STL := gnustl_shared
jni-engine.cpp
#include <jni.h>
#include "tbb/parallel_reduce.h"
#include "tbb/blocked_range.h"
float SR_Click()
{
int N=10000000;
float fr = 1.0f/(float)N;
float sum = tbb::parallel_reduce(
tbb::blocked_range<int>(0,N), 0.0f,
[=](const tbb::blocked_range<int>& r, float sum)->float
{
for( int i=r.begin(); i!=r.end(); ++i )
sum += fr;
return sum;
},
[]( float x, float y )->float
{
return x+y;
}
);
return sum;
}
float DR_Click()
{
int N=10000000;
float fr = 1.0f/(float)N;
float sum = tbb::parallel_deterministic_reduce(
tbb::blocked_range<int>(0,N), 0.0f,
[=](const tbb::blocked_range<int>& r, float sum)->float
{
for( int i=r.begin(); i!=r.end(); ++i )
sum += fr;
return sum;
},
[]( float x, float y )->float
{
return x+y;
}
);
return sum;
}
extern "C" JNIEXPORT jfloat JNICALL Java_com_example_app1_FullscreenActivity_onClickDRCall(JNIEnv *env, jobject obj)
{
return DR_Click();
}
extern "C" JNIEXPORT jfloat JNICALL Java_com_example_app1_FullscreenActivity_onClickSRCall(JNIEnv *env, jobject obj)
{
return SR_Click();
}
We use the same algorithms that we used in the previous blog.
When we use the NDK to build, it compiles libraries to the required folders including our libraries libjni-engine.so, libgnustl_shared.so and libtbb.so.
Next, switch back to Eclipse and build the app1.apk file. Now the application is ready to install on AVD or actual hardware. On AVD it looks like
![Image 2](data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)
That’s it! This simple application is ready and should be a good start towards writing a more complex parallel application for Android. And for those who used code from the previous blog, the application was successfully ported to Android.
* Other names and brands may be claimed as the property of others.
Related Articles and Resources
To learn more about Intel tools for the Android developer, visit Intel® Developer Zone for Android.