android - files.meetup.comfiles.meetup.com/1698110/capers - android.pdf• many android developers...

58
Developing performance critical components using the Android NDK ANDROID

Upload: vuongminh

Post on 02-Apr-2018

228 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

Developing performance critical components using the Android NDK

ANDROID

Page 2: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 3: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

HELLO WORLDC/C++

Page 4: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

Java Native Interface

Page 5: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

WHAT IS SNORKEL-EMBEDDED?

Web application development API written in C/C++

Page 6: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

TODAYS WEB APPLICATIONS

• Broken into logical chunks called tiers

• Presentation tier

• Client browser

• Explorer, Chrome, Firefox, Safari, etc….

• Application tier (application logic)

• Web Server

• Apache, Tomcat, IIS, etc…

• Server side dynamic content engine

• ASP, ASP.NET, CGI, ColdFusion, JSP/Java, PHP, Perl, Python, Ruby on Rails or Struts2, etc…

• Database tier

• SQL, Oracle, proprietary,…

Page 7: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE APPLICATION TIER CONSISTS OF LOOSELY

COBBLED TOGETHER BLOCKS OF STUFF

Web Server

Servlet Container

CGI

PHPFile System

Page 8: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

TODAYS WEB APPLICATIONS ARE COMPLEX

• Over componentized

• To many moving parts

• To many things that can break

• Have obfuscated away the underlying hardware

• Difficult to debug and develop

• Suffer from code bloat – trying to be everything to everyone

• Require beefy systems to run

• Employ complex frameworks that are equally complex to configure for the average user

• Not conducive to smaller devices with limited resources

• Printers, Cameras, toasters,…, appliances, Android devices, etc…

• More resources equals shorter battery life and less resources to run other things

• Layered with prerequisites and third party dependencies

• Are not easily implemented in native solutions

• C/C++ based applications

Page 9: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

Todays

Applications

“Everything should be made as simple as possible,

but not simpler”

Albert Einstein

Page 10: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

ONE SOLUTION, ONE EXECUTABLE EQUALS

SNORKEL-EMBEDDED

Web Application

File System

Web Server

Servlet Container

CGI

PHPFile System

Page 11: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

ADVANTAGES OF SNORKEL-EMBEDDED

• Written in C

• Extremely portable

• Compile everywhere, debug once

• Written using cross platform standard APIs

• Shorter development cycles

• Existing native code can be reused.

• The Snorkel API is easy to learn and the average developer can begin implementing

Snorkel with in a couple of days.

• Web applications are written within weeks instead of months.

• No third party dependencies = easier configuration and installation

Page 12: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

ADVANTAGES OF SNORKEL -- CONTINUED

• Snorkel based web applications require far fewer resources to run

• Leverages the latest system architectures such as NUMA

• Reduced context switching

• Less page faulting

• Does more with far fewer threads (4 threads = 200 concurrent users)

• Lockless memory management

• Employs memory segregation which provides efficient garbage collection

• Outperforms Apache, IIS, and Tomcat for both static and dynamic content delivery.

• Supports not only HTTP/HTTPS but also proprietary protocol development

Page 13: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

GOING NATIVE ON ANDROID

Page 14: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 15: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

WHY NATIVE?

• In many cases well written native components in C are faster, leaner, and more efficient

than their Java based counterparts.

• Porting existing C/C++ code to Android instead of converting it to JAVA means getting to

market faster.

• Going forward beginning with Android (Gingerbread) Google has beefed up the NDK and

added a NativeActivity class as well as a new helper class for native development to

attract more developers.

• Soon, developers will be able to choose to work with JAVA mixed with C/C++, pure

JAVA, or pure C/C++.

Page 16: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

WHAT’S THE BEST APPROACH FOR

IMPLEMENTING NATIVE CODE

• Gingerbread is not widely supported yet

• Nexus S

• JNI is still the practiced approach

• Allows you to keep your core code in C/C++

• Allows you to quickly migrate to other non-JAVA or JAVA based platforms that are

