Angry Birds安装后,运行后提示:Unfortunately, Angry Birds has stopped. 虽然没做过android开发,但我还是先尝试做一下android下的调试,为以后打打基础。
1、查log信息:
Android下查看log使用logcat工具(参考http://fins.iteye.com/blog/141021)。
logcat输出:
E/AndroidRuntime( 2443): FATAL EXCEPTION: main
E/AndroidRuntime( 2443): java.lang.UnsatisfiedLinkError: Couldn't load angrybirds: findLibrary returned null
E/AndroidRuntime( 2443): at java.lang.Runtime.loadLibrary(Runtime.java:365)
E/AndroidRuntime( 2443): at java.lang.System.loadLibrary(System.java:535)
E/AndroidRuntime( 2443): at com.rovio.ka3d.App.onCreate(App.java:29)
E/AndroidRuntime( 2443): at android.app.Activity.performCreate(Activity.java:4465)
E/AndroidRuntime( 2443): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
E/AndroidRuntime( 2443): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1919)
E/AndroidRuntime( 2443): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1980)
E/AndroidRuntime( 2443): at android.app.ActivityThread.access$600(ActivityThread.java:122)
E/AndroidRuntime( 2443): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1146)
E/AndroidRuntime( 2443): at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2443): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime( 2443): at android.app.ActivityThread.main(ActivityThread.java:4340)
E/AndroidRuntime( 2443): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2443): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime( 2443): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
E/AndroidRuntime( 2443): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
E/AndroidRuntime( 2443): at dalvik.system.NativeStart.main(Native Method)
可以看出系统在加载一个库文件时出现错误:Couldn't load angrybirds,这里我想应该是俩个意思:1、这个库不存在;2、库的格式不对。最初我是按第一个意思理解,而且没看出库的名字是什么,现在看来应该是libangrybirds.so。既然不知道程序加载哪个库文件,那就想办法跟踪系统调用。
2、跟踪系统调用
linux下跟踪系统调用可以使用strace,android下也有相应的工具,我的sdk已经自带了strace,省去的编译的麻烦。但strace要在命令行下执行,因此需要找到手动启动应用的方法。
3、手动启动程序
搜索了一下google,android手动启动应用要使用am工具,参考http://tech.it168.com/a2009/0529/579/000000579028.shtml。
am的简单用法是:am start PackageName/ActivityName。PackageName和ActivityName在AndroidManifest.xml中定义,因此解压apk包,找到angry birds的AndroidManifest.xml,但这个xml居然是个二进制文件,应该是加扰过的,需要反编译。
4、反编译
参考http://lytsing.org/wiki/android/decompile.html,我下载了里面的AXMLPrinter2.jar,在pc上执行java -jar AXMLPrinter2.jar AndroidManifest.xml > AndroidManifest2.xml,得到xml的源码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="2110"
android:versionName="2.1.1"
android:installLocation="0"
package="com.rovio.angrybirds"
>
<application
android:label="@7F030001"
android:icon="@7F020000"
android:debuggable="false"
>
<activity
android:theme="@android:01030007"
android:name="com.rovio.ka3d.App"
android:launchMode="2"
android:screenOrientation="0"
android:configChanges="0x000004A0"
>
<intent-filter
>
<action
android:name="android.intent.action.MAIN"
>
</action>
<category
android:name="android.intent.category.LAUNCHER"
>
</category>
</intent-filter>
</activity>
<activity
android:theme="@android:01030007"
android:name="com.burstly.lib.component.networkcomponent.burstly.VideoPlayerActivity"
android:configChanges="0x000000B0"
>
</activity>
<activity
android:theme="@android:01030007"
android:name="com.burstly.lib.component.networkcomponent.burstly.BurstlyFullscreenActivity"
android:configChanges="0x000000B0"
>
</activity>
<activity
android:name="com.google.ads.AdActivity"
android:configChanges="0x00000FB0"
>
</activity>
<provider
android:name="com.greystripe.android.sdk.AdContentProvider"
android:exported="false"
android:multiprocess="true"
android:authorities="com.rovio.ka3d.AdContentProvider"
>
</provider>
<activity
android:name="com.greystripe.android.sdk.AdView"
android:configChanges="0x000000B0"
>
<intent-filter
>
<category
android:name="android.intent.category.LAUNCHER"
>
</category>
</intent-filter>
</activity>
<activity
android:name="com.millennialmedia.android.MMAdViewOverlayActivity"
>
</activity>
<activity
android:theme="@android:01030007"
android:name="com.millennialmedia.android.VideoPlayer"
android:configChanges="0x000000B0"
>
</activity>
<supports-screens
android:anyDensity="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
>
</supports-screens>
<activity
android:theme="@android:01030007"
android:name="com.burstly.lib.component.networkcomponent.jumptap.JumptapActivity"
android:configChanges="0x000000B0"
>
</activity>
</application>
<uses-permission
android:name="android.permission.INTERNET"
>
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE"
>
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
>
</uses-permission>
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"
>
</uses-permission>
<uses-permission
android:name="android.permission.READ_PHONE_STATE"
>
</uses-permission>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
>
</uses-permission>
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="13"
>
</uses-sdk>
</manifest>
可以看出其PackageName和ActivityName分别为:com.rovio.angrybirds和com.rovio.ka3d.App。
5、继续strace追踪
使用am执行:am start com.rovio.angrybirds/com.rovio.ka3d.App,可以看到触摸屏上出现同样的提示:Unfortunately, Angry Birds has stopped. 于是加上strace执行:strace am start com.rovio.angrybirds/com.rovio.ka3d.App,却提示:
execve("/system/bin/am", ["am", "start com.rovio.angrybirds/com."...], [/* 20 vars */]) = -1 ENOEXEC (Exec format error)
write(2, "strace: exec", 12strace: exec) = 12
write(2, ": ", 2: ) = 2
write(2, "Exec format error", 17Exec format error) = 17
write(2, "\n", 1
) = 1
exit_group(1) = ?
strace不能启动am。继续查了一下am,发现am其实是个脚本:
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/am.jar
exec app_process $base/bin com.android.commands.am.Am "$@"
那么,直接修改exec为exec strace -f(-f为追踪fork的子进程)。于是,strace成功输出系统调用过程。
6、strace分析
一般来说,如果是动态库不存在,系统会返回ENOENT错误,但查找了strace的所有输出,没发现哪个so存在ENOENT的错误返回,甚至没找到跟angry birds有关的so调用,我想可能是strace在追踪android应用时,对虚拟机的调用捕获的不完整。但其中有一个打开logging.properties的ENOENT的错误,很值得注意。
7、logging.properties
这个文件是jdk的日志配置文件(参考http://qingzuochen.iteye.com/blog/616151)。按照文章中的配置,程序执行后确实在/目录下生成的SSLog0.log,可惜内容是空的,没写入任何log信息。
8、最终答案:ARM与MIPS
也许经验丰富的人早就看出问题的所在了,我的板子是个MIPS的方案,而android现在只提供了arm的编译器,软件商也只提供了基于arm的jni本地版本,所以网上下载的大多数游戏在我的MIPS CPU上不能运行是再正常不过的事情了,而我却绕了这么大一个圈子,最后看到apk下的so是放在arm文件夹下,才想起这个事情,这也算是初入android平台的教训吧。好消息在这儿:http://mobile.youkuaiyun.com/a/20120417/2804671.html