Building WebRTC for Android

ENV
Ubuntu

入门以及下载源码
https://webrtc.org/native-code/development/
https://webrtc.org/native-code/android/

gclient config --name=src https://chromium.googlesource.com/external/webrtc.git
echo "target_os = ['android']" >> .gclient
gclient sync --force
gclient runhooks --force

查看支持的参数列表

gn args --list out/Debug

设置参数

gn gen out/Debug --args='target_os="android" rtc_include_tests=false enable_nocompile_tests=true libyuv_include_tests=false'

开始编译

ninja -C out/Debug 或者 ninja -C out/Release

内存不够的时候就用 -j1 或者 -j2

需要使用项目自带的一些工具的时候需要执行

source ./build/android/envsetup.sh

可能出现的问题

guohai@ubuntu:/home/guohai/WebRTC/src$ ninja -C out/Debug
ninja: Entering directory `out/Debug'
[4/3003] ACTION //base:android_runtime_jni_headers__jni_Runtime(//build/toolchain/android:android_clang_arm)
FAILED: gen/base/android_runtime_jni_headers/base/jni/Runtime_jni.h 
python ../../base/android/jni_generator/jni_generator.py --jar_file ../../third_party/android_tools/sdk/platforms/android-28/android.jar --input_file java/lang/Runtime.class --ptr_type=long --output_dir gen/base/android_runtime_jni_headers/base/jni --includes ../../../../../../../base/android/jni_generator/jni_generator_helper.h
Traceback (most recent call last):
  File "../../base/android/jni_generator/jni_generator.py", line 1405, in <module>
    sys.exit(main(sys.argv))
  File "../../base/android/jni_generator/jni_generator.py", line 1401, in main
    GenerateJNIHeader(input_file, output_file, options)
  File "../../base/android/jni_generator/jni_generator.py", line 1308, in GenerateJNIHeader
    jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
  File "../../base/android/jni_generator/jni_generator.py", line 773, in CreateFromClass
    stderr=subprocess.PIPE)
  File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
Java 环境变量没有设置好,这里需要 javap 命令
/home/guohai/WebRTC/src/third_party/android_tools/sdk//build-tools/22.0.0/aapt: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
sudo apt-get install lib32z1

Hello World Android Things

物联网 IoT(Internet of things) 一个听起来高大上,但是实际上是历史悠久东西,但是随着社会/科技的发展(网络,协议,设备等等共同的发展),近些年被正式命名了。

以前开发这类的产品都需要复杂的流程,比如厂商基于某款特定的硬件,移植某个嵌入式的操作系统,然后在上面开发定制化的程序,可能需要懂些底层的东西,比如驱动程序等等,而且运行资源都相对来说很有限。

但是 Google 某一天宣布了一个叫做 Android Things 的东西,好像很多事情都变的简单些了。

这里就不介绍了,直接入门,记录怎么让第一个程序如何跑起来。

1) 硬件设备 RASPBERRY PI 3 MODEL B

我个人比较喜欢这款性价比高的硬件设备,自己买过一些开发板,这个完全不心疼 ^_^

不管是二手的,还是新的,只要型号对的,买个就好了(以前我也很纠结是买原产国还是买国产的,后来就选择买便宜的)

2) 操作系统 Android Things

https://developer.android.com/things/hardware/raspberrypi.html

下载镜像(https://developer.android.com/things/preview/download.html),烧录到 Micro SD Card 上,具体办法网上搜索(我这里旧物利用,翻出来原来 Motorola Milestone 上的一张卡)。制作完毕之后就可以插电开机(USB 供电,HDMI 视频输出,HDMI 也可以提供供电)。

开机之后的画面
at-iot-home

RASPBERRY PI 3 MODEL B 支持无线网络和有线网络,开发调试 adb 支持无线和有线

我这里使用的是 macOS

查看接入的 SD Card 挂载位置

diskutil list
sudo dd bs=1m if=iot_rpi3.img of=/dev/disk3

具体文件名和挂载位置根据实际情况修改

3) 开发程序

https://developer.android.com/things/sdk/samples.html

推出 Android Things 的意图就是物联网会爆发起来(虽然目前还不确切知道什么时候),所以开发程序必须要简单快速。最简单的看下本 Sample 就好了。

本程序和普通的 Android 程序配置上差别不大,就是新建一个标准的 Phone/Tablet 项目就好,主要在 app/build.gradle 和 AndroidManifest.xml 当中有点差别

Jshell 启动错误 build 9-ea+121


Exception in thread "main" java.lang.InternalError: Launching execution engine threw: Failed remote launch: com.sun.jdi.CommandLineLaunch (defaults: home=/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home, options=, main=, suspend=true, quote=", vmexec=java) -- {home=home=/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home, options=options=, main=main=jdk.internal.jshell.remote.RemoteAgent 57696, suspend=suspend=true, quote=quote=", vmexec=vmexec=java}
at jdk.jshell.JShell.executionControl(jdk.jshell@9-ea/JShell.java:714)
at jdk.jshell.Unit.classesToLoad(jdk.jshell@9-ea/Unit.java:275)
at jdk.jshell.Eval.lambda$compileAndLoad$15(jdk.jshell@9-ea/Eval.java:580)
at java.util.stream.ReferencePipeline$7$1.accept(java.base@9-ea/ReferencePipeline.java:269)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(java.base@9-ea/ArrayList.java:1477)
at java.util.stream.AbstractPipeline.copyInto(java.base@9-ea/AbstractPipeline.java:484)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(java.base@9-ea/AbstractPipeline.java:474)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(java.base@9-ea/ReduceOps.java:913)
at java.util.stream.AbstractPipeline.evaluate(java.base@9-ea/AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(java.base@9-ea/ReferencePipeline.java:511)
at jdk.jshell.Eval.compileAndLoad(jdk.jshell@9-ea/Eval.java:581)
at jdk.jshell.Eval.declare(jdk.jshell@9-ea/Eval.java:441)
1 127.0.0.1 Hais-MacBook-Pro
at jdk.jshell.Eval.processMethod(jdk.jshell@9-ea/Eval.java:372)
at jdk.jshell.Eval.eval(jdk.jshell@9-ea/Eval.java:127)
at jdk.jshell.JShell.eval(jdk.jshell@9-ea/JShell.java:393)
at jdk.internal.jshell.tool.JShellTool.processCompleteSource(jdk.jshell@9-ea/JShellTool.java:2114)
at jdk.internal.jshell.tool.JShellTool.processSource(jdk.jshell@9-ea/JShellTool.java:2102)
at jdk.internal.jshell.tool.JShellTool.processSourceCatchingReset(jdk.jshell@9-ea/JShellTool.java:789)
at jdk.internal.jshell.tool.JShellTool.run(jdk.jshell@9-ea/JShellTool.java:769)
at jdk.internal.jshell.tool.JShellTool.startUpRun(jdk.jshell@9-ea/JShellTool.java:706)
at jdk.internal.jshell.tool.JShellTool.resetState(jdk.jshell@9-ea/JShellTool.java:663)
at jdk.internal.jshell.tool.JShellTool.start(jdk.jshell@9-ea/JShellTool.java:483)
at jdk.internal.jshell.tool.JShellTool.start(jdk.jshell@9-ea/JShellTool.java:462)
at jdk.internal.jshell.tool.JShellTool.main(jdk.jshell@9-ea/JShellTool.java:452)
Caused by: java.lang.InternalError: Failed remote launch: com.sun.jdi.CommandLineLaunch (defaults: home=/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home, options=, main=, suspend=true, quote=", vmexec=java) -- {home=home=/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home, options=options=, main=main=jdk.internal.jshell.remote.RemoteAgent 57696, suspend=suspend=true, quote=quote=", vmexec=vmexec=java}
at jdk.internal.jshell.jdi.JDIConnection.reportLaunchFail(jdk.jshell@9-ea/JDIConnection.java:353)
at jdk.internal.jshell.jdi.JDIConnection.launchTarget(jdk.jshell@9-ea/JDIConnection.java:319)
at jdk.internal.jshell.jdi.JDIConnection.open(jdk.jshell@9-ea/JDIConnection.java:120)
at jdk.internal.jshell.jdi.JDIEnv.init(jdk.jshell@9-ea/JDIEnv.java:49)
at jdk.internal.jshell.jdi.JDIExecutionControl.jdiGo(jdk.jshell@9-ea/JDIExecutionControl.java:425)
at jdk.internal.jshell.jdi.JDIExecutionControl.start(jdk.jshell@9-ea/JDIExecutionControl.java:95)
at jdk.jshell.JShell.executionControl(jdk.jshell@9-ea/JShell.java:712)
... 23 more
Caused by: com.sun.jdi.connect.VMStartException: VM initialization failed for: /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,address=Hais-MacBook-Pro:57697,suspend=y jdk.internal.jshell.remote.RemoteAgent 57696
at com.sun.tools.jdi.AbstractLauncher$Helper.launchAndAccept(jdk.jdi@9-ea/AbstractLauncher.java:193)
at com.sun.tools.jdi.AbstractLauncher.launch(jdk.jdi@9-ea/AbstractLauncher.java:132)
at com.sun.tools.jdi.SunCommandLineLauncher.launch(jdk.jdi@9-ea/SunCommandLineLauncher.java:225)
at jdk.internal.jshell.jdi.JDIConnection.launchTarget(jdk.jshell@9-ea/JDIConnection.java:312)
... 28 more

https://bugs.openjdk.java.net/browse/JDK-8131029
这个问题在新版的已经被修复了,但是如果碰到了,可以修改 /etc/hosts 来绕过(增加一个本地计算机名字的 loop ip)

本地计算机名字可以用
uname -n
来查看

参考这个文章找到的 workaround

小结二零一五

虽然都是流水账(这年终总结也做的太晚了T_T),但是还是要记录一下,还是分 2 个部分。

工作上有喜也有忧,总之创业不是个容易的事情,“大众创业万众创新”看起来很霸气,但是你看看今年死掉多少创业公司就知道了,还好我们还算幸运,公司人力和业务在这一年都有了比较大的进展,但是距离目标还是很遥远。自己负责的这一块整体进展还不令人满意(自己的角色也从一个不停写代码的人转变为写代码 + 维护整体项目),但是今年应该会有些努力尝试的方向和自由度,另外也需要更集中精力,因为不免杂事很多,需要花比较多的时间来处理,效率下降。不过总之我们都还是走在正确的路上。

生活上今年膝盖受伤(膝关节脂肪垫磨损)是最大的障碍了,医生劝告自己修养,所以很多运动都无法进行,非常感谢这期间同事一段时间内几乎每天帮我带外卖,希望 2016 年能恢复到可以自由的玩所有各种运动(千万是不要自己作死,哈哈哈)。能和喜欢的人在一起也很开心,虽然经历了千辛万苦,期待我们的未来美好,当然先努力实现我们的一些小愿望吧,一步一步朝前走。

还有一件重要的事情是时间上能安排合理,需要看书,写代码,写博客,这地方基本已经处于半荒废状态了。
忙,不要把自己忙的找不到方向了

P.S. 目前我们正在做的是互联网上提供有保障的实时音视频传输方案,Powering Real-Time Communications,agora.io,广告就不多做啦

独立编译 Skia for Android

最近想了解下 Skia 相关的东西,想利用其中的一些 API 来做做优化,所以打算独立编译一个版本试试看。

https://skia.org/user/quick/android

使用的代码版本


commit 81bdbf8bed8b739c2b65ac576e89d0258276e6dc
Author: caryclark
Date: Wed Oct 21 04:16:19 2015 -0700

编译环境

Ubuntu 14.04.2

直接按照官方说明就可以编译出来,我这里是不想去下载一遍 NDK,所以进行了点改动。


http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin

如果机器上已经安装过对应版本的 NDK,可以修改以下文件直接生成 TOOLCHAIN(这个步骤不是必须的)

/mnt/extra/skia/platform_tools/android/bin/utils/setup_toolchain.sh


function default_toolchain() {
- TOOLCHAINS=${SCRIPT_DIR}/../toolchains
+ TOOLCHAINS=/home/ubuntu/dev

ANDROID_ARCH=${ANDROID_ARCH-arm}
LLVM=3.6
@@ -50,19 +50,13 @@ function default_toolchain() {
exportVar ANDROID_TOOLCHAIN "${TOOLCHAINS}/${TOOLCHAIN}/bin"

if [ ! -d "$ANDROID_TOOLCHAIN" ]; then
- mkdir -p $TOOLCHAINS
pushd $TOOLCHAINS
- curl -o $NDK.bin https://dl.google.com/android/ndk/android-ndk-$NDK-$HOST-x86_64.bin
- chmod +x $NDK.bin
- ./$NDK.bin -y
./android-ndk-$NDK/build/tools/make-standalone-toolchain.sh \
--arch=$ANDROID_ARCH \
--llvm-version=$LLVM \
--platform=android-$API \
--install_dir=$TOOLCHAIN
cp android-ndk-$NDK/prebuilt/android-$ANDROID_ARCH/gdbserver/gdbserver $TOOLCHAIN
- rm $NDK.bin
- rm -rf android-ndk-$NDK
popd
fi

生成过一次 TOOLCHAIN 之后也可以把

export ANDROID_TOOLCHAIN=/home/ubuntu/dev/arm-r10e-14/bin
export PATH=$ANDROID_TOOLCHAIN:$PATH

手动加在到配置文件里面去(这个步骤不是必须的)


./platform_tools/android/bin/android_ninja -d nexus_5

然后就是等待编译,如果中途编译 APK 的时候却少一些特定版本的 Build Tool 的时候修改下 App 当中使用版本就好了,或者也可以去更新代码当中对应的版本
App 代码位于

/mnt/extra/skia/platform_tools/android/apps/

编译完成之后就可以在
/mnt/extra/skia/out/config/android-nexus_5/Debug
下看到 so 了

android.util.Pair 引起的崩溃

博客好久没有更新过了。
一直都觉得自己没啥时间 囧囧

创业开始一直都在负责 App 相关的工作。
早上例行看了下昨日统计,崩溃率暴涨,但是就维持在 4 个用户,一看 Android 版本,都是 4.0.4,
心想肯定尼玛有碰到了不该用的 API。


FATAL EXCEPTION: h-262 262
PID: 2610
java.lang.NullPointerException
at android.util.Pair.hashCode(Pair.java:63)
at java.lang.Object.toString(Object.java:332)
at java.lang.StringBuilder.append(StringBuilder.java:202)
at java.util.AbstractMap.toString(AbstractMap.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:202)
......
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at cc.beckon.service.a.h.run(l:159)

看了下最新的 android.util.Pair 代码,似乎没有什么问题,然后追溯这个文件的修改历史
Screen Shot 2015-10-06 at 12.34.01 PM
对于为 Null 的值在低版本的 Pair 上确实无法处理,回过头来看,在这条案例上没有测试到就直接上了,该打。

小结二零一四

看了下 2014 年的目标 小结二零一三,很多都没有完成。。。所以 2015 年的目标就是把 2014 年的完成[我知道你们会不相信 @_@]。

2014
中秋回家看了一次家人,然后还算经常地给他们通电话。。。

在一家 Vans 店看到别人玩滑板的视屏觉得很酷,然后自己买了块板开始玩,不过时间有限,努力训练也没有别人多,所以技术自然也不是特别好,处于一个需要认真训练才能跨过的坎,反正慢慢玩呗,有空晚上去滑滑,看别人滑滑,跟着大部队刷刷街

上半年还比较勤的去玩篮球,下半年就只能呵呵了

有一个事情还是算好的,现在大部分时间可以坐直了工作(以前都是弯着腰),形成了习惯,不过不知道对脊柱有没有什么不良影响

其它大部分时间应该都是工作,吃饭,睡觉,一直处于忙碌状态

OS X 上交叉编译在 Android 上运行的 libevent

下载官方源码 这里使用的是 libevent-2.0.21

首先看了下这几篇文章

http://blog.csdn.net/sozell/article/details/8898646
http://blog.csdn.net/cutesource/article/details/8970641
http://blog.chinaunix.net/uid-20514606-id-485808.html
注意,以下 $ANDROID_NDK 都是本机上 NDK 的路径

export ANDROID_ROOT=$ANDROID_NDK

export PATH=$PATH:$ANDROID_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin

 ./configure \
 --host=arm-linux-androideabi \
 CC=arm-linux-androideabi-gcc \
 LD=arm-linux-androideabi-ld \
 CPPFLAGS="-I$ANDROID_ROOT/platforms/android-14/arch-arm/usr/include/" \
 CFLAGS="-nostdlib" \
 LDFLAGS="-Wl,-rpath-link=$ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/ -L$ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/" \
 LIBS="-lc -lgcc -L$ANDROID_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9"

ln -s $ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/crtbegin_so.o
ln -s $ANDROID_ROOT/platforms/android-14/arch-arm/usr/lib/crtend_so.o

make

还有另外一种方法,看起来比较正规点

http://stackoverflow.com/questions/11929773/compiling-the-latest-openssl-for-android

以下是编译armv7-a的方法(其它arch需要稍微调整下)

注意,以下 $ANDROID_NDK 都是本机上 NDK 的路径

export NDK=$ANDROID_NDK
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-14 --toolchain=arm-linux-androideabi-4.9 --install-dir=`pwd`/android-toolchain-arm
export TOOLCHAIN_PATH=`pwd`/android-toolchain-arm/bin
export TOOL=arm-linux-androideabi
export NDK_TOOLCHAIN_BASENAME=${TOOLCHAIN_PATH}/${TOOL}
export CC=$NDK_TOOLCHAIN_BASENAME-gcc
export CXX=$NDK_TOOLCHAIN_BASENAME-g++
export LINK=${CXX}
export LD=$NDK_TOOLCHAIN_BASENAME-ld
export AR=$NDK_TOOLCHAIN_BASENAME-ar
export RANLIB=$NDK_TOOLCHAIN_BASENAME-ranlib
export STRIP=$NDK_TOOLCHAIN_BASENAME-strip
export ARCH_FLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"
export ARCH_LINK="-march=armv7-a -Wl,--fix-cortex-a8"
export CPPFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 "
export CXXFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -frtti -fexceptions "
export CFLAGS=" ${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 "
export LDFLAGS=" ${ARCH_LINK} "

./configure --host=arm-linux-androideabi

就会在 .libs 下生成 so/a 档案

例子程序程序调用过程当中遇到的问题,具体完整代码参见 https://github.com/guohai/and-libevent

guohai@Hais-MacBook-Pro:~/Dev/work/idea/and-libevent/app/src/main/jni$ ndk-build V=1 -B
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/lib*.so /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/lib*.so
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/gdbserver /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/gdbserver
rm -f /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/arm64-v8a/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/armeabi-v7a-hard/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/mips64/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86/gdb.setup /Users/guohai/Dev/work/idea/and-libevent/app/src/main/libs/x86_64/gdb.setup
[armeabi-v7a] Compile thumb  : demo_libevent <= demo_libevent.c
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-gcc -MMD -MP -MF /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -no-canonical-prefixes -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb -Os -g -DNDEBUG -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni -DANDROID  -Wa,--noexecstack -Wformat -Werror=format-security    -I/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/include -c  /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/demo_libevent.c -o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o
[armeabi-v7a] Executable     : demo_libevent
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ -Wl,--gc-sections -Wl,-z,nocopyreloc --sysroot=/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm -Wl,-rpath-link=/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib -Wl,-rpath-link=/Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/objs/demo_libevent/demo_libevent.o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_core.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_extra.a /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent_pthreads.a -lgcc -no-canonical-prefixes -march=armv7-a -Wl,--fix-cortex-a8  -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now  -L/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib -llog -lc -lm -o /Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/demo_libevent
/Users/guohai/Dev/android-ndk-r10c/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /Users/guohai/Dev/work/idea/and-libevent/app/src/main/jni/libevent.a(event.o): in function evthread_make_base_notifiable:event.c(.text.evthread_make_base_notifiable+0x5c): error: undefined reference to 'eventfd'
collect2: ld returned 1 exit status
make: *** [/Users/guohai/Dev/work/idea/and-libevent/app/src/main/obj/local/armeabi-v7a/demo_libevent] Error 1

eventfd 是 2.6.22 加入到内核当中的系统调用,然后默认写的 -L/Users/guohai/Dev/android-ndk-r10c/platforms/android-3/arch-arm/usr/lib 内核比较低,于是修改

APP_PLATFORM := android-14

编译通过

在模拟器上启动程序,配置端口转发,测试

guohai@Hais-MacBook-Pro:~$ adb forward tcp:9995 tcp:9995

guohai@Hais-MacBook-Pro:~$ telnet localhost 9995
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello, World!
Connection closed by foreign host.

服务器端的反馈

root@generic:/data/data # ./demo_libevent                                        
flushed answer
^CCaught an interrupt signal; exiting cleanly in two seconds.
done
root@generic:/data/data # exit

Android 当中的坑

这里顺便记录下 Android 应用开发当中的一个一个的坑,很多时候我们都在面对这种问题,不同版本,不同厂商。。。
也许没有详尽/优雅的解决方法,但是至少问题在这里

1. SoundPool.play在 Android 4.3 当中没有办法 looping 播放
https://code.google.com/p/android/issues/detail?id=58113

2. Streaming 播放声音的时候(比如 AudioManager.MODE_IN_COMMUNICATION)无法切换外放
AudioManager.setMode(AudioManager.MODE_IN_CALL); // 切换成电话模式就可以切换
AudioManager.setSpeakerphoneOn(true);

3. 在某些机器上,比如插入耳机的时候无法切换外放

4. 写个跟 Android 编译相关的
Ant 脚本当中还是很老的 Java 1.5
参见 $ANDROID_HOME/tools/ant/build.xml

<property name="java.target" value="1.5" />
<property name="java.source" value="1.5" />

对于追求新的人来说当然太老了,Android 开发都用 Java 7,自己玩都用 Java 9 了

    [javac]   (use -source 7 or higher to enable diamond operator)
    [javac]   XXXX error: diamond operator is not supported in -source 1.5

所以如果实在要用 Ant 的话,需要手动改改,build.xml 同级目录加入 ant.properties 文件
里面内容增加

java.source=1.7
java.target=1.7

Parcelable encounteredClassNotFoundException reading a Serializable object

记录下,这个问题一直无法知道合理的原因

1065 07-09 22:25:29.927 670 918 E AmStub : java.lang.RuntimeException: Parcelable encounteredClassNotFoundException reading a Serializable object (name = xx.oo.MySerializableObject)
1066 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readSerializable(Parcel.java:2148)
1067 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readValue(Parcel.java:2016)
1068 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readMapInternal(Parcel.java:2226)
1069 07-09 22:25:29.927 670 918 E AmStub : at android.os.Bundle.unparcel(Bundle.java:223)
1070 07-09 22:25:29.927 670 918 E AmStub : at android.os.Bundle.containsKey(Bundle.java:271)
1071 07-09 22:25:29.927 670 918 E AmStub : at android.content.Intent.hasExtra(Intent.java:4414)
1072 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.c.a(Unknown Source)
1073 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.AmSmartShowStub.checkStartActivity(Unknown Source)
1074 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.checkStartActivity(ActivityManagerService.java:3015)
1075 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3224)
1076 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:3213)
1077 07-09 22:25:29.927 670 918 E AmStub : at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:144)
1078 07-09 22:25:29.927 670 918 E AmStub : at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:1968)
1079 07-09 22:25:29.927 670 918 E AmStub : at android.os.Binder.execTransact(Binder.java:351)
1080 07-09 22:25:29.927 670 918 E AmStub : at dalvik.system.NativeStart.run(Native Method)
1081 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.ClassNotFoundException: xx.oo.MySerializableObject
1082 07-09 22:25:29.927 670 918 E AmStub : at java.lang.Class.classForName(Native Method)
1083 07-09 22:25:29.927 670 918 E AmStub : at java.lang.Class.forName(Class.java:217)
1084 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2279)
1085 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1638)
1084 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:2279)
1085 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1638)
1086 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:658)
1087 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1781)
1088 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:762)
1089 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1981)
1090 07-09 22:25:29.927 670 918 E AmStub : at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1938)
1091 07-09 22:25:29.927 670 918 E AmStub : at android.os.Parcel.readSerializable(Parcel.java:2142)
1092 07-09 22:25:29.927 670 918 E AmStub : … 14 more
1093 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.NoClassDefFoundError: xx/oo/MySerializableObject
1094 07-09 22:25:29.927 670 918 E AmStub : … 24 more
1095 07-09 22:25:29.927 670 918 E AmStub : Caused by: java.lang.ClassNotFoundException: Didn’t find class “xx.oo.MySerializableObject” on path: DexPathList[[zip file “/system/framework/mediatek-op.jar”],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
1096 07-09 22:25:29.927 670 918 E AmStub : at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:53)
1097 07-09 22:25:29.927 670 918 E AmStub : at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
1098 07-09 22:25:29.927 670 918 E AmStub : at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
1099 07-09 22:25:29.927 670 918 E AmStub : … 24 more
1100 07-09 22:25:29.934 670 918 I ActivityManager: START u0 {flg=0x10000000 cmp=xx.oo/xx.oo.MyActivity (has extras) contextId=2722, taskId=2306 } from pid 23461