2013年1月13日星期日

设定Android NDK编译环境并移植ffmpeg


简介

本文介绍如何使用 Android NDK(r7) 设置 Android 本地代码编译工具链,如何根据 Makefile 编写 Android.mk,并以 ffmpeg(0.8.5) 为例子介绍如何使用此工具链移植。使用编译出来的库文件,可以通过本地 C/C++ 程序调用 ffmpeg 解码库;也可以另外编写 JNI 接口,使用 Java 程序调用 ffmepg。


我们都知道编译软件的一般步骤为:

./configure
make
make install

当然还可以增加参数做些自定义,但大概的流程是这样。要移植一个已有的库到 Android 当中却有很大的不同,首先需要搭建一个交叉编译环境去运行 configure 脚本以便生成配置文件,然后还需要编写 Android.mk 才能编译。

ffmpeg 作例子,运行 configure 会生成 config.mak、config.h 和 libavutil/avconfig.h 这几个文件,里面决定了 ffmpeg 编译哪些模块、是否开启某些特性等。当然如果足够熟悉的话也可以手动修改这几个文件,但是其中的依赖关系复杂,较容易出错。接着根据原来的 Makefile 手动编写 Android.mk 文件,就能编译了。以下是详细流程。

注意:不能直接在宿主系统上运行 configure 脚本,因为环境和目标系统(Android)是不同的,这需要建立交叉编译环境。

如何检测 Android Cursor 泄漏

简介

本文介绍如何在 Android 检测 Cursor 泄漏的原理以及使用方法,还指出几种常见的出错示例。有一些泄漏在代码中难以察觉,但程序长时间运行后必然会出现异常。同时该方法同样适合于其他需要检测资源泄露的情况。



最近发现某蔬菜手机连接程序在查询媒体存储(MediaProvider)数据库时出现严重 Cursor 泄漏现象,运行一段时间后会导致系统中所有使用到该数据库的程序无法使用。另外在工作中也常发现有些应用有 Cursor 泄漏现象,由于需要长时间运行才会出现异常,所以有的此类 bug 很长时间都没被发现。

但是一旦 Cursor 泄漏累计到一定数目(通常为数百个)必然会出现无法查询数据库的情况,只有等数据库服务所在进程死掉重启才能恢复正常。通常的出错信息如下,指出某 pid 的程序打开了 866 个 Cursor 没有关闭,导致了 exception:


3634 3644 E JavaBinder: *** Uncaught remote exception! (Exceptions are not yet supported across processes.)
3634 3644 E JavaBinder: android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=866 (# cursors opened by pid 1565=866)
3634 3644 E JavaBinder: at android.database.CursorWindow.(CursorWindow.java:104)
3634 3644 E JavaBinder: at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:147)
3634 3644 E JavaBinder: at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:141)
3634 3644 E JavaBinder: at android.database.CursorToBulkCursorAdaptor.getBulkCursorDescriptor(CursorToBulkCursorAdaptor.java:143)
3634 3644 E JavaBinder: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:118)
3634 3644 E JavaBinder: at android.os.Binder.execTransact(Binder.java:367)
3634 3644 E JavaBinder: at dalvik.system.NativeStart.run(Native Method)