The native android api

Android NDK Native APIs

On this page

The Android NDK provides a set of native headers and shared library files that has gradually increased with successive releases of new Android API levels. This page explains these headers and files, and maps them to specific Android API levels.

Overview

There are two basic steps to enable your app to use the libraries that the NDK provides:

  1. Include in your code the headers associated with the libraries you wish to use.
  2. Tell the build system that your native module needs to link against the libraries at load time. For example, to link against /system/lib/libfoo.so , add the following line to your Android.mk file:

To list multiple libraries, use a space as a delimiter. For more information about using the LOCAL_LDLIBS variable, see Android.mk.

For all API levels, the build system automatically links the standard C libraries, the standard C++ libraries, real-time extensions, and pthread ; you do not need to include them when defining your LOCAL_LDLIBS variable. For more information about the C and C++ libraries, see Android API level 3.

Table 1 shows the correspondence between NDK-supported API levels and Android releases.

Table 1. NDK-supported API levels and corresponding Android releases.

NDK-supported API level Android release
3 1.5
4 1.6
5 2.0
8 2.2
9 2.3 through 3.0.x
12 3.1.x
13 3.2
14 4.0 through 4.0.2
15 4.0.3 and 4.0.4
16 4.1 and 4.1.1
17 4.2 and 4.2.2
18 4.3
19 4.4
21 4.4W and 5.0

Each new release of NDK headers and libraries for a given Android API level is cumulative; you are nearly always safe if you use the most recently released headers when building your app. For example, you can use the NDK headers for Android API level 21 for an app targeting API level 16. By doing so, however, you increase your APK’s footprint.

For more information about Android API levels, see What is API Level?.

Major Native API Updates

Android API level 3

The NDK provides the following APIs for developing native code that runs on Android 1.5 system images and above.

C library

The C library headers for Android 1.5 are available through their standard names, such as stdlib.h and stdio.h . If a header is missing at build time, it’s because the header is not available on the 1.5 system image.

C++ library

An extremely minimal C++ support API is available. For more information on C++ library support, see C++ Library Support.

Android-specific log support

You can write your own wrapper macros to access this functionality. If you wish to perform logging, your native module should link to /system/lib/liblog.so . Implement this linking by including the following line in your Android.mk file:

ZLib compression library

You can use the Zlib compression library by including zlib.h and zconf.h . You must also link your native module against /system/lib/libz.so by including the following line in your Android.mk file:

Dynamic linker library

You can access the Android dynamic linker’s dlopen() , dlsym() , and dlclose() functions by including dlfcn.h . You must also link against /system/lib/libdl.so by including the following line in your Android.mk file:

Android API level 4

The NDK provides the following APIs for developing native code that runs on Android 1.6 system images and above.

OpenGL ES 1.x Library

The standard OpenGL ES headers gl.h and glext.h contain the declarations necessary for performing OpenGL ES 1.x rendering calls from native code.

To use these headers, link your native module to /system/lib/libGLESv1_CM.so by including the following line in your Android.mk file:

All Android-based devices support OpenGL ES 1.0, because Android provides an Open GL 1.0-capable software renderer that can be used on devices without GPUs.

Only Android devices that have the necessary GPU fully support OpenGL ES 1.1. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.

Additionally, you must put a tag in your manifest file to indicate the version of OpenGL ES that your application requires.

The EGL APIs are only available starting from API level 9. You can, however, use the VM to perform some of the operations that you would get from those APIS. These operations include surface creation and flipping. For an example of how to use GLSurfaceView , see Introducing GLSurfaceView.

The san-angeles sample application provides an example of how to perform these operations, rendering each frame in native code. This sample is a small Android port of the excellent San Angeles Observation demo program.

Android API level 5

The NDK provides the following APIs for developing native code that runs on Android 2.0 system images and above.

OpenGL ES 2.0 library:

The standard OpenGL ES 2.0 headers and contain the declarations needed for performing OpenGL ES 2.0 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.

To use OpenGL ES 2.0, link your native module to /system/lib/libGLESv2.so by including the following line in your Android.mk file:

