Uncategorized

Redirecting stdio to the Android Debug Log from a static/shared library

This is quite a technical post, but this issue seemed to take up most of an afternoon, so perhaps my notes will be useful to someone else…
I have a static library (in this case an audio codec) that is being integrated into an Android OMX/Stagefright audio decoder. There are some issues and it is crashing on certain input streams. This library has some debug (write to stderr) functionality already, but I can’t see it on the Android host as its going to stdio. So… how to get this into the Android debug log?
The OMX wrapper is built with the Android AOSP toolchain, but the library isn’t Android specific, and due to the use of assembler in its source and the differences between ARM assembler and GNU assembler, the library needs to be built with RVCT (RVDS/DS-5) and not the Android NDK.
Although Android is using bionic rather than libc I have managed to get away with using the ARM arm_linux stdc headers without problem., i.e:
 LDINCLUDE = /usr/local/DS-5/include/
The output static library from RVDS is placed somewhere in the AOSP/NDK build tree and the library is linked against during build with a few additions to the modules Android.mk:

LOCAL_PATH:= $(call my-dir)

MYLOCAL_PATH := $(LOCAL_PATH)

include $(CLEAR_VARS)


# Tell the build system about the existing (pre-built) library.

# Note: The library name appears here and in the LOCAL_WHOLE_STATIC_LIBRARIES below.

# Also, the path is relative to the path of this makefile

LOCAL_PREBUILT_LIBS += prebuilt/my_lib.a



include $(BUILD_MULTI_PREBUILT)



LOCAL_PATH := $(MYLOCAL_PATH)

include $(CLEAR_VARS)



LOCAL_SRC_FILES := myDecoder.cpp



LOCAL_C_INCLUDES := \

        frameworks/av/media/libstagefright/include \

        frameworks/av/include/media/stagefright \

        frameworks/native/include/media/openmax \

        $(LOCAL_PATH)/src \

        $(LOCAL_PATH)/include \



LOCAL_CFLAGS := -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= 

LOCAL_STATIC_LIBRARIES := my_lib



LOCAL_SHARED_LIBRARIES := libstagefright libstagefright_omx libstagefright_foundation libutils libcutils



LOCAL_MODULE := libstagefright_soft_mydec



LOCAL_MODULE_TAGS := optional



include $(BUILD_SHARED_LIBRARY)
I have only experienced one problem with doing this, which is that if building with the RVCT linux headers, calling printf(stderr, “msg”) produces a linkage error against aeabi_stderr when attemping to link the static library into the Android library:
/media/Android_Build/build/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld: out/target/product/toro/obj/STATIC_LIBRARIES/dec_lib_intermediates/my_lib.a(fmi_api.o): in function ddpi_fmi_checkframe:sub_dec/fmi_api.c(.text+0x1e8): error: undefined reference to '__aeabi_stderr'
This isn’t unexpected, as I’m building with the RVCT libc rather than bionic. To work around this, link against the NDK/AOSP c headers. In my case they’re at:
/home/rob/android_ndk/android-ndk-r7/platforms/android-14/arch-arm/usr/include
I still had one error at this point, as RVCT was looking for linux_rvct.h. Including this in the path solved the last build error, and the library now links during the AOSP build.
Lets look at the library contents with nm. The library with the problem:
axdd.o:

00000000 t $a

000001dc t $a

00000178 t $d

         U __aeabi_stderr

00000000 T xdd_init

000001dc T xdd_seek

0000001c T xdd_unp

         U bso_init

         U bso_rewind

         U fprintf
And now:
axdd.o:

00000000 t $a

000001d8 t $a

00000174 t $d

00000000 a          U __sF

00000000 T xdd_init

000001d8 T xdd_seek

0000001c T xdd_unp

         U bso_init

         U bso_rewind

         U fprintf



__aeabi_stderr is now __sF
Bionic defines sF:
#define stderr (&__sF[2])
All looking good!
The last job is to get dalvik to pipe stderr to the system log. This is covered at: http://developer.android.com/tools/debugging/debugging-log.html
In this case, /data/local.prop did not exist and I had to add the property to build.prop via adb:
cat "log.redirect-stdio=true" >> /system/build.prop
This persists after a reboot, so should have been picked up by dalvik when it started.
Outside the scope of this document, the decoder shared library was then pushed into the phone’s filesystem. However there still wasn’t anything in the log.
Searching around, it looks as though the stderr() output isn’t being piped into the log as redirect-stdio only refers to the dalvik VM. What is needed is to include the Android Native logging API and use the ___android_log_write() method.
See:
Rebuild the library and here we go…. log data appears in the adb log:
01-02 01:25:30.734: E/mydec_subdec(129): FATAL ERROR:  auxdatal > frmsz

01-02 01:25:30.734: E/mydec_subdec(129): Error occurred in:

01-02 01:25:30.734: E/mydec_subdec(129): my_dec/xdd.c (line 88)

In this case a macro was being used:
#define         ERR_PRINTERRMSG(a)               __android_log_print(ANDROID_LOG_ERROR,"ddp_subdec","\n\nFATAL ERROR:  %s\n\nError occurred in:\n%s (line %d)\n\n", (a),__FILE__,__LINE__)
In this specific case of this library some aux data is out of bounds and the assert on this was crashing. In case you were interested.
01-02 01:55:08.328: V/subdec_axdd(2841): auxdatal=4868

01-02 01:55:08.804: V/subdec_axdd(2841): auxdatal=6870

01-02 01:55:10.023: V/subdec_axdd(2841): auxdatal=6951

01-02 01:55:10.453: V/subdec_axdd(2841): auxdatal=8404

01-02 01:55:12.398: V/subdec_axdd(2841): auxdatal=2260

01-02 01:55:13.453: V/subdec_axdd(2841): auxdatal=3476

01-02 01:55:13.757: V/subdec_axdd(2841): auxdatal=6356

01-02 01:55:14.171: V/subdec_axdd(2841): auxdatal=11460

01-02 01:55:15.757: V/subdec_axdd(2841): auxdatal=6916

01-02 01:55:16.320: V/subdec_axdd(2841): auxdatal=9332

01-02 01:55:16.398: V/subdec_axdd(2841): auxdatal=10950

01-02 01:55:16.421: V/subdec_axdd(2841): auxdatal=8532

01-02 01:55:16.632: V/subdec_axdd(2841): auxdatal=11476

01-02 01:55:16.781: V/subdec_axdd(2841): auxdatal=13015

01-02 01:55:17.500: V/subdec_axdd(2841): auxdatal=6870

01-02 01:55:17.929: V/subdec_axdd(2841): auxdatal=3940
The only real downside to this method is that the source of the static library is needed. If that is true, then this is a useful tool for debugging the library on an Android host. If we don’t have the source, then this won’t work and a more generic way of intercepting stdio output would be required in the operating system itself.