also based on a Linux Kernel

• Many Android developers have taken this approach – writing a small JNI wrapper to

handle lifecycle management.

• Example: Angry Birds

Page 17: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

A CLOSER LOOK AT JNI

C Component

Java Libraries

Your Java Class

Java Virtual

Machine

Your class

methods

Page 18: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

A CLOSER LOOK AT JNI

Java Program

C Routine

C++ Class

C Debugger

Page 19: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

A CLOSER LOOK AT JNI

Functions

Libraries

Exceptions

Classes

JVM

C/C++ Java

JNI

Page 20: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

PREREQUISITES FOR NATIVE DEVELOPMENT

USING WINDOWS

• Windows XP (32-bit) or Vista (32 or 64-bit)

• JDK 1.6 or higher

• Cygwin 1.7 or higher

• GNU Awk or Nawk

• GNU Make 3.81 or higher

• Eclipse (Galileo) or higher

• Helios

• http://developer.android.com/sdk/ndk/overview.html

Page 21: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

LEARNING BY EXAMPLEA BETTER HELLO WORLD

HELLO

WORLD

Page 22: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

CREATING AN ANDROID PROJECT

Page 23: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 24: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 25: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

API LEVEL

Platform Version API Level

Android 3.0 11

Android 2.3.3 10

Android 2.3 9

Android 2.2 8

Android 2.1 7

Android 2.0.1 6

Android 2.0 5

Android 1.6 4

Android 1.5 3

Android 1.1 2

Android 1.0 1

Page 26: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 27: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

MAIN.XML

<?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"

>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello"

/>

</LinearLayout>

Page 28: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

STRINGS.XML

<?xml version="1.0" encoding="utf-8"?>

<resources>

<string name="hello">Hello World, MywebActivity!</string>

<string name="app_name">Myweb</string>

</resources>

Page 29: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

MYWEBACTIVITY.JAVA

package com.mycompany.myweb;

import android.app.Activity;

import android.os.Bundle;

public class MywebActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

}

}

Page 30: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

DESIGNING A UI

Page 31: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

TOOLS FOR UI DESIGN

• The Eclipse IDE – graphical layout tool

• Droid draw http://www.droiddraw.org/

Page 32: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

WRITING THE JAVA WRAPPER CLASS

Start

Stop

Status

Error

Messages

Page 33: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

WRITING THE JAVA WRAPPER CLASS

Page 34: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management
Page 35: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

package com.mycompany.myweb;

public class Server {

static final int RUNNING=1;

static final int DOWN=0;

static final int SNORKEL_SUCCESS=0;

static final int SNORKEL_ERROR=-1;

static {

System.loadLibrary("snorkel32");

System.loadLibrary("Server");

}

public native String lastError ();

public native int isRunning ();

public native int start (int port,

String rootDir,

int showDir);

public native int stop ();

}

Page 36: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

INTERFACING WITH C

lastError

isRunning

start

Server Class

JNI

Functions?

libsnorkel32.so

C – libServer.so

stop

Page 37: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

JNI NAMING CONVENTIONS

JNIEXPORT return_type JNICALL Java_package_ClassName_MethodName

(JNIEnv *env, jobject obj, arg0, arg1, arg2,…, argn)

Java_com_mycompany_myweb_Server_MethodName where

com_mycompany_myweb_Server identifies the class com.mycompany.myweb.Server

Must include <jni.h>

Page 38: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE LASTERROR METHOD

Server.lastError = Java_com_mycompany_myweb_Server_lastError

JNIEXPORT jstring JNICALL

Java_com_mycompany_myweb_Server_lastError (

JNIEnv *env,

jobject javaThis)

{

return (*env)->NewStringUTF (env, snrkl_lerr ());

}

• JNIEnv allows access to all JAVA classes from C/C++

• jobect allows C/C++ to access our JAVA class methods

Page 39: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE ISRUNNING METHOD

JNIEXPORT jint JNICALL

Java_com_mycompany_myweb_Server_isRunning (

JNIEnv *env,

jobject javaThis)

{

if (g_this_server)

return RUNNING;

return DOWN;

}

Page 40: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE STOP METHOD

JNIEXPORT void JNICALL

Java_com_mycompany_myweb_Server_stop (

JNIEnv *env,

jobject javaThis)

{

if (g_this_server)

snrkl_destroy (g_this_server);

g_this_server = 0;

}

Page 41: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE START METHOD

JNIEXPORT jint JNICALL

Java_com_mycompany_myweb_Server_start (

JNIEnv *env,

jobject javaThis,

jint port,

jstring rootString,

jint showDir)

{

const char *pszroot =

(*env)->GetStringUTFChars (env, rootString, 0);

if (g_this_server)

return SNORKEL_SUCCESS;

Page 42: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE START METHOD – CONTINUED

if (snrkl_init () != SNORKEL_SUCCESS)

return SNORKEL_ERROR;

g_this_server = srnkl_server (2, pszroot);

(*env)->ReleaseStringChars (env, pszroot,

(const jchar *)pszroot);

if ( !g_this_server)

return SNORKEL_ERROR;

if (showDir)

snrkl_srvset_show_dir (g_this_server, 1);

Page 43: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE START METHOD – CONTINUED

if (snrkl_srvadd_listener (g_this_server, port, 0)

== SNORKEL_ERROR)

{

snrkl_destroy (g_this_server);

g_this_server = 0;

return SNORKEL_ERROR;

}

/*

* disable IPV6 - not supported on Android yet

*/

snorkel_obj_set (g_this_server, snorkel_attrib_ipvers,

IPVERS_IPV4, SOCK_SET);

Page 44: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

THE START METHOD – CONTINUED

if (snrkl_start (g_this_server) != SNORKEL_SUCCESS)

{

snrkl_destroy (g_this_server);

g_this_server = 0;

return SNORKEL_ERROR;

}

return SNORKEL_SUCCESS;

}

Page 45: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

TYING IN THE SERVER CLASS TO THE MAIN

ACTIVITY CLASS

