We now describe the basics of developing applications with Eclipse. We begin with a short C++ example that you can build and run in your development machine; then we will port the example to run on the Android device, first using Java, then using Java + native code (C/C++), and finally using only native code.
After you complete this topic you should be able to:
We will now create our first C++ example program using Eclipse. The goal of this lesson is to get you familiarized with the Eclipse environment, so we will focus on a simple program that you will run on your desktop computer.
#ifndef FIBONACCI_H_
#define FIBONACCI_H_
unsigned int Fibonacci( unsigned int n );
#endif /* FIBONACCI_H_ */
main.cpp
in the Source File: entry.#include <iostream>
#include "Fibonacci.h"
int main( int argc, char * argv[] )
{
std::cout << "Fibonacci(10) = " << Fibonacci( 10 ) << std::endl;
}
#include "Fibonacci.h"
unsigned int Fibonacci( unsigned int n )
{
if( n == 1 ) { return 1; }
if( n == 0 ) { return 0; }
return Fibonacci( n - 1 ) + Fibonacci( n - 2 );
}
Note: If you get an error message stating that the binary couldn't be found, go back to the previous step and make sure the project is built correctly. |
We will now debug the program to trace its execution.
Note: Debugging requires gdb to be in your PATH. On Windows, you will be either using Cygwin gdb or MinGW gdb. If you are using Cygwin as installed by CodeWorks for Android, gdb will be missing. Run setup.exe under NVPACK/cygwin, select "install from Internet" and install the gdb package (under Devel section). If this does not work yet, it could be because Cygwin recently changed the formatting of their mirror's folder structure to support both x86 and x64. Because of this, setup.exe downloaded before this change no longer work due to them looking for the ini at ftp.someMirrorName.com\cygwin , where the new location is ftp.someMirrorName.com\cygwin\x86 . To resolve the issue, you can try to download setup-x86.exe or setup-x86_64.exe into the NVPACK/cygwin folder and use it instead of setup.exe . |
main.cpp
and insert a breakpoint by double-clicking on the left margin as shown below. (Alternatively, right-click and select Toggle Breakpoint.) The blue dot is an indication that the breakpoint has been set.Note: If Eclipse complains that it can not find a source file, click on the Locate File... button, and browse to the location of the file. |
In the previous steps, we left many details uncovered. Eclipse has an internal Makefile builder that creates the Makefile based on the sources that you add to the project. That is why we were able to build the program successfully. In addition, Eclipse has different build configurations for a project. In this example, both Debug and Release configurations were created. The Debug configuration builds the program for debugging, while the Release turns on compiler optimizations for the final program. If you want to change the build properties, right-click on the project, and press Alt + Enter (on Linux and Windows), or Cmd + I (on Mac) to bring up the properties sheet. Under C/C++ Build, you will find the build options.
We will now create a similar Android project to run on our device. If this is the first time you develop an android application, it could be a good idea to visit first the getting started page for Android developers.
Note: Don't use spaces in the project name, otherwise native debugging will fail to find the symbols. |
src
and select New > Class. Fill out the class properties as shown — we want to create a class that inherits from android.app.Activity
within the package com.nvidia.example.fibonacci
.FibonacciActivity.java
and add a Fibonacci function to the class skeleton. Java doesn't have unsigned types, so we will use integers instead and handle negative numbers correctly. package com.nvidia.example.fibonacci; import android.app.Activity; public class FibonacciActivity extends Activity { int Fibonacci( int n ) {
if( n == 1 ) { return 1; }
if( n <= 0 ) { return 0; }
return Fibonacci( n - 1 ) + Fibonacci ( n - 2 );
}
}
onCreate
method to the FibonacciActivity
class: @Override
public void onCreate( Bundle savedInstance ) {
super.onCreate(savedInstance);
// Create the TextView
TextView tv = new TextView( this );
tv.setText( "Fibonacci(10) = " + Fibonacci( 10 ) );
setContentView( tv );
}
Note: After you copy and paste the code shown above, Eclipse will underline Bundle and TextView , and note them as undefined classes. These are Android framework classes that require an import declaration. To add the imports for these, hover the cursor over the underlined text, and select the import option from the possible fixes or press the shortcut combination Ctrl-Shift-M (Linux, Windows) or CMD-SHFT-M (on Mac). Of course, you can also just type the imports in, too.import android.app.Activity; |
AndroidManifest.xml
. Eclipse will open the manifest editor. Select the AndroidManifest.xml tab to view the xml file.<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nvidia.example.fibonacci"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".FibonacciActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
.apk
file that is pushed to the device and launched. The first time you run the application, you will be shown the "Auto Monitor Logcat" dialog. Choose Yes. If the dialog does not appear, go to Window > Show View > Other and select Logcat.This concludes our simple Java application tutorial.
See also:
|
Now that we have completed our first app, we will launch the debugger and trace execution of the Fibonacci function.
@Override
public void onCreate( Bundle savedInstance ) {
super.onCreate( savedInstance );
// Create the TextView
TextView tv = new TextView( this );
int fibo = Fibonacci( 10 );
tv.setText( "Fibonacci(10) = " + fibo );
setContentView( tv );
}
Android provides a system log mechanism for developers to use from their applications. The log has different levels of information:
All messages in the log include the process id that generated it. We will now add logging to our Fibonacci application.
FibonacciActivity.java
, and add the highlighted lines:import android.util.Log;
public class FibonacciActivity extends Activity {
private static final String TAG = "Fibonacci";
@Override
public void onCreate( Bundle savedInstance ) {
Log.d( TAG, "onCreate called" );
super.onCreate( savedInstance );
// Create the TextView
TextView tv = new TextView( this );
int fibo = Fibonacci( 10 );
tv.setText( "Fibonacci(10) = " + fibo );
setContentView( tv );
}
android-sdk-[linux|windows|mac]/platform-tools
directory. adb logcat -s Fibonacci:*
-s
makes the default filter silent and the Fibonacci:* tells logcat to enable the Fibonacci tagged messages.If you would like to write debug messages to a file, you need to be aware that in Android, every application runs under a different user id, and only a limited set of paths are writable by the application and visible to the user. If you are using a Tegra prototype device, you can create directory under data
to store your log files. But on commercial devices, this location is usually protected and you will need to find a suitable user-accessible path. Android provides the means to do so. To keep it simple, let's add logging to a file we create in external storage. Don't get misled by the word external here, the external storage might not be the SD card. But files you write to external storage are not deleted when the application is uninstalled.
FibonacciActivity.java
, we will add code to write to a log file. We will create a logWriter class instance variable that we will use to write text messages to a file we will create. private FileWriter logWriter;
@Override
public void onCreate( Bundle savedInstance ) {
Log.d( TAG, "onCreate called" );
super.onCreate( savedInstance );
try {
File path = Environment.getExternalStorageDirectory();
File logfile = new File( path, "fibo_log.txt" );
logWriter = new FileWriter( logfile );
Log.i( TAG, "Writing log to " + logfile );
}
catch( IOException e ) {
Log.e( TAG, "Couldn't open log file - reason " + e.getMessage() );
}
logMessage( "FibonacciActivity.onCreate\n" );
// Create the TextView
TextView tv = new TextView( this );
int fibo = Fibonacci( 10 );
tv.setText( "Fibonacci(10) = " + fibo );
setContentView( tv );
}
private void logMessage( String msg ) {
if( logWriter != null ) {
try {
logWriter.write( msg );
}
catch( IOException e ) {
Log.e( TAG, "Couldn't write message to log file - reason " + e.getMessage() );
}
}
}
@Override
public void onPause() {
logMessage( "FibonacciActivity.onPause\n" );
try {
logWriter.close();
}
catch( IOException e ) {
Log.e( TAG, "Failed to close log file - reason: " + e.getMessage() );
}
super.onPause();
}
AndroidManifest.xml
and indicate that the application requests permission to write to external storage.<!-- Before the application tag, add the requested permissions -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="@string/app_name"
adb pull /storage/sdcard0/fibo_log.txt
See also: An explanation on Android storage. |
Using our FibonacciActivity as a starting point, we will add a native library that computes the Fibonacci function.
libfibonacci.so
, and click on Finish.jni
that contains fibonacci.cpp
and Android.mk
.LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fibonacci
LOCAL_SRC_FILES := fibonacci.cpp
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE
gives the module name which in turn is used for the output filename. LOCAL_SRC_FILES
contains the list of files to build, and finally, the include
command is used to include the rules for building a shared library. The output of the build will be libfibonacci.so
. This library needs to be explicitly loaded by the Java VM, as we show next.jni
folder named Application.mk. Right-click on jni
and select New > File.Android.mk
file defines module settings, the Application.mk
file is used to define per-application settings that apply to all modules. Set the contents of the new file as shown below: APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
APP_ABI
line defines the target machine code instruction set. The default is armeabi
, which corresponds to an ARM ISA with no hardware floating point support. To support hardware FPU instructions of more recent ARM processors, use armeabi-v7a
. We also set the APP_PLATFORM
to android-ver, where ver is the value of the android::minSdkVersion
in the AndroidManifest.xml
. For NativeActivity
support, a version at or above 9 is required, but this example uses a Java Activity.public class FibonacciActivity extends Activity {
@Override
public void onCreate( Bundle savedInstance ) {
super.onCreate( savedInstance );
// Create the TextView
TextView tv = new TextView( this );
int fibo = Fibonacci( 10 );
tv.setText( "Fibonacci(10) = " + fibo );
setContentView( tv );
}
// Our native Fibonacci function
native int Fibonacci( int n );
static {
System.loadLibrary( "fibonacci" );
}
javah
utility to generate the function headers for you and avoid remembering the mangling rules. For this, you will first need to compile your project. Right-click on the project name and select Build Project.fibonacci.cpp
is empty, the C++ builder is invoked successfully. There is no error telling us that the native method has not been implemented. This kind of error will be a Java Exception raised by the virtual machine. You can see it for yourself; if you try to run the application, it will crash. You can look at the error by browsing the logcat:AndroidManifest.xml
file is located), and run javah
. javah -classpath ./bin/classes -d jni com.nvidia.example.fibonacci.FibonacciActivity
jni/com_nvidia_example_fibonacci_FibonacciActivity.h
.If it doesn't work: We have found on some installations, that javah from a previous, non-Android Java installation was on the path before the one from Android toolkit. If you encounter errors, type which javah to find which version is used. It should return a path within NVPACK. On cygwin, we fixed this by editing /home/<user>/.bash_profile by adding a line: PATH="/cygdrive/c/NVPACK/jdk1.6.0_24/bin:${PATH}" |
fibonacci.cpp
to continue working on our implementation. Create the Fibonacci function as shown and add an include for the new header. #include <jni.h>
int Fibonacci( int n )
{
if( n == 1 ) { return 1; }
if( n <= 0 ) { return 0; }
return Fibonacci( n - 1 ) + Fibonacci( n - 2 );
}
jni/com_nvidia_example_fibonacci_FibonacciActivity.h
into fibonacci.cpp
. If you can't see the file in the jni
folder, click the folder and press F5 to refresh. The header file only contains the function declaration; in the cpp file you will have to actually call the function. To this aim, the entire function declaration has to be copied from the .h to the .cpp file (including the extern "C") and modified as in the highlighted lines. Our jni function will simply be a wrapper around the Fibonacci function. #ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_nvidia_example_fibonacci_FibonacciActivity
* Method: Fibonacci
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_nvidia_example_fibonacci_FibonacciActivity_Fibonacci
( JNIEnv *env, jobject obj, jint n )
{
return Fibonacci( n );
}
#ifdef __cplusplus
}
#endif
See also:
|
Now that we have built and deployed our mixed Java and native code Activity, we will show how to debug it. There are two Debug configurations that we can use. To debug Java code, we will debug as we did previously, by selecting Debug As > Android Application. This configuration launches a debugger that attaches to the Java VM. For native code, we will instead use Debug As > Android Native Application. This configuration now launches a gdbserver
instance on the device that attaches to the application process.
fibonacci.cpp
: #ifdef __cplusplus
extern "C" {
#endif
#define WAIT_FOR_DEBUGGER
jint JNI_OnLoad( JavaVM *vm, void *reserved )
{
#if defined(WAIT_FOR_DEBUGGER)
volatile int _dbg = 1;
while ( _dbg )
{
}
#endif
return JNI_VERSION_1_2;
}
#ifdef __cplusplus
}
#endif
_dbg
. It is marked volatile to make sure the compiler does not optimize the variable away so we can clear it from the debugger.android:minSdkVersion
and android:targetSdkVersion
in AndroidFibonacciManifest.xml
, and APP_PLATFORM
in Application.mk
to the same Android version. For instance, android:minSdkVersion="19"
, android:targetSdkVersion="19"
and APP_PLATFORM := android-19
._dbg
from 1 to 0; also set a breakpoint on the call to Fibonacci. Finally, let the program continue running by pressing F8; you should immediately hit the breakpoint you have just set.We are done! You have now seen the basics on how to do Java and native code debugging of Android applications running on the device from Eclipse.
We can print debugging messages to the Android log from native code using the __android_log_print
function.
fibonacci.cpp
and add the following code at the top of the file. #if !defined(LOG_TAG)
#define LOG_TAG "Fibonacci"
#endif
#define LOGV(...) __android_log_print( ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__ )
#define LOGD(...) __android_log_print( ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__ )
#define LOGI(...) __android_log_print( ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__ )
#define LOGW(...) __android_log_print( ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__ )
#define LOGE(...) __android_log_print( ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__ )
#include <android/log.h>
JNIEXPORT jint JNICALL Java_com_nvidia_example_fibonacci_FibonacciActivity_Fibonacci
( JNIEnv *env, jobject obj, jint n )
{
LOGV( "Fibonacci( %d ) = %d\n", n, Fibonacci( n ) );
return Fibonacci( n );
}
Android.mk
to link the log library into the project.TheLOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fibonacci
LOCAL_SRC_FILES := fibonacci.cpp
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
LOCAL_LDLIBS
directive specifies a list of system libraries provided by the NDK that we can link into our project. In the above example, the log library defines __android_log_print
.WAIT_FOR_DEBUGGER
of the previous section (so you don't stay in an infinite loop), run the project, and verify that you can see the log message (either in eclipse or using adb).When logging to a file from native code, we are still bound by the same restrictions we mentioned regarding user-accessible paths. Additionally, there is no native version of Environment.getExternalStorageDirectory()
in the NDK, so we will have to pass the directory information from Java.
FibonacciActivity.java
, add a new native method that will enable native code logging into the specified file. // Enable native logging to the given filename
native void enableNativeLogging( String filename );
onCreate
, we will call enableNativeLogging
: @Override
public void onCreate( Bundle savedInstance )
{
super.onCreate( savedInstance );
[...]
// create the log file before calling Fibonacci()
enableNativeLogging( Environment.getExternalStorageDirectory() + "/fibo_native_log.txt" );
TextView tv = new TextView( this );
int fibo = Fibonacci( 10 );
tv.setText( "Fibonacci(10) = " + fibo );
setContentView( tv );
}
enableNativeLogging
. First, in the file fibonacci.cpp
, we create an ofstream
with the scope of the entire source file to hold a handle to the log file (and include fstream
): #include <fstream>
static std::ofstream gLogFile;
enableNativeLogging
; this function calls into JNI to convert the Java string into a C-style string, opens the file, and then releases the allocated C-style string (do not forget to declare this as "extern C"):
/*
* Class: com_nvidia_example_fibonacci_FibonacciActivity
* Method: enableNativeLogging
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_nvidia_example_fibonacci_FibonacciActivity_enableNativeLogging
( JNIEnv *env, jobject obj, jstring jfilename )
{
if( gLogFile.is_open() )
{
gLogFile.close();
}
// Call JNI to convert the jstring into UTF 8 bit characters
const char* filename = env->GetStringUTFChars( jfilename, NULL );
// If filename is non-empty, open the file
if( filename[0] != 0 )
{
// Open the file
gLogFile.open( filename );
}
// Release the string allocated by JNI
env->ReleaseStringUTFChars( jfilename, filename );
}
ofstream
, when the program exits, the gLogFile
object will go out of scope and the file will be closed. Alternatively, you could add enableNativeLogging( "" );
in the onPause()
method in the Java side. javah -classpath ./bin/classes -d jni com.nvidia.example.fibonacci.FibonacciActivity
ofstream
object, we need to modify the Application.mk
file. By adding the following line to the Application.mk
, the NDK build system will set the include path for the headers and add the static library.# APP_STL
# By default, the NDK build system provides C++ headers for the minimal
# C++ runtime library (/system/lib/libstdc++.so) provided by the Android
# system.
#
# However, the NDK comes with alternative C++ implementations that you can
# use or link to in your own applications. Define APP_STL to select one of
# them. Examples are:
#
# APP_STL := stlport_static --> static STLport library
# APP_STL := stlport_shared --> shared STLport library
# APP_STL := system --> default C++ runtime library
APP_STL := gnustl_static
fibonacci.cpp
: int Fibonacci( int n )
{
gLogFile << "Fibonacci called with " << n << std::endl;
[...]
adb shell
from the command line to see what the file contains: karip@mac:~$ adb shell
root@android:/ # cd /storage/
root@android:/storage # ls
sdcard0
sdcard1
root@android:/storage # cd sdcard0/
root@android:/storage/sdcard0 # cat fibo_native_log.txt
Fibonacci called with 10
Fibonacci called with 9
[... many lines removed ...]
Fibonacci called with 1
Fibonacci called with 0
root@android:/storage/sdcard0 #
You can exit from the shell with CTRL-D. The many lines in the file demonstrate that although this recursive implementation of Fibonacci number calculation is elegant, it's not particularly efficient.
We will extend our Fibonacci example further, by showing how to call Java methods from the native code. We will add the ability to log messages into the TextView, to mimic the behavior of a console application.
FibonacciActivity.java
. Copy the new code for the FibonacciActivity class. We have moved the TextView
to class member scope and we have added a function called printToConsole
that we can call to append text to this TextView
. In addition, we have a new native function called FibonacciSequence
.public class FibonacciActivity extends Activity {
private TextView mConsoleText;
@Override
public void onCreate( Bundle savedInstance ) {
super.onCreate( savedInstance );
// Create the TextView.
mConsoleText = new TextView( this );
setContentView( mConsoleText );
// Generate the Fibonacci sequence up to 10.
FibonacciSequence( 10 );
}
// Append new text to the consoleText TextView.
private void printToConsole( String text ) {
mConsoleText.setText( mConsoleText.getText() + text );
}
// Native Fibonacci function - returns the nth Fibonacci number.
native int Fibonacci ( int n );
// Computes the Fibonacci sequence up to n and prints
// it through the print function.
native void FibonacciSequence( int n );
static {
System.loadLibrary( "fibonacci" );
}
}
javah -classpath ./bin/classes -d jni com.nvidia.example.fibonacci.FibonacciActivity
jni/com_nvidia-example_fibonacci_FibonacciActivity.h
will be regenerated.fibonacci.cpp
, and copy and paste the newly added function header from com_nvidia-example_fibonacci_FibonacciActivity.h
. Our implementation of FibonacciSequence will compute the Fibonacci numbers and print them to the TextView by calling the Java printToConsole
method. The function code looks like this: #include <sstream>
[...]
/*
* Class: com_nvidia_example_fibonacci_FibonacciActivity
* Method: FibonacciSequence
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_com_nvidia_example_fibonacci_FibonacciActivity_FibonacciSequence
( JNIEnv *env, jobject obj, jint n )
{
const char *methodName = "printToConsole";
const char *methodSignature = "(Ljava/lang/String;)V";
jclass objClass = ( jclass ) env->GetObjectClass( obj );
jmethodID methodId = env->GetMethodID( objClass, methodName, methodSignature );
for( int i = 0; i <= n; i++ )
{
// Our string buffer for the output message.
std::stringstream msg;
// Compute the current Fibonacci number.
int fibo = Fibonacci( i );
// Create the msg to print.
msg << "Fibonacci(" << i << ") = " << fibo << std::endl;
// Create a jstring to send the message to the Java VM.
jstring jtext = env->NewStringUTF( msg.str().c_str() );
// Call the Java class printToConsole method.
env->CallVoidMethod( obj, methodId, jtext );
// Delete the local reference created by NewStringUTF
// to allow the Java VM to garbage collect the jstring object.
env->DeleteLocalRef( jtext );
}
}
printToConsole
method on the passed Java object, we need to obtain its method ID from the Java VM. First, we ask for the jclass of the passed object by calling GetObjectClass
. Then we obtain the jmethodID by calling GetMethodID
and passing the corresponding jclass identifier, the method name, and the method signature. The method name is printToConsole and the signature (Ljava/lang/String;)V
, which stands for a method returning void that takes an argument of type java.Lang.String
.newStringUTF
function takes a char * and returns a jstring instance. We can then call the Java function using the CallVoidMethod
and passing the obj, the method ID, and the string.Android provides a NativeActivity framework that can be used to run applications that are written entirely in native code. A NativeActivity can have event loops to receive user input, but will have no UI building blocks; it was developed for game developers and it is expected that the UI is built using OpenGL ES rendering.
As an introduction to NativeActivity, we will write our Fibonacci example using this framework. Since there is no Java code, let's start with a new project. The following steps assume you have already performed all the previous tutorials.
libfibonacci.so
.jni/Application.mk
file and set the APP_ABI to armeabi-v7a
, and the Android platform to 14 (this is the first platform to support the NativeActivity). Also, set APP_STL to gnustl_static
.APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
APP_STL := gnustl_static
AndroidManifest.xml
, which has a few extra settings for the NativeActivity. In the application section we specify that the app doesn't have any Java code. <!-- We do not have Java code. Therefore android:hasCode is set to false. -->
<application android:label="@string/app_name"
android:hasCode="false">
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:hasCode="false"
android:theme="@style/AppTheme" >
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboard|keyboardHidden"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name"
android:value="fibonacci" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Android.mk
. Our library needs to statically link with the android_native_app_glue
library, which is provided as a separate module, and against the shared system log
and android
libraries.LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := fibonacci
LOCAL_SRC_FILES := fibonacci.cpp
LOCAL_LDLIBS := -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_SHARED_LIBRARY)
$(call import-module, android/native_app_glue)
fibonacci.cpp
and add the following code:#if !defined(LOG_TAG)
#define LOG_TAG "Fibonacci"
#endif
#define LOGV(...) __android_log_print( ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__ )
#define LOGD(...) __android_log_print( ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__ )
#define LOGI(...) __android_log_print( ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__ )
#define LOGW(...) __android_log_print( ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__ )
#define LOGE(...) __android_log_print( ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__ )
#include <android/log.h>
#include <android_native_app_glue.h>
int Fibonacci( int n )
{
if ( n == 1 ) { return 1; }
if ( n <= 0 ) { return 0; }
return Fibonacci( n - 1 ) + Fibonacci( n - 2 );
}
/**
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
* event loop for receiving input events and doing other things.
*/
void android_main( struct android_app *state )
{
// Make sure glue isn't stripped.
app_dummy();
LOGV( "Fibonacci(10) = %d\n", Fibonacci( 10 ) );
// Event loop manager.
// This is an empty event loop manager that waits for the user
// to destroy the activity.
while( 1 )
{
// Read all pending events.
int ident;
int events;
struct android_poll_source *source;
// Wait indefinitely for an event to occur.
while( ( ident = ALooper_pollAll( -1, NULL, &events, (void **)&source ) ) >= 0 )
{
// Process this event.
if( source != NULL )
{
source->process( state, source );
}
// Check if we are exiting.
if( state->destroyRequested != 0 )
{
return;
}
}
}
}
android_native_app_glue.h
which provides the callbacks for notification of Activity life cycle events. In addition, the native application glue also requires an android_main function to be defined as the entry point for the application.Fibonacci(10)
to the Android log. In addition, we do have to process application events for the Activity to remain responsive. This is done inside the event manager loop, where we process all events until the user requests the app to exit.
Note: As the comment says, |
Try running the application. The screen will remain blank. Check the log message for the output. A handy way to find it quickly is to type in the LogCat search line tag:fib
.
In an earlier example, we showed how we could log into a file from native code, with the full path filename being provided by the Java application. When running a NativeActivity, we will find the path available to the application using the externalDataPath member of the ANativeActivity struct.
fibonacci.cpp
and add the following includes and static declarations.#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <errno.h>
static std::ofstream gLogFile;
android_main()
function to create and open the file. As opposed to what we have seen in the Java framework, the path might not exist, so we will need to create it. For this, we have developed an auxiliary function, MakePath()
, that we will present shortly.void android_main( struct android_app *state )
{
// Make sure glue isn't stripped.
app_dummy();
LOGV( "Fibonacci(10) = %d\n", Fibonacci( 10 ) );
std::stringstream filename;
filename << state->activity->externalDataPath << "/" << "fibo_native_log.txt";
MakePath( state->activity->externalDataPath, 0770 );
// Open the log file for output
gLogFile.open( filename.str().c_str() );
if( gLogFile.is_open() )
{
LOGI( "Opened log file %s\n", filename.str().c_str() );
gLogFile << "FibonacciActivity Native log file " << filename.str().c_str() << std::endl;
}
else
{
LOGE( "Couldn't open the log file %s\n", filename.str().c_str() );
}
MakePath
and MakeDir
functions before android_main:static int MakeDir( std::string const &path, mode_t mode )
{
struct stat st;
if( stat( path.c_str(), &st ) != 0 )
{
if( mkdir( path.c_str(), mode ) != 0 && errno != EEXIST )
{
return false;
}
}
else if( !S_ISDIR( st.st_mode ) )
{
errno = ENOTDIR;
return false;
}
return true;
}
static bool MakePath( std::string const &path, mode_t mode )
{
std::string cstr( path );
int cpos = 0;
int ppos = 0;
bool success = true;
while( success && ( cpos = cstr.find_first_of( "/", ppos ) ) != std::string::npos )
{
if( cpos != ppos )
{
/* Neither root nor double slash in path */
cstr[cpos] = '\0';
success = MakeDir( cstr, mode );
cstr[cpos] = '/';
}
ppos = cpos + 1;
}
if( success )
{
success = MakeDir( path, mode );
}
return success;
}
/storage/sdcard0/Android/data/com.nvidia.nativeactfib/files/fibo_native_log.txt
, depending on the project name, etc.See also:
|
NVIDIA® GameWorks™ Documentation Rev. 1.0.220830 ©2014-2022. NVIDIA Corporation and affiliates. All Rights Reserved.