Geeks With Blogs
Josh Reuben


Native activities – create an application based only on native code, without a single line of Java.

Use cases:

  • Android sensor polling – more accurate than Java events
  • Cross platform 3D – include a common OpenGL static lib that can also be linked in say an ObjectiveC app. (If writing purely for Android, just use the Java API and import android.opengl.GLES20.* package, adapting a TextureView to perform EGL init like a GLSurfaceView - the performance leverages the same OpenGL ES calls via JNI wrappers, and shaders run on the GPU anyway, yielding same performance. Or you could use LibGDX...)
  • Image processing – eg leverage OpenCV C++ libs for Augmented Reality apps (see my next post).

You can pretty much call any POSIX API or included C/C++ lib that is POSIX compliant !

The native_app_glue Module API

NativeActivity class leverages JNI to handle application lifecycle events from the ART JVM and pass them to native code in a separate thread.

${ANDROID_NDK}/sources/android/native_app_glue – hides details of synchronization with mutexes, IPC pipes

different events set android_app.activityState with the appropriate APP_CMD_* value:

  • onStart, onResume, onPause, onStop
  • onSaveInstance - wait for native application callback to save state. 
  • OnDestroy - notify native thread that destruction is pending, and free memory when acknowledged.
  • onConfigChanged, onWindowFocusedChanged, onLowMemory
  • onNativeWindowCreated / onNativeWindowDestroyed - call android_app_set_window() which provides and requests the native thread to change its display window.
  • onInputQueueCreated / onInputQueueDestoyed - call android_app_set_input() to register an input queue
  • Note: screen orientation changes require activity recreation, and raises an APP_CMD_ SAVE_STATE event


  • application entry point - forks the native thread
  • Executed on the UI thread, communicates to native thread via callback event wrappers over Linux pipes and synchronization mutexes
  • allocates memory and initializes android_app application context
  • android_app_entry() - executed on the native thread - reads data incoming from the pipe and passes it to ALooper event queue processor
  • ALooper_prepare() - creates ALooper
  • Alooper_addFd() - attaches ALooper to the pipe (as a POSIX file descriptor)
android_poll_source::process – called from custom event loop. Calls process_cmd() / process_input()
  • process_cmd() - process command queue and calls back to custom android_app::onAppCmd callback pointer
  • process_input() - process input queue and calls back to custom android_app::onAppCmd callback pointer

thread entry point attaches the Command Queue to the ALooper; From my understanding, the Input Queue communicates to the ALooper via a pipe but can be manually attached to the ALooper via AInputQueue_attach/detachLooper()

Custom user queue can also be attached to the ALooper to listen to additional file-descriptors.

app_dummy() - ensures native glue is not stripped by the linker.

android_app structure - contains native activity context info: state, window, event queue, etc

  • onAppCmd: callback pointer - triggered each time an activity event occurs from command queue.
  • onInputEvent: callback pointer - triggered each time an input event occurs from input queue.
  • void* userData: pointer to data structure accessible to callback function
  • int destroyRequested flag to notify custom event loop that an application is being terminated, and that is should gracefully save state & free resources
  • int activityState - current activity state APP_CMD_*
  • ‹ANativeActivity* activity - the JNI NativeActivity
  • ‹  AConfiguration* config - info about host hardware and system state: locale, screen orientation & size etc
  • void* savedState, size_t savedStateSize - save data when an activity thread is destroyed for later restoration
  • ‹AInputQueue* inputQueue handles input events 
  • ‹ALooper* looper – manually attach /detach event listeners against custom event sources exposed via POSIX file descriptors
  • ‹  ANativeWindow* window, ARect contentRect: - graphics drawable area, declared in native_window.h

Alooper_pollAll() – custom native event loop should poll the queue for pending android_poll_source events.

ANativeActivity_finish() - request activity termination