public class MywebActivity extends Activity {

Server m_server;

.

.

public void onCreate (Bundle savedInstanceState) {

super.onCreate (savedInstanceState);

m_server = new Server();

.

.

}

Page 46: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

BUILDING THE NATIVE COMPONENT

lastError

isRunning

start

Server Class

JNI

Java..lastError

libsnorkel32.so

C – libServer.so

stop

Java..isRunning

Java..start

Java..stop

Page 47: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

SETTING UP FOR NDK-BUILD

• NDK-BUILD is a build system for building Android native code

• Script that wraps the GCC compiler

• The easiest way to build native code

• Requires C/C++ source files to be located in the “jni” subdirectory of the current project.

• Operates on NDK build make files located in the “jni” subdirectory

• Android.mk

• Describes native sources to the NDK build system

• Application.mk

• Allows you to specify build type (release, debug)

• Targeted chipsets

• Usually run from within a Cgywin command shell

• Can be configured as part of the build process in Eclipse http://mobilepearls.com/labs/ndk-builder-in-eclipse/

Page 48: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

ANDROID.MK

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := snorkel32

LOCAL_SRC_FILES := snorkel/libsnorkel32.so

LOCAL_EXPORT_C_INCLUDES:=snorkel

include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := Server

LOCAL_SRC_FILES := Server.c

LOCAL_SHARED_LIBRARIES := snorkel32

include $(BUILD_SHARED_LIBRARY)

libsnorkel32.so

libServer.so

Page 49: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

TARGETING CHIPSETS/TOOLCHAINS FOR

OPTIMIZATION

• Default tool-chain is armeabi

• To date all released phones are based on ARM architecture

• Should be avoided unless there are significant performance gains on targeted devices

• Increases deployment size, since you have to include basic arm support along with

the optimized implementation

• Additional toolchains are specified in the Application.mk file

Page 50: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

APPLICATION.MK

APP_OPTIM := release

APP_ABI := armeabi armeabi-v7a

TARGET_CPU_ABI := armeabi-v7a

TARGET_CPU_ABI2 := armeab

Page 51: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

USING NDK-BUILD

• Run from Cygwin command prompt in “jni” directory

• When run without command line options builds a release build

• Located in the NDK directory “installation_directory/android-ndk-r5”

$ /home/android-ndk-r5/ndk-build

Compile thumb : Server <= Server.c

Prebuilt : libsnorkel32.so <= jni/snorkel/

SharedLibrary : libServer.so

Install : libServer.so => libs/armeabi/libServer.so

Install : libsnorkel32.so => libs/armeabi/libsnorkel32.so

Page 52: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

REUSING NATIVE RUNTIMES OR THIRD PARTY

LIBRARIES

MyWeb

libsnorkel32.so

libServer.so

Page 53: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

DEBUGGING NATIVE CODE

• Compile with debug option

• Change or add “APP_OPTIM := debug” to Application.mk file

• Set debuggable to true in manifest.xml

• Run NDK-BUILD with debug option “NDK-DEBUG=1”

• No easy way to debug from within IDE

• Sequoyah http://www.eclipse.org/sequoyah/documentation/native_debug.php

• DDD, GDB

• ndk-gdb

• DDMS from within Eclipse and arm-eabi-addr2line.exe

Page 54: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

USING DDMS AND ADDR2LINE TO IDENTIFY THE

LOCATION OF A CRASH

• Trap the crash using logcat from within adb by issuing the command:

adb logcat

• Trap crash from within the DDMS view in Eclipse which has a logcat window opened by

default.

Page 55: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

OUTPUT FROM LOGCAT

I/ServiceManager( 417): Executing: /android/bin/app_process (link=/android/bin/app_process, wrapper=/android/bin/app_process)

I/DEBUG: -- observer of pid 417 starting --

I/appproc ( 417): App process is starting with pid=417, class=android/activity/ActivityThread.

I/DEBUG: -- observer of pid 417 exiting --

I/DEBUG: -- observer of pid 420 starting --

I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

I/DEBUG: pid: 373, tid: 401 >>> android.content.providers.pim <<<

I/DEBUG: signal 11 (SIGSEGV), fault addr 00000000

I/DEBUG: r0 ffffffff r1 00000000 r2 00000454 r3 002136d4

I/DEBUG: r4 002136c0 r5 40804810 r6 0022dc70 r7 00000010

I/DEBUG: r8 0020a258 r9 00000014 10 6b039074 fp 109ffcf8

I/DEBUG: ip 6b039e90 sp 109ffc0c lr 580239f0 pc 6b0156a0

I/DEBUG: #01 pc 6b0156a0 /android/lib/libjamvm.so

I/DEBUG: #01 lr 580239f0

Page 56: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

ADDR2LINE SCRIPT

@ECHO OFF

C:\cygwin\home\android-ndk-r5\toolchains\arm-eabi-4.4.0\prebuilt\windows\bin\arm-eabi-

addr2line.exe -f -e obj\local\armeabi\lib%1.so 0x%2

Page 57: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

IDENTIFYING THE LINE AND FILE THAT CRASH

OCCURS

>> addr2line snorkel32 0000acdc

buffer_vprintf

C:/cygwin/home/PFHWEC0/android_workspace/sailfish/jni/snorkel.c:6068

Page 58: Android - files.meetup.comfiles.meetup.com/1698110/Capers - Android.pdf• Many Android developers have taken this approach –writing a small JNI wrapper to handle lifecycle management

QUESTIONS

• More about JNI http://java.sun.com/docs/books/jni/

• WINGDB plugin for debugging native Android and other mobile type native components in

Visual Studio

• http://www.wingdb.com/wgMobileEdition.htm

• http://ian-ni-lewis.blogspot.com/2011/01/its-like-coming-home-again.html

• The SnorkelEMBEDDED project: www.snorkelembedded.webs.com