Showing posts with label ndk. Show all posts
Showing posts with label ndk. Show all posts

Monday, September 7, 2015

Asynchronous and synchronous I/O in Android NDK

This week, I had some issues on my tests in a Lollipop device with AOSP. I really wanted to have synchronous reads/writes so that I could evaluate my solution in a different way. I am also trying to minimize the effects of caching as much as possible. If you check for async and sync I/O operations for Linux, you'll a lot of references to the flags O_DIRECT, O_SYNC, O_DSYNC, ...

Actually, that's a good way to implement. However, with Android NDK apps, things are not so straightforward.

First, to have a good understanding about the O_*SYNC flags, check this link. Of course, the man page for the command open as well.

First, O_DIRECT does not work in Android since 4.4. See this link for more details about it.  That's sad. So, let's try to use the O_*SYNC data.

O_SYNC and O_DSYNC work fine in Android. But, as the description say, only for writes. Another detail: for Android, O_SYNC has the same semantics as O_DSYNC. That's good, but I still want something similar to reads as well.

Why don't we use O_RSYNC? Well, Android does not implement it :-( But it's not the only one... there are other Linux distributions that don't do it either.

What about dropping caches?? See this link for more details. Hum, that works, but after the first read, the data will be cached again :-(

So, I am still looking for a solution for Android Lollipop. Hope to post it soon!


Saturday, August 2, 2014

Problem on linking OpenSSL into your NDK application

This week, I tried to compile a simple NDK application and link it with the OpenSSL library. Most of libraries (including OpenSSL) are not supported by the NDK, what makes it a bit more complicated to use. So, in this post, I describe what I usually do to properly compile applications that need external libs.

The project structure is as follows:

my_project/
    + jni/my_code.c
    + jni/Android.mk
    + jni/Application.mk
    + libs/system

Problem #01: How my Android.mk looks like?

In this example, I need two libraries: libcrypto.so and libssl.so. So, the final Android.mk looks like this

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := my_exec
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := my_code.c
LOCAL_C_INCLUDES += $(ANDROID_SRC)/external/openssl/include \ 
                    $(ANDROID_SRC)/external/openssl/crypto \ 
                    $(KERNEL_SRC)/kernel/module
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../libs/system
LOCAL_SHARED_LIBRARIES := libandroid libdl libz libcrypto libssl
LOCAL_LDLIBS += -landroid -ldl -lz


include $(BUILD_EXECUTABLE) 

See, as an example, that we also include the headers for the library (in ANDROID_SRC/external/openssl/include).

NDK does not provide support for libcrypto.so and libssl.so -- we need to have access to the libraries somehow. So, you should create a folder (for example, my_project/libs/system) and push the files /system/lib/libcrypto.so and /system/lib/libssl.so from the device to such folder.

Problem #02: Where do I get the libs from?

You shall get all of them (including libc.so) from your rooted device. The point is that, as I said, NDK does not provide support for libcrypto.so and libssl.so. Therefore, you need to get such libraries from the device. However, there's another problem: most likely, the libcrypto.so and libssl.so libraries don't recognize the symbols from the NDK libc.so and libstdc++.so libraries. Regarding this problem, it will be discussed on item #04.

Problem #03: Where do I get the headers from?

Usually, you get them from the android source code. For OpenSSL, they are located inside the folder ANDROID_SRC/external.

Problem #04: Why does my lib complain about libc symbols?

As I described in topic #02, you need to copy the libraries from the device. However, libcrypto.so and libssl.so do not recognize some symbols from the libc.so and libstdc++.so libraries (most likely, the libraries provided by NDK are not compatible with the ones in the device). Usually, you will have the following compilation error:

/home/raul/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/libcrypto.so: error: undefined reference to '__strlen_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/libcrypto.so: error: undefined reference to '__memcpy_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/libcrypto.so: error: undefined reference to '__memset_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: 
/home/raul/my_project/jni/../libs/system/libcrypto.so: error: undefined reference to '__strchr_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-
x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/libcrypto.so: error: undefined reference to '__strcat_chk'

That's easy to solve. Here comes the trick: you have to replace NDK's libraries by those ones from the device. NDK contains several libraries for distinct platforms, as we can see from the path NDK_FOLDER/platforms:

@desktop:$ ls NDK_FOLDER/platforms
android-12  android-13  android-14  android-15  android-16  android-17  
android-18  android-19  android-3   android-4   android-5   android-8  android-9

 Considering that your application is using NDK for platform android-17 (you can define that in file Application.mk), replace the main libraries of folder NDK_PATH/platforms/android-17

@desktop:$ ls NDK_FOLDER/platforms/android-17/arch-arm/usr/lib
crtbegin_dynamic.o  crtend_android.o  libc.a    libEGL.so       libjnigraphics.so libm_hard.a         libOpenSLES.so    libthread_db.so
crtbegin_so.o       crtend_so.o       libc.so   libGLESv1_CM.so  liblog.so       libm.so             libstdc++.a       libz.so

crtbegin_static.o   libandroid.so     libdl.so  libGLESv2.so     libm.a           libOpenMAXAL.so     libstdc++.so

So, push the libraries /system/lib/libc.so, and /system/lib/libstdc++.so from the device to the folder NDK_FOLDER/platforms/android-17/arch-arm/usr/lib. After that, compile the application again and voilĂ  -- all problems solved :-)