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>
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成功输出系统调用过程。
一般来说,如果是动态库不存在,系统会返回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.csdn.net/a/20120417/2804671.html