Not all devices support OpenGL ES 2.0. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.

Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.

The hello-gl2 sample application provies a basic example of how to use OpenGL ES 2.0 with the NDK.

The EGL APIs are only available starting from API level 9. You can, however, use the VM to perform some of the operations that you would get from those APIs. These operations include surface creation and flipping. For an example of how to use GLSurfaceView , see Introducing GLSurfaceView.

Note: The Android emulator does not support OpenGL ES 2.0 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 2.0.

Android API level 8

The NDK provides the following APIs for developing native code that runs on Android 2.2 system images and above.

jnigraphics

The jnigraphics library exposes a C-based interface that allows native code to reliably access the pixel buffers of Java bitmap objects. The workflow for using jnigraphics is as follows:

  1. Use AndroidBitmap_getInfo() to retrieve information from JNI, such as width and height, about a given bitmap handle.
  2. Use AndroidBitmap_lockPixels() to lock the pixel buffer and retrieve a pointer to it. Doing so ensures that the pixels do not move until the app calls AndroidBitmap_unlockPixels() .
  3. In native code, modify the pixel buffer as appropriate for its pixel format, width, and other characteristics.
  4. Call AndroidBitmap_unlockPixels() to unlock the buffer.

To use jnigraphics , include the header in your source code, and link against jnigraphics by including the following line in your Android.mk file:

Additional details about this feature are in the comments of the bitmap.h file.

Android API level 9

The NDK provides the following APIs for developing native code that runs on Android 2.3 system images and above.

EGL provides a native platform interface for allocating and managing OpenGLES surfaces. For more information about its features, see EGL Native Platform Interface.

EGL allows you to perform the following operations from native code:

  • List supported EGL configurations.
  • Allocate and release OpenGLES surfaces.
  • Swap or flip surfaces.

The following headers provide EGL functionality:

  • EGL/egl.h : the main EGL API definitions.
  • EGL/eglext.h : EGL extension-related definitions.

To link against the system’s EGL library, add the following line to your Android.mk file:

OpenSL ES

Android native audio handling is based on the Khronos Group OpenSL ES 1.0.1 API.

The standard OpenSL ES headers OpenSLES.h and OpenSLES_Platform.h contain the declarations necessary for performing audio input and output from the native side of Android. The NDK distribution of the OpenSL ES also provides Android-specific extensions. For information about these extensions, see the comments in OpenSLES_Android.h and OpenSLES_AndroidConfiguration.h .

The system library libOpenSLES.so implements the public native audio functions. Link against it by adding the following line to your Android.mk file:

For more information about the OpenSL ES API, refer to $NDK/docs/Additional_library_docs/opensles/index.html , where $NDK is your NDK installation root directory.

Android native application APIs

Starting from API level 9, you can write an entire Android app with native code, without using any Java.

Note: Writing your app in native code is not, in itself, enough for your app to run in the VM. Moreover, your app must still access most features of the Android platform via JNI.

This release provides the following native headers:

For more information about these headers, see the NDK API Reference documentation, as well as the comments in the headers, themselves. Also, for more information about the larger topic of writing native apps, see Native Activities and Applications.

When you include one or more of these headers, you must also link against the libandroid.so library. To link against libandroid.so , include the following line in your Android.mk file:

Android API level 14

The NDK provides the following APIs for developing native code that runs on Android 4.0 system images and above.

OpenMAX AL

Android native multimedia handling is based on Khronos Group OpenMAX AL 1.0.1 API.

The standard OpenMAX AL headers and contain the declarations necessary for performing multimedia output from the native side of Android.

The NDK distribution of OpenMAX AL also provides Android-specific extensions. For information about these extensions, see the comments in OpenMAXAL_Android.h .

The system library libOpenMAXAL.so implements the public native multimedia functions. To link against this library, include the following line in your Android.mk file:

For more information about this topic, see $NDK/docs/openmaxal/index.html , where $NDK is the root directory of your NDK installation.

OpenSL ES

OpenSL ES support for this Android API level adds PCM support. For more information about OpenSL ES support in the NDK, see OpenSL ES.

Android API level 18

The NDK provides the following APIs for developing native code that runs on Android 4.3 system images and above.

OpenGL ES 3.0

The standard OpenGL ES 3.0 headers gl3.h and gl3ext.h contain the declarations needed for performing OpenGL ES 3.0 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.

To use OpenGL ES 3.0, link your native module against /system/lib/libGLESv3.so by including the following line in your Android.mk file:

Not all devices support OpenGL ES 3.0. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.

Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.

The gles3jni sample application provides a basic example of how to use OpenGL ES 3.0 with the NDK.

Note: The Android emulator does not support OpenGL ES 3.0 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 3.0.

Android API level 21

The NDK provides the following APIs for developing native code that runs on Android 4.3 system images and above.

OpenGL ES 3.1

The standard OpenGL ES 3.1 headers gl31.h and gl3ext.h contain the declarations needed for performing OpenGL ES 3.1 rendering calls from native code. These rendering calls provide the ability to use the GLSL language to define and use vertex and fragment shaders.

To use OpenGL ES 3.1, link your native module against /system/lib/libGLESv3.so by including the following line in your Android.mk file:

Not all devices support OpenGL ES 3.1. An app can query the OpenGL ES version string and extension string to determine whether the current device supports the features it needs. For information on how to perform this query, see the description of glGetString() in the OpenGL specification.

Additionally, you must put a tag in your manifest file to indicate which version of OpenGL ES your application requires. For more information about the OpenGL ES settings for , see OpenGL ES.

The gles3jni sample application provides a basic example of how to use OpenGL ES 3.1 with the NDK.

Note: The Android emulator does not support OpenGL ES 3.1 hardware emulation. Running and testing code that uses this API requires a real device with hardware that can support OpenGL ES 3.1.

Источник

Android Native Application API

(For more resources related to this topic, see here.)

Based on the features provided by the functions defined in these header files, the APIs can be grouped as follows:

Activity lifecycle management:

Input (including key and motion events) and sensor events:

Assets, configuration, and storage management:

In addition, Android NDK also provides a static library named native app glue to help create and manage native activities. The source code of this library can be found under the sources/android/native_app_glue/ directory.

In this article, we will first introduce the creation of a native activity with the simple callback model provided by native_acitivity.h, and the more complicated but flexible two-threaded model enabled by the native app glue library. We will then discuss window management at Android NDK, where we will draw something on the screen from the native code. Input events handling and sensor accessing are introduced next. Lastly, we will introduce asset management, which manages the files under the assets folder of our project. Note that the APIs covered in this article can be used to get rid of the Java code completely, but we don’t have to do so. The Managing assets at Android NDK recipe provides an example of using the asset management API in a mixed-code Android project.

Before we start, it is important to keep in mind that although no Java code is needed in a native activity, the Android application still runs on Dalvik VM, and a lot of Android platform features are accessed through JNI. The Android native application API just hides the Java world for us.

Creating a native activity with the native_activity.h interface

The Android native application API allows us to create a native activity, which makes writing Android apps in pure native code possible. This recipe introduces how to write a simple Android application with pure C/C++ code.

Getting ready

Readers are expected to have basic understanding of how to invoke JNI functions.

How to do it…

The following steps to create a simple Android NDK application without a single line of Java code:

Create an Android application named NativeActivityOne. Set the package name as cookbook.chapter5.nativeactivityone.

Change the AndroidManifest.xml file as follows:

We should ensure that the following are set correctly in the preceding file:

The activity name must be set to android.app.NativeActivity.

The value of the android.app.lib_name metadata must be set to the native module name without the lib prefix and .so suffix.

android:hasCode needs to be set to true, which indicates that the application contains code. Note that the documentation in /docs/NATIVE-ACTIVITY.HTML gives an example of the AndroidManifest.xml file with android:hasCode set to false, which will not allow the application to start.

Add two files named NativeActivityOne.cpp and mylog.h under the jni folder. The ANativeActivity_onCreate method should be implemented in NativeActivityOne.cpp. The following is an example of the implementation:

Add the Android.mk file under the jni folder:

Build the Android application and run it on an emulator or a device. Start a terminal and display the logcat output using the following:

Alternatively, you can use the logcat view at Eclipse to see the logcat output. When the application starts, you should be able to see the following logcat output:

As shown in the screenshot, a few Android activity lifecycle callback functions are executed. We can manipulate the phone to cause other callbacks being executed. For example, long pressing the home button and then pressing the back button will cause the onWindowFocusChanged callback to be executed.

How it works…

In our example, we created a simple, “pure” native application to output logs when the Android framework calls into the callback functions defined by us. The “pure” native application is not really pure native. Although we did not write a single line of Java code, the Android framework still runs some Java code on Dalvik VM.

Android framework provides an android.app.NativeActivity.java class to help us create a “native” activity. In a typical Java activity, we extend android.app.Activity and overwrite the activity lifecycle methods. NativeActivity is also a subclass of android. app.Activity and does similar things. At the start of a native activity, NativeActivity. java will call ANativeActivity_onCreate, which is declared in native_activity.h and implemented by us. In the ANativeActivity_onCreate method, we can register our callback methods to handle activity lifecycle events and user inputs. At runtime, NativeActivity will invoke these native callback methods when the corresponding events occurred.

In a word, NativeActivity is a wrapper that hides the managed Android Java world for our native code, and exposes the native interfaces defined in native_activity.h.

The ANativeActivity data structure: Every callback method in the native code accepts an instance of the ANativeActivity structure. Android NDK defines the ANativeActivity data structure in native_acitivity.h as follows:

The various attributes of the preceding code are explained as follows:

callbacks: It is a data structure that defines all the callbacks that the Android framework will invoke with the main UI thread.

vm: It is the application process’ global Java VM handle. It is used in some JNI functions.

env: It is a JNIEnv interface pointer. JNIEnv is used through local storage data , so this field is only accessible through the main UI thread.

clazz: It is a reference to the android.app.NativeActivity object created by the Android framework. It can be used to access fields and methods in the android. app.NativeActivity Java class. In our code, we accessed the toString method of android.app.NativeActivity.

internalDataPath: It is the internal data directory path for the application.

externalDataPath: It is the external data directory path for the application.

internalDataPath and externalDataPath are NULL at Android 2.3.x. This is a known bug and has been fixed since Android 3.0. If we are targeting devices lower than Android 3.0, then we need to find other ways to get the internal and external data directories.

sdkVersion: It is the Android platform’s SDK version code. Note that this refers to the version of the device/emulator that runs the app, not the SDK version used in our development.

instance: It is not used by the framework. We can use it to store user-defined data and pass it around.

assetManager: It is the a pointer to the app’s instance of the asset manager. We will need it to access assets data. We will discuss it in more detail in the Managing assets at Android NDK recipe of this article

There’s more…

The native_activity.h interface provides a simple single thread callback mechanism, which allows us to write an activity without Java code. However, this single thread approach infers that we must quickly return from our native callback methods. Otherwise, the application will become unresponsive to user actions (for example, when we touch the screen or press the Menu button, the app does not respond because the GUI thread is busy executing the callback function).

A way to solve this issue is to use multiple threads. For example, many games take a few seconds to load. We will need to offload the loading to a background thread, so that the UI can display the loading progress and be responsive to user inputs. Android NDK comes with a static library named android_native_app_glue to help us in handling such cases. The details of this library are covered in the Creating a native activity with the Android native app glue recipe.

A similar problem exists at Java activity. For example, if we write a Java activity that searches the entire device for pictures at onCreate, the application will become unresponsive. We can use AsyncTask to search and load pictures in the background, and let the main UI thread display a progress bar and respond to user inputs.

Creating a native activity with the Android native app glue

The previous recipe described how the interface defined in native_activity.h allows us to create native activity. However, all the callbacks defined are invoked with the main UI thread, which means we cannot do heavy processing in the callbacks.

Android SDK provides AsyncTask, Handler, Runnable, Thread, and so on, to help us handle things in the background and communicate with the main UI thread. Android NDK provides a static library named android_native_app_glue to help us execute callback functions and handle user inputs in a separate thread. This recipe will discuss the android_native_app_glue library in detail.

Getting ready

The android_native_app_glue library is built on top of the native_activity.h interface. Therefore, readers are recommended to read the Creating a native activity with the native_activity.h interface recipe before going through this one.

How to do it…

The following steps create a simple Android NDK application based on the android_native_app_glue library:

Create an Android application named NativeActivityTwo. Set the package name as cookbook.chapter5.nativeactivitytwo.

Right-click on the NativeActivityTwo project, select Android Tools | Add Native Support.

Change the AndroidManifest.xml file as follows:

Add two files named NativeActivityTwo.cpp and mylog.h under the jni folder. NativeActivityTwo.cpp is shown as follows:

Add the Android.mk file under the jni folder:

Build the Android application and run it on an emulator or device. Start a terminal and display the logcat output by using the following command:

When the application starts, you should be able to see the following logcat output and the device screen will shows a black screen:

On pressing the back button, the following output will be shown:

How it works…

This recipe demonstrates how the android_native_app_glue library is used to create a native activity.

The following steps should be followed to use the android_native_app_glue library:

Implement a function named android_main. This function should implement an event loop, which will poll for events continuously. This method will run in the background thread created by the library.

Two event queues are attached to the background thread by default, including the activity lifecycle event queue and the input event queue. When polling events using the looper created by the library, you can identify where the event is coming from, by checking the returned identifier (either LOOPER_ID_MAIN or LOOPER_ID_INPUT). It is also possible to attach additional event queues to the background thread.

When an event is returned, the data pointer will point to an android_poll_source data structure. We can call the process function of this structure. The process is a function pointer, which points to android_app->onAppCmd for activity lifecycle events, and android_app->onInputEvent for input events. We can provide our own processing functions and direct the corresponding function pointers to these functions.

In our example, we implement a simple function named handle_activity_lifecycle_ events and point the android_app->onAppCmd function pointer to it. This function simply prints the cmd value and the user data passed along with the android_app data structure. cmd is defined in android_native_app_glue.h as an enum. For example, when the app starts, the cmd values are 10, 11, 0, 1, and 6, which correspond to APP_CMD_START, APP_CMD_RESUME, APP_CMD_INPUT_CHANGED, APP_CMD_INIT_WINDOW, and APP_CMD_ GAINED_FOCUS respectively.

android_native_app_glue Library Internals: The source code of the android_native_ app_glue library can be found under the sources/android/native_app_glue folder of Android NDK. It only consists of two files, namely android_native_app_glue.c and android_native_app_glue.h. Let’s first describe the flow of the code and then discuss some important aspects in detail.

Since the source code for native_app_glue is provided, we can modify it if necessary, although in most cases it won’t be necessary.

android_native_app_glue is built on top of the native_activity.h interface. As shown in the following code (extracted from sources/android/native_app_glue/ android_native_app_glue.c). It implements the ANativeActivity_onCreate function, where it registers the callback functions and calls the android_app_create function. Note that the returned android_app instance is pointed by the instance field of the native activity, which can be passed to various callback functions:

The android_app_create function (shown in the following code snippet) initializes an instance of the android_app data structure, which is defined in android_native_app_ glue.h. This function creates a unidirectional pipe for inter-thread communication. After that, it spawns a new thread (let’s call it background thread thereafter) to run the android_ app_entry function with the initialized android_app data as the input argument. The main thread will wait for the background thread to start and then return:

The background thread starts with the android_app_entry function (as shown in the following code snippet), where a looper is created. Two event queues will be attached to the looper. The activity lifecycle events queue is attached to the android_app_entry function. When the activity’s input queue is created, the input queue is attached (to the android_ app_pre_exec_cmd function of android_native_app_glue.c). After attaching the activity lifecycle event queue, the background thread signals the main thread it is already running. It then calls a function named android_main with the android_app data. android_main is the function we need to implement, as shown in our sample code. It must run in a loop until the activity exits:

The following diagram indicates how the main and background thread work together to create the multi-threaded native activity:

We use the activity lifecycle event queue as an example. The main thread invokes the callback functions, which simply writes to the write end of the pipe, while true loop implemented in the android_main function will poll for events. Once an event is detected, the function calls the event handler, which reads the exact command from the read end of the pipe and handles it. The android_native_app_glue library implements all the main thread stuff and part of the background thread stuff for us. We only need to supply the polling loop and the event handler as illustrated in our sample code.

Pipe: The main thread creates a unidirectional pipe in the android_app_create function by calling the pipe method. This method accepts an array of two integers. After the function is returned, the first integer will be set as the file descriptor referring to the read end of the pipe, while the second integer will be set as the file descriptor referring to the write end of the pipe.

A pipe is usually used for Inter-process Communication (IPC), but here it is used for communication between the main UI thread and the background thread created at android_ app_entry. When an activity lifecycle event occurs, the main thread will execute the corresponding callback function registered at ANativeActivity_onCreate. The callback function simply writes a command to the write end of the pipe and then waits for a signal from the background thread. The background thread is supposed to poll for events continuously and once it detects a lifecycle event, it will read the exact event from the read end of the pipe, signal the main thread to unblock and handle the events. Because the signal is sent right after receiving the command and before actual processing of the events, the main thread can return from the callback function quickly without worrying about the possible long processing of the events.

Different operating systems have different implementations for the pipe. The pipe implemented by Android system is “half-duplex”, where communication is unidirectional. That is, one file descriptor can only write, and the other file descriptor can only read. Pipes in some operating system is “full-duplex”, where the two file descriptors can both read and write.

Looper is an event tracking facility, which allows us to attach one or more event queues for an event loop of a thread. Each event queue has an associated file descriptor. An event is data available on a file descriptor. In order to use a looper, we need to include the android/ looper.h header file.

The library attaches two event queues for the event loop to be created by us in the background thread, including the activity lifecycle event queue and the input event queue. The following steps should be performed in order to use a looper:

Create or obtain a looper associated with the current thread: This is done by the ALooper_prepare function:

This function prepares a looper associated with the calling thread and returns it. If the looper doesn’t exist, it creates one, associates it with the thread, and returns it

Attach an event queue: This is done by ALooper_addFd. The function has the following prototype:

The function can be used in two ways. Firstly, if callback is set to NULL, the ident set will be returned by ALooper_pollOnce and ALooper_pollAll. Secondly, if callback is non-NULL, then the callback function will be executed and ident is ignored. The android_native_app_glue library uses the first approach to attach a new event queue to the looper. The input argument fd indicates the file descriptor associated with the event queue. ident is the identifier for the events from the event queue, which can be used to classify the event. The identifier must be bigger than zero when callback is set to NULL. callback is set to NULL in the library source code, and data points to the private data that will be returned along with the identifier at polling.

In the library, this function is called to attach the activity lifecycle event queue to the background thread. The input event queue is attached using the input queue specific function AInputQueue_attachLooper, which we will discuss in the Detecting and handling input events at NDK recipe.

Poll for events: This can be done by either one of the following two functions:

These two methods are equivalent when callback is set to NULL in ALooper_addFd. They have the same input arguments. timeoutMillis specifies the timeout for polling. If it is set to zero, then the functions return immediately; if it is set to negative, they will wait indefinitely until an event occurs. The functions return the identifier (greater than zero) when an event occurs from any input queues attached to the looper. In this case, outFd, outEvents, and outData will be set to the file descriptor, poll events, and data associated with the event. Otherwise, they will be set to NULL.

Detach event queues: This is done by the following function:

It accepts the looper and file descriptor associated with the event queue, and detaches the queue from the looper.

Источник

Читайте также:  Смартфон андроид восстановление системы
Оцените статью