Create a native Android project:

  • create a new project > Android project and set settings: project name, Build target, Application name, Package name (com.domain.MyApp), Min SDK Version. Uncheck Create Activity.
  • remove res/layout/main.xml, src directory (its for Java code).
  • add NativeActivity to the AndroidManifest.xml file: Instead of a new Java Activity child class
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=""
package="com.MyNS.MyApp" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:minSdkVersion="21"/>
<application android:icon="@drawable/icon" android:label="@string/app_name">
	<activity android:name="" android:label="@string/app_name">
		<meta-data android:name=""   android:value="MyApp"/>
            	<action android:name="android.intent.action.MAIN"/>
            	<category android:name="android.intent.category.LAUNCHER"/>

set project to compile native code:

  • Convert the project to a hybrid C++ project (not C) using Convert C/C++ Project wizard.
  • Project >Properties > C/C++ Build - set default build command to ndk-build.
  • Project >Properties > C/C++ Build > Path and Symbols/Includes - add Android NDK & native app glue include directories:

Create directory jni under project root – add all hpp, cpp , mk files here.

Make File

Build script – I'll cover the details of Make (and Cmake) in a future post …

define a Make macro LS_CPP that automatically lists all .cpp files in jni directory

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LS_CPP=$(subst $(1)/,,$(wildcard $(1)/*.cpp))
LOCAL_LDLIBS    := -landroid -llog
LOCAL_STATIC_LIBRARIES := android_native_app_glue
$(call import-module, android/native_app_glue)


app entry point android_main() method runs the event loop


#include “Timer.hpp”

#include "EventHandlerImpl.hpp"
#include "EventLoop.hpp"
using namespace MyNS;
void android_main (android_app* pApp){
    EventLoop eventLoop(pApp);
    Timer timer;
    EventHandlerImpl eventHandler (timer, pApp);;


Abstract base – interface to observe and handle all native activity events passed from EventLoop - each event has its own handler method. it is important to handle 3 core events in the activity lifecycle:

  • ‰ onActivate(): activity is resumed and window is available and focused.

  • ‰ onDeactivate(): activity is paused or display window loses focus or is destroyed.

  • ‰  onStep(): - idle: computations can take place.


namespace MyNS {
    class EventHandler {
            virtual int32_t onActivate() = 0;
            virtual void onDeactivate() = 0;
            virtual int32_t onStep() = 0;

            virtual void onStart() {};
            virtual void onResume() {};
            virtual void onPause() {};
            virtual void onStop() {};
            virtual void onDestroy() {};
            virtual void onSaveState(void** pData, int32_t* pSize) {};
            virtual void onConfigChanged() {};
            virtual void onLowMemory() {};
            virtual void onInitWindow() {};
            virtual void onTerminateWindow() {};
            virtual void onGainFocus() {};
            virtual void onLostFocus() {};




#include <android_native_app_glue.h>
#include "EventHandler.hpp"

namespace MyNS {
    class EventLoop {
        EventLoop(android_app* pApp);

void run(EventHandler& pEventHandler);


        void activate();
        void deactivate();
        void processEvent(int32_t appCmdCode);


const int32_t SUCCESS;

        static void eventCallback(android_app* pApp, int32_t appCmdCode);
        int isBlocking() const;

bool isEnabled_;

bool isTerminating_;

EventHandler* eventHandler_;

android_app* app_;





#include "EventLoop.hpp"
#include "Log.hpp"
namespace MyNS {
    EventLoop::EventLoop(android_app* pApp) :

isEnabled_(false), isTerminating_(false), app_(pApp), eventHandler_(nullptr) {

app_->onAppCmd = eventCallback;

app_->userData = this;


run() method polls application events in an event loop - during activity lifetime, loops continuously over events until it is requested to terminate.

    void EventLoop::run() {
        int32_t events;
        android_poll_source* pPollSource;
        while (true) {
            while (Alooper_pollAll( isBlocking(), nullptr, &events,  (void**) &pPollSource) >= 0) {
                if (pPollSource) {
                    Log::info("Processing an event");
                    pPollSource->process(app_, pPollSource);
                if (app_->destroyRequested) {
                    Log::info("Exiting event loop"); 



if ((isEnabled_) && (!isTerminating_)) {

                if (eventHandler_->onStep() != SUCCESS) {
                    isTerminating_ = true;





int EventLoop::isBlocking() {

// return blocking timeout param:

// -1 block until event is received - avoid consuming battery / CPU time uselessly

// 0 non-blocking: empty event queue → inner while loop will be terminated

// note: > 0 → block until event is received or timeout duration elapsed

return isEnabled_ ? 0 : -1;


eventCallback() calls processEvent()

Parameter appCmdCode contains an enumeration value (APP_CMD_*) which describes the occurring event.

    void EventLoop::eventCallback(android_app* pApp,  int32_t appCmdCode) { 
        EventLoop& eventLoop = *(EventLoop*) pApp->userData;


    void EventLoop::processEvent(int32_t appCmdCode) {
        switch (appCmdCode) {
            case APP_CMD_CONFIG_CHANGED:
            case APP_CMD_INIT_WINDOW:
            case APP_CMD_START:
            case APP_CMD_STOP:
            case APP_CMD_TERM_WINDOW:
            case APP_CMD_DESTROY:
            case APP_CMD_GAINED_FOCUS:


            case APP_CMD_LOST_FOCUS:
            case APP_CMD_LOW_MEMORY:
            case APP_CMD_PAUSE:
            case APP_CMD_RESUME:
            case APP_CMD_SAVE_STATE:
                eventHandler_->onSaveState(&app_->savedState,  &app_->savedStateSize);





activate() / deactivate() - check activity state & notify the observer

Activation occurs when activity gains focus - can receive input events.

Deactivation occurs when window loses focus , application is paused or window is destroyed - cannot receive input events.

    void EventLoop::activate() {
        if ((!isEnabled_) && (app_->window != nullptr)) {
            isTerminating_ = false; 
            isEnabled_ = true;
            if (eventHandler_->onActivate() != SUCCESS) {

isTerminating_ = true;




    void EventLoop::deactivate() {
        if (isEnabled_) {
            isEnabled_ = false;


implements EventHandler interface - place application-specific code here.


#include <android_native_app_glue.h>
#include "EventHandler.hpp"
#include “Timer.hpp”

namespace MyNS {
    class EventHandlerImpl : public EventHandler {

EventHandlerImpl(Timer& pTimer, android_app* pApp);

        int32_t onActivate();
        void onDeactivate();
        int32_t onStep();
        void onStart();
        void onResume();
        void onPause();
        void onStop();
        void onDestroy();
        void onSaveState(void** pData; int32_t* pSize);
        void onConfigChanged();
        void onLowMemory();
        void onInitWindow();
        void onTerminateWindow();
        void onGainFocus();
        void onLostFocus();
        const int32_t SUCCESS;
        const int32_t FAIL;
        void clear();
        void draw();
        android_app* app_;
        ANativeWindow_Buffer windowBuffer_;
        Timer* timer_;




#include "EventHandlerImpl.hpp"
#include "Log.hpp"
#include <math.h>

namespace MyNS {

EventHandlerImpl::EventHandlerImpl(Timer& pTimer, android_app* pApp) :

timer_(pTimer), app_(pApp), SUCCESS(0), FAIL(-1) {}

the ANativeWindow_* API gives native access to the display window and allow manipulating its surface like a bitmap - requires locking and unlocking before and after processing.

set window format as 32-bit with ANativeWindow_setBuffersGeometry().

Query window information in an ANativeWindow_Buffer structure

    int32_t EventHandlerImpl::onActivate() {
        if (ANativeWindow_setBuffersGeometry(
            app_->window, 0,0, WINDOW_FORMAT_RGBX_8888 /* 32bit */ ) < 0) 
            return FAIL;
        // Need to lock the window buffer to get its properties.
        if (ANativeWindow_lock (app_->window, &windowBuffer_, nullptr) >= 0) {
        } else {
            return FAIL;
        return SUCCESS;

step the application by moving the cursor at a constant rate –

call ANativeWindow_lock() to lock window buffer for drawing and call ANativeWindow_unlockAndPost() to unlock it when drawing is finished

    int32_t EventHandlerImpl::onStep() {
        if (ANativeWindow_lock(app_->window, &windowBuffer_, nullptr) >= 0) {
            return SUCCESS;
        } else {
            return FAIL;



implement clear and draw methods

The display window surface which is a continuous memory buffer - directly accessible via the bits field and can be modified pixel by pixel

Clear the screen with a brute-force approach using memset().

    void EventHandlerImpl::clear() {
        memset( windowBuffer_.bits,  0, windowBuffer_.stride * windowBuffer_.height * sizeof(uint32_t*));
    void EventHandlerImpl::draw() {
        // todo: transform windowBuffer_.bits



define _Log_debug macro - activates debug messages if NDEBUG flag is set:

#ifndef _LOG_HPP
#define _LOG_HPP

namespace MyNS {
    class Log {
        static void error(const char* pMessage, ...);
        static void warn(const char* pMessage, ...);
        static void info(const char* pMessage, ...);
        static void debug(const char* pMessage, ...);
#ifndef NDEBUG
    #define _Log_debug(...) Log::debug(__VA_ARGS__)
    #define _Log_debug(...)


Log.cpp file - implement method info().

NDK provides a dedicated logging API in header android/log.h to write messages to Android logs.

log methods differ in their level macro: ANDROID_LOG_INFO/ERROR,/WARN/DEBUG .

NDEBUG macro is defined by the NDK compilation toolchain. To undefined it, in the manifest, set:<application android:debuggable="true" ...>

run adb logcat to see emitted log messages.

#include <stdarg.h>
#include <android/log.h>
#include "Log.hpp"

namespace MyNS {
    void Log::info(const char* pMessage, ...) {

va_list varargs;
va_start(varargs, pMessage);

__android_log_vprint(ANDROID_LOG_INFO, "MyNS", pMessage, varargs);
__android_log_print(ANDROID_LOG_INFO, "MyNS", "\n");





adapt FPS according to device speed.

Use POSIX time primitives from time.h

clock_gettime() - retrieve current time from monotonic system clock

work with doubles when manipulating absolute time to avoid losing accuracy - resulting delay can be converted back to float

#ifndef _TIMer_HPP_
#define _TIMer_HPP_

#include <time.h>
namespace MyNS {
    class Timer {
        void reset();
        void update();
        double now();
        float elapsed();
        float elapsed_;
        double lastTime_;


#include "Timer.hpp"
namespace MyNS {
    Timer::Timer() : elapsed_(0.0f), lastTime_(0.0f) {}

    void Timer::reset() {
        elapsed_ = 0.0f;
        lastTime_ = now();
    void Timer::update() {
        double currentTime = now();
        elapsed_ = (currentTime - lastTime_);
        lastTime_ = currentTime;
    double Timer::now() {
        timespec timeVal;
        clock_gettime(CLOCK_MONOTONIC, &timeVal);
        return timeVal.tv_sec + (timeVal.tv_nsec * 1.0e-9);
    float Timer::elapsed() {
        return elapsed_;

			Posted on Tuesday, February 17, 2015 6:12 PM

 | Back to top

Comments on this post: Native Android Apps

# re: Native Android Apps
Requesting Gravatar...
I have used the app and it really worked well. - Mark Zokle
Left by George Thomas on Dec 20, 2016 6:03 PM

Your comment:
 (will show your gravatar)

Copyright © JoshReuben | Powered by: