当前位置: 代码迷 >> Android >> Android Platform 3.0 SDK跟Eclipse ADT安装记录二
  详细解决方案

Android Platform 3.0 SDK跟Eclipse ADT安装记录二

热度:101   发布时间:2016-05-01 19:09:58.0
Android Platform 3.0 SDK和Eclipse ADT安装记录二

Android Platform 3.0 SDK和Eclipse ADT安装记录二

?

(20120308补注)

注:从NDK r7开始引入了新的命令文件ndk-build.cmd,可以实现无cygwin的编译。使用它可以免除在Windows下手工写bat。但只适用于标准的JNI工程,如果要编译纯elf文件(main入口)仍然需要手工写Makefile或bat。下文中大多数都是基于NDK r5b的,可能已经过时,请留意。

?

(20120401补注)

注:从CDT Indigo SR2开始,CDT支持交叉编译的配置,下文中提到的CDT最初是基于旧版本的CDT?Galileo,相对会麻烦很多,而且不容易配置出正确的高亮着色和定义跳转。至于gdb的配置和使用是差不多的。请注意。另外,旧版本CDT可以使用GNU ARM的Ecllipse插件来简化配置操作。

?

目录:

一、简单地编写JNI及测试

二、ndk-gdb的使用

三、在CDT上看NDK工程(最好使用CDT Indigo SR2部署工程,见第十五节

四、创建普通Android原生程序(main入口)

五、如何使用jdb调试android的java程序

六、利用Android NDK的Import Module功能导入C++的标准库(gnu-libstdc++)

七、main入口的c++程序编写(测试用)

八、依赖库问题

九、用Flash Builder 3.5开发Android的Air应用程序(模拟器上运行)

十、apk逆向工程

十一、adb使用摘要

十二、Android数据共享手段

十三、在App中运行原生可执行文件(elf格式)

十四、ListView的一些问题。

十五、用CDT?Indigo SR2创建main入口c工程

十六、Error generating final archive: Debug Certificate expired on ...的错误(转)

十七、刷新avd列表(重启adb服务器)

十八、查看内存占用量(检查内存泄露)

?

----------------

?

一、简单地编写JNI及测试:

?

(注:更快的方法是使用Ant和Eclipse,

见官网的介绍

http://developer.android.com/sdk/ndk/overview.html

?

首先用

>?..\..\ndk-build.cmd

生成libs\armeabi下的.so文件

然后原地创建Eclipse工程

?

In Eclipse:
Click File > New Android Project...
Select the Create project from existing source radio button.
Select any API level above Android 1.5.
In the Location field, click Browse... and select the <ndk-root>/samples/hello-jni directory.
Click Finish.

在创建Android工程的向导中有三项,第二项是从现存代码中创建(注意,必须按Browse按钮

ADT会自动生成原来没有的许多工程文件。

不建议使用以下方法,因为从头再做一遍太麻烦了,而且容易出错!!!

?

1. 用bat文件设置JDK、Android SDK、ANT的路径,双击启动控制台。

?

@set PATH="C:\WINDOWS"  @set PATH="C:\WINDOWS\system32";%PATH%  @set PATH="D:\java\apache-ant-1.8.1\bin";%PATH%    @set JAVA_HOME="D:\java\jdk1.6.0_20"  @set PATH="D:\java\jdk1.6.0_20\bin";%PATH%    @set PATH="D:\java\android-sdk_r10-windows\android-sdk-windows\platform-tools";%PATH%  @set PATH="D:\java\android-sdk_r10-windows\android-sdk-windows\tools";%PATH%  @cd /D "D:\java\android-sdk_r10-windows\android-sdk-windows\work"  @cmd ?

?

?

2. 创建工程,并且测试(假设AVD的名称为add2)

?


> android create project --target 1 --name MyJNI --path ./MyJNI --activity MyJNIActivity --package com.example.myjni
> cd myjni
> ant
> ant debug
> android
(添加或检查已有AVD)
> start emualator -avd add2
> start adb logcat
(Ctrl+C退出)
> ant install
> adb shell pm list packages | find "myjni"
(看到package:com.example.myjni)
(打开模拟器,打开主菜单,选择MyJNIActivity,看到有一行文字
Hello World, MyJNIActivity

> ant uninstall
(关闭模拟器)
?

?

3. 加入JNI类,放入src\com\example\myjni目录中

?

?

package com.example.myjni;public class MyJNI {	public static native int mycall(int x);} 
?

然后执行ant compile编译

?

4. 生成头文件,这里需要指定原生类class文件的根目录以及完整类名。

> javah -jni -classpath ./bin/classes -d jni com.example.myjni.MyJNI

输出文件为jni\com_example_myjni_MyJNI.h,内容如下:

?

?

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_myjni_MyJNI */#ifndef _Included_com_example_myjni_MyJNI#define _Included_com_example_myjni_MyJNI#ifdef __cplusplusextern "C" {#endif/* * Class:     com_example_myjni_MyJNI * Method:    mycall * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_example_myjni_MyJNI_mycall  (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif
?

由于使用JNIEXPORT进行导出,

所以在编译.so文件时编译器会检查此函数是否被实现。

(如果编译器看到这个头文件的内容)

?

5. 实现JNI接口。

创建jni目录。

创建一个.c文件,内容如下:

?

?

#include "com_example_myjni_MyJNI.h"#include <stdio.h>jint JNICALLJava_com_example_myjni_MyJNI_mycall(JNIEnv *env, jclass cl, jint x){	printf("hello, JNI, %d", x);	return x + 1;}
?

6. 编译JNI的.so文件(需要下载NDK,使用其中的工具链命令行,这里尽量用命令行)

方便起见,我没有使用官方提供的ndk-build,而是直接使用工具链命令行(可能有问题)。

?

(请尽量使用ndk-build和ndk-build.cmd,以节约时间和保证生成.so的正确性,以下步骤只是因为NDK r7之前还没有出现ndk-build.cmd工具

?

> mkdir libs
> mkdir libs\armeabi
> C:/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gcc.exe --sysroot="C:/cygwin/home/Administrator/android-ndk-r5b" -I"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/include" -L"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/lib" -o libs\armeabi\libMyJNI.so -shared jni/MyJNI.c

?

注意:上面的--sysroot应该是写错了,应该是类似这样才对

--sysroot=“C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm”

见下面的Makefile。

?

输出文件名必须是lib前缀,.so后缀,而且必须输出到libs/armeabi目录下。

?

7. 在Activity中使用JNI,必须首先使用loadLibrary指定要加载的so文件名(不需要lib前缀和.so后缀)

?

?

package com.example.myjni;import android.app.Activity;import android.os.Bundle;public class MyJNIActivity extends Activity{    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        int result = MyJNI.mycall(0);        System.out.println("result is " + result);    }        static {        System.loadLibrary("MyJNI");    }}
?

8. 重新编译和打包apk

> ant clean debug

然后用7zip打开bin\MyJNI-debug.apk,查看libs\armeabi\libMyJNI.so是否被打包

?

9. 在模拟器内测试(方法同2),adb logcat的输出如下:

?

?

com.android.launcher2.Launcher }
D/dalvikvm( 117): GC_EXPLICIT freed 2501 objects / 136776 bytes in 251ms
W/InputManagerService( 58): Ignoring hideSoftInput of: com.android.internal.vi
[email protected]
I/ActivityManager( 58): Starting activity: Intent { act=android.intent.action.
MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.myjni
/.MyJNIActivity }
I/ActivityManager( 58): Start proc com.example.myjni for activity com.example.
myjni/.MyJNIActivity: pid=262 uid=10037 gids={1015}
D/dalvikvm( 262): Trying to load lib /data/data/com.example.myjni/lib/libMyJNI.
so 0x44ede258
D/dalvikvm( 262): Added shared lib /data/data/com.example.myjni/lib/libMyJNI.so
0x44ede258
D/dalvikvm( 262): No JNI_OnLoad found in /data/data/com.example.myjni/lib/libMy
JNI.so 0x44ede258, skipping init
I/System.out( 262): result is 1
I/ActivityManager( 58): Displayed activity com.example.myjni/.MyJNIActivity: 2
033 ms (total 2033 ms)
D/dalvikvm( 119): GC_EXPLICIT freed 1177 objects / 85560 bytes in 95ms
D/dalvikvm( 171): GC_EXPLICIT freed 2990 objects / 179416 bytes in 105ms
D/dalvikvm( 195): GC_EXPLICIT freed 3071 objects / 178608 bytes in 103ms

?

可以看到:

* dalvikvm加载libMyJNI.so成功,

* 发现JNI_OnLoad不存在,自动跳过。

* System.out输出1,证明执行了MyJNI.mycall。

* .c文件内的printf没有产生任何输出。(不解,可能是.so编译过程有问题)

* 按后退键,然后重新启动活动,执行MyJNI.mycall。

* 按Home键,然后重新启动活动,不执行MyJNI.mycall。

?

10. 更多信息请参考官方的介绍或其它资料:

* http://developer.android.com/guide/practices/design/jni.html

* http://stackoverflow.com/questions/5123564/use-ant-build-xml-to-compile-jni-directory

* Android NDK的文档和示例。

?

----------------

20111025:

?

二、ndk-gdb的使用:(这里用官方提供的原生活动例子,所以需要Level 10的模拟器)

?

修改AndroidManifest.xml,添加可调试标签:

android:debuggable="true"

?

?

<?xml version="1.0" encoding="utf-8"?><!-- BEGIN_INCLUDE(manifest) --><manifest xmlns:android="http://schemas.android.com/apk/res/android"        package="com.example.native_activity"        android:versionCode="1"        android:versionName="1.0">    <!-- This is the platform API where NativeActivity was introduced. -->    <uses-sdk android:minSdkVersion="10" />    <!-- This .apk has no Java code itself, so set hasCode to false. -->    <application android:label="@string/app_name" android:hasCode="false" 		android:debuggable="true">        <!-- Our activity is the built-in NativeActivity framework class.             This will take care of integrating with our NDK code. -->        <activity android:name="android.app.NativeActivity"                android:label="@string/app_name"                android:configChanges="orientation|keyboardHidden">            <!-- Tell NativeActivity the name of or .so -->            <meta-data android:name="android.app.lib_name"                    android:value="native-activity" />            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest> <!-- END_INCLUDE(manifest) -->

?

然后必须重新编译JNI工程(使用ndk-build clean all)和Android工程(使用ant clean debug)

如果缺少一个,都无法使用ndk-gdb调试

(官方NDK文档说可以在编译时使用

$NDK/ndk-build NDK_DEBUG=1

就不需要修改AndroidManifest.xml文件了

?

?

启动模拟器

> start emulator -avd <AVD名称>

?

启动ndk-gdb并启动程序(程序未启动)

?

?

$ ../../ndk-gdb --adb=/cygdrive/D/java/android-sdk_r10-windows/android-sdk-windows/platform-tools/adb.exe --start
?

或,启动ndk-gdb并依附到程序(程序已启动)

?

?

$ ../../ndk-gdb --adb=/cygdrive/D/java/android-sdk_r10-windows/android-sdk-windows/platform-tools/adb.exe
?

启动会话后ndk-gdb会自动暂停程序,出现>提示符,输入

> l

查看主文件的内容(或直接用编辑器查看)

以选择合适的断点行号或函数名,然后用

> b <断点地址,行号或函数名>

添加断点,

然后输入

> c

继续执行程序。

当断点命中时,可以用

> bt

查看回溯堆栈信息,

或使用其它gdb指令查看当前的变量值。

?

?

-----------------------------

三、在CDT上看NDK工程:最好使用CDT Indigo SR2部署工程,见第十五节??)

?

?

1. 安装JRE(或JDK)以及CDT

JDK :?

http://www.oracle.com/technetwork/java/javase/downloads/index.html

Eclipse IDE for C/C++ Developers :

http://www.eclipse.org/downloads/

2. 创建C Makefile工程

File->New->Project...->C/C++->C Project

->(cancel) Use default location :?

不带空格,而且是新的子目录(需要自己添加)

->Makefile proejct->Empty->Cross GCC

3. 把工程的文本编码修改为UTF-8

Project->Properties->

Resource->Text file encoding->Other:?

-> UTF-8

4. 取消cygwin构建工具的本地化(避免中文乱码)

Project->Properties->

C/C++ Build->Environment->Add... :?

-> Name:LANG, Value:en_US.UTF-8

-> Name:PATH, Value:C:\cygwin\bin

(默认不会覆盖原有的环境变量,而是尾加,

所以需要按Edit把C:\cygwin\bin放到PATH的最前面,

避免编译时PATH查找到别的目录中)

5. 修改构建工具

Project->Properties->

C/C++ Build->Builder Settings

-> (cancel) Use default build command

-> Build command: bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build

(根据实际路径设置ndk-build的cygdrive绝对路径)

6. 修改头文件自动检测命令

Project->Properties->

C/C++ Build->Discovery Options

-> Compiler invocation command

-> C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gcc.exe

根据NDK工具链的实际位置进行修改。

重启CDT后,Project Explorer会出现Includes目录。

多次修改可能无法生效(CDT的自动检测有问题?)

由于检测数据放在<workspace>\.metadata\.plugins\org.eclipse.cdt.make.core目录下

如果要修改这个设置,可以删除此目录,

然后重启CDT,强制使其重新执行检测命令,

扫描新的头文件目录。

7. 测试make

Project->Clean...

输出内容如下:

bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build clean?

cygwin warning:

? MS-DOS style path detected: D:\ugame_c\native_activity

? Preferred POSIX equivalent is: /cygdrive/d/ugame_c/native_activity

? CYGWIN environment variable option "nodosfilewarning" turns off this warning.

? Consult the user's guide for more details about POSIX paths:

? ? http://cygwin.com/cygwin-ug-net/using.html#using-pathnames

/cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/build/core/build-local.mk:85: *** Android NDK: Aborting ? ?. ?Stop.

Android NDK: Could not find application project directory ! ? ?

Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. ? ?

说明ndk-build运行正常(因为目录中没有包含AndroidManifest.xml和JNI源代码)

8. 加入代码

复制示例代码

<NDK目录>/samples/native-activity

到Eclipse的工程树下

然后重新执行Project->Clean...

进行编译,输出如下:

?

?

**** Clean-only build of configuration Default for project native_activity ****

bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build clean
cygwin warning:
MS-DOS style path detected: D:\ugame_c\native_activity
Preferred POSIX equivalent is: /cygdrive/d/ugame_c/native_activity
CYGWIN environment variable option "nodosfilewarning" turns off this warning.
Consult the user's guide for more details about POSIX paths:
http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
Compile thumb : native-activity <= main.c
Compile thumb : android_native_app_glue <= android_native_app_glue.c
StaticLibrary : libandroid_native_app_glue.a
SharedLibrary : libnative-activity.so
Install : libnative-activity.so => libs/armeabi/libnative-activity.so

**** Build Finished ****

?

?

9. 纠正代码错误提示的问题

由于CDT的错误提示不依赖于编译过程(即编译通过,编辑器仍会显示错误)

需要手动指定NDK工具链的头文件目录:

Project->Properties->

C/C++ Build->Paths and Symbols->Includes->GNU C->Add...

-> C:\cygwin\home\Administrator\android-ndk-r5b\platforms\android-9\arch-arm\usr\include

-> C:\cygwin\home\Administrator\android-ndk-r5b\sources\android\native_app_glue

(需要根据实际目录添加)

确定后CDT会自动刷新工程,重新检查错误。

?

-------------------

?

?

?

四、创建普通Android原生程序(main入口):

?

方法类似上面创建原生活动的方法,不同的是:

1. Make命令改为

bash -c /cygdrive/C/cygwin/bin/make

2. 创建源文件文件

File->New->Source File

->Source file : hello.c

编辑内容如下:

?

?

#include <stdio.h>int main(int argc, char **argv) {	printf("Hello, world!\n");	return 0;}
?

3. 创建Makefile

File->New->Other->General->File

->File name: Makefile

编辑内容如下:(绝对路径根据实际修改)

?

?

NDK_HOME := C:/cygwin/home/Administrator/android-ndk-r5bCC := /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gccCC += --sysroot=$(NDK_HOME)/platforms/android-9/arch-armRM := rm -rfCFLAGS := -gCFLAGS += -I $(NDK_HOME)/platforms/android-9/arch-arm/usr/includeLIBS := -lmTARGET := helloOBJS := hello.oall : $(TARGET)$(TARGET) : $(OBJS)	$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)%.o : %.c	$(CC) $(CFLAGS) -o $@ -c $<	clean :	$(RM) $(OBJS) $(TARGET)
?

4. 重新编译

然后按Project->Clean...重新编译,左面工程树出现Binaries和Includes节点。

5. 上传到模拟器并测试

启动emulator后,

> adb shell

# mkdir /data/hellowolrd

# exit

(创建可写目录)

> adb push hello /data/helloworld

(把刚才编译的文件上传至模拟器)

> adb shell

# cd /data/helloworld

# ls

# chmod 744 hello

# ./hello

Hello, world!

# exit

6. 远程调试

gdbserver的用法如下:

# gdbserver --help

gdbserver --help

Usage: ?gdbserver COMM PROG [ARGS ...]

? ? ? ? gdbserver COMM --attach PID [--close-fd FD]

?

COMM may either be a tty device (for serial debugging), or

HOST:PORT to listen for a TCP connection.

?

Exiting

如果要执行远程调试,可以

> start adb shell?

# cd /data/helloworld

# gdbserver :5039 ./hello

gdbserver :5039 ./hello

Process ./hello created; pid = 293

Listening on port 5039

(此时gdbserver未被连接,所以被阻塞)

然后重定向端口(详细见gdb help)

? adb forward <local> <remote> - forward socket connections

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?forward specs are one of:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?tcp:<port>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localabstract:<unix domain socket name>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localreserved:<unix domain socket name>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localfilesystem:<unix domain socket name>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dev:<character device name>

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jdwp:<process pid> (remote only)

方法如下:

> adb forward tcp:5039 tcp:5039

这样模拟器的监听的模拟器端口5039,被重定向到宿主机的端口5039(只需要做一次)

然后启动本地的gdb

> C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe

进入gdb后

(gdb) file hello

(加载elf文件的调试信息)

(gdb) target remote localhost:5039

(连接到本机的5039端口)

(gdb) b main

(下断点)

(gdb) c

(继续)

Continuing.

Error while mapping shared library sections:

/system/bin/linker: No such file or directory.

Error while mapping shared library sections:

libc.so: No error.

Error while mapping shared library sections:

libm.so: No error.

?

Breakpoint 1, main (argc=1, argv=0xbe9c5cd4) at hello.c:4

4 ? ? ? ? ? ? ? printf("Hello, world!\n");

(断点命中,用其它gdb指令调试)

(gdb) printf "%s\n", argv[0]

./hello

(输出argv[0]的字符串值,当前为./hello)

(gdb) bt

#0 ?main (argc=1, argv=0xbe9c5cd4) at hello.c:4

(回溯堆栈)

(gdb) n

(步进,gdbserver的控制台出现如下输出:

gdb: Unable to get location for thread creation breakpoint: requested event is n

ot supported

Hello, world!

7. 在CDT中执行gdb

原理和上面用命令行调试一样,但断点的触发不能关联到编辑器(未解决)

设置方法是

启动gdbserver后

打开CDT的Run->Debug Configurations->双击新建C/C++ Attach to Application->Debugger

-> Debugger : gdbserver

-> Main -> GDB debugger : C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe

-> Connection -> Port Number : 5039

(设置好gdb绝对路径和端口号,按Apply和Debug)

Console视图会出现gdb的控制台(看右上角按钮Display Selected Console),可以输入相应的gdb命令。

不同于控制台调试,

1) gdb命令没有(gdb)提示符

2) gdb命令用绿色高亮显示

由于CDT的原因,断点触发时无法自动打开源文件。

?

---------------------------

?

?

五、如何使用jdb调试android的java程序

http://blog.csdn.net/dlmu2001/article/details/6946830

(未测试)

?

?

?

---------------------------

?

六、利用Android NDK的Import Module功能导入C++的标准库(gnu-libstdc++)

?

默认NDK不支持C++标准库,但提供Import Module功能

支持外挂的第三方移植库,

例如samples\native-activity就是在Android.mk中使用

LOCAL_STATIC_LIBRARIES := android_native_app_glue

$(call import-module,android/native_app_glue)

导入

$(NDK)/sources/android/native_app_glue

的第三方库

所以,可以用相同的方法导入

$(NDK)/sources/cxx-stl/gnu-libstdc++

?

例如:

?

# Copyright (C) 2009 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##      http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := libgl2jniLOCAL_CFLAGS    := -WerrorLOCAL_SRC_FILES := gl_code.cpp LOCAL_LDLIBS    := -llog -lGLESv2LOCAL_STATIC_LIBRARIES := gnustl_static# see http://stackoverflow.com/questions/7209971/ndk-build-undefined-reference-to-errors-when-statically-linking-to-libxml-a# 避免以下错误:# undefined reference to `std::__throw_bad_alloc()'LOCAL_ALLOW_UNDEFINED_SYMBOLS := trueinclude $(BUILD_SHARED_LIBRARY)$(call import-module,cxx-stl/gnu-libstdc++)

?

其中?

?

$(call import-module,cxx-stl/gnu-libstdc++)

表示导入

$(NDK)/sources/cxx-stl/gnu-libstdc++

的头文件和库文件

?

LOCAL_STATIC_LIBRARIES := gnustl_static

?

表示导入的模块名(必需)

模块名定义在

$(NDK)/sources/cxx-stl/gnu-libstdc++/Android.mk

中:

?

?

LOCAL_MODULE := gnustl_static

?

如果出现undefined reference to `std::__throw_bad_alloc()'错误

需要添加以下标志:

?

?

LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

?

?

参见

http://stackoverflow.com/questions/7209971/ndk-build-undefined-reference-to-errors-when-statically-linking-to-libxml-a

?

--------------------------

?

七、main入口的c++程序编写(测试用)

?

假设有一个C++代码文件:

?

?

#include <iostream>using namespace std;int main(int argc, char *argv[]){	cout << "Hello, world!" << endl;	return 0;}

?

编译用bat

?

?

C:/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-g++ --sysroot=C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm -L"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi" -L"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/lib" -I"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/include" -I"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/include" -I"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include" hello.cpp -lc -lm -lstdc++ -o hello_cpppause
?

上传和chmod 744的做法与前面关于c的hello,world程序编译步骤相同。

?

?

我测试过C++标准库中的vector,map,iostream和异常,代码如下(内附输出内容):

?

?

/*adb push hello_cpp /data/wmt*/#include <iostream>#include <vector>#include <map>using namespace std;int main(int argc, char *argv[]){	cout << "Hello, world!" << endl;	vector<int> V;	V.insert(V.begin(), 3);	V[0] = 4;	V[1] = 5; //越界 out of range		cout << "size:" << V.size() << ",capacity:" << V.capacity() << endl;	V.reserve(3);	cout << "size:" << V.size() << ",capacity:" << V.capacity() << endl;	cout << "V[0]:" << V[0] << endl;	cout << "V[1]:" << V[1] << endl;		map<const char*, int> months;		months["january"] = 31;	months["february"] = 28;	months["march"] = 31;	months["april"] = 30;	months["may"] = 31;	months["june"] = 30;	months["july"] = 31;	months["august"] = 31;	months["september"] = 30;	months["october"] = 31;	months["november"] = 30;	months["december"] = 31;	cout << "june -> " << months["june"] << endl;		try	{		throw "hello, exception!";	} 	catch (const char *&str) 	{		cout << str << endl;	}		return 0;}/*# chmod 744 hello_cpp && ./hello_cppchmod 744 hello_cpp && ./hello_cppHello, world!size:1,capacity:1size:1,capacity:3V[0]:4V[1]:0june -> 30hello, exception!*/
?

------------------------------------------------

八、依赖库问题:

?

E/AndroidRuntime(544): Caused by: java.lang.UnsatisfiedLinkError: Library XXX not found

这个错误有可能是因为它所依赖的动态库(.so)文件不存在,
不一定是因为它自身不存在(开发环境的libs/armeabi目录下)

查看导入导出表和依赖库的方法有:

(1) 用IDAPro查看导入导出表
用IDAPro打开,然后查看Import或Export视图(可以点击表格的标题栏排序名称)

(2) 用readelf或nm或objdump搜索.so的导出函数(用c++filt可以转换C++函数名)
$ arm-linux-androideabi-readelf -s libapplication.so ?| grep SDL_main
? ?335: 0000c3cd ? 820 FUNC ? ?GLOBAL DEFAULT ? ?7 SDL_main
$ arm-linux-androideabi-nm -D libapplication.so | grep SDL_main
0000c3cc T SDL_main
$ arm-linux-androideabi-objdump -T libapplication.so ?| grep SDL_main
0000c3cc g ? ?DF .text ?00000334 SDL_main

(3) 用readelf列出.so的依赖动态库
$ arm-linux-androideabi-readelf -d libapplication.so

Dynamic section at offset 0x3a200 contains 32 entries:
? Tag ? ? ? ?Type ? ? ? ? ? ? ? ? ? ? ? ? Name/Value
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libsdl.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libsdl_mixer.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libsdl_image.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libsdl_ttf.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libbz2.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libmad.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libtremor.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libc.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libstdc++.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libm.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libGLESv1_CM.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libdl.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [liblog.so]
?0x00000001 (NEEDED) ? ? ? ? ? ? ? ? ? ? Shared library: [libz.so]
?0x0000000e (SONAME) ? ? ? ? ? ? ? ? ? ? Library soname: [libapplication.so]
?0x00000010 (SYMBOLIC) ? ? ? ? ? ? ? ? ? 0x0
?0x00000019 (INIT_ARRAY) ? ? ? ? ? ? ? ? 0x3b134
?0x0000001b (INIT_ARRAYSZ) ? ? ? ? ? ? ? 8 (bytes)
?0x00000004 (HASH) ? ? ? ? ? ? ? ? ? ? ? 0xd4
?0x00000005 (STRTAB) ? ? ? ? ? ? ? ? ? ? 0x4910
?0x00000006 (SYMTAB) ? ? ? ? ? ? ? ? ? ? 0x15d0
?0x0000000a (STRSZ) ? ? ? ? ? ? ? ? ? ? ?25486 (bytes)
?0x0000000b (SYMENT) ? ? ? ? ? ? ? ? ? ? 16 (bytes)
?0x00000003 (PLTGOT) ? ? ? ? ? ? ? ? ? ? 0x3b320
?0x00000002 (PLTRELSZ) ? ? ? ? ? ? ? ? ? 984 (bytes)
?0x00000014 (PLTREL) ? ? ? ? ? ? ? ? ? ? REL
?0x00000017 (JMPREL) ? ? ? ? ? ? ? ? ? ? 0xb8f8
?0x00000011 (REL) ? ? ? ? ? ? ? ? ? ? ? ?0xaca0
?0x00000012 (RELSZ) ? ? ? ? ? ? ? ? ? ? ?3160 (bytes)
?0x00000013 (RELENT) ? ? ? ? ? ? ? ? ? ? 8 (bytes)
?0x6ffffffa (RELCOUNT) ? ? ? ? ? ? ? ? ? 383
?0x00000000 (NULL) ? ? ? ? ? ? ? ? ? ? ? 0x0


------------------------------------------------

?

九、用Flash Builder 3.5开发Android的Air应用程序(模拟器上运行)

* 安装Flash Builder 3.5,创建一个Flex Mobile Project

* 右键->Export...->Flash Builder->Release Build

* 创建签名C:\Test\Test.p12文件,然后导出Test.apk

* 用adb install Test.apk安装,结果安装失败

Failure [INSTALL_FAILED_INVALID_APK]

(可能因为导出的apk使用了armeabi的.so不能装在模拟器上)

* 确保当前avd已经使用了sdcard(可以用edit按钮修改,但会丢失所有模拟器数据)

如果没有sdcard,后面运行air程序时会失败(adb logcat提示无法创建目录)。

* 用emulator -avd启动这个avd

* 用adb install(或adb install -s)安装C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\emulator\Runtime.apk

* 在Flex工程目录中写个bat文件,用adt创建自己的apk(指定目标为apk-emulator)

?

set path=C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\bin;%path%cd bin-releasecall adt.bat -package -target apk-emulator -storetype pkcs12 -keystore C:\Test\Test.p12 ..\Test.apk Test-app.xml Test.swfcd ..pause

* 在模拟器内的settings中确保已经安装air(因为它不显示在启动器中)

* 用adb install重新安装生成的Test.apk

* 运行,成功

?

参考:

http://www.3amartstudio.com/blog/post/130.html

http://www.cnblogs.com/ginoz/archive/2011/01/26/1945074.html

http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-5d0f4f25128cc9cd0cb-7ffe.html

?

?

(20120527)

如果用真机调试,SDK中AIR运行时的安装包

C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\device\Runtime.apk

只包含armeabi-v7a的.so文件,可能需要自己替换成

C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\emulator\Runtime.apk

否则运行会出错。

?

------------------------------------------------

十、apk逆向工程 / android hack技术

?

(TODO)

参考:

http://chuancun.sakura.ne.jp/mt/mt-search.cgi?IncludeBlogs=2&search=source%20code

(链接失效)

?

如何用gdb找到Android so文件中的加密key

http://all-ipad.net/how-to-get-key-from-android-so-using-gdb/

?

?

-------------------------------------------------

十一、adb使用摘要

(2012/03/13)

?

摘自android-ui-utils的design-preview:

http://code.google.com/p/android-ui-utils/

?

1. 运行应用程序的某个Activity

$ adb shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n com.google.android.apps.proofer/.DesktopViewerActivity

?

2. 强制杀死应用程序

$ adb shell am force-stop com.google.android.apps.proofer

?

3. 卸载应用程序

$ adb uninstall com.google.android.apps.proofer

?

4. 安装apk到SD卡

$ adb install -r Proofer.apk

?

5. 重定向设备的监听端口到本机

$ adb forward tcp:<本地端口号如6800> tcp:<设备端口号如7800>

(Windows下测试)

> netstat -ano | find "6800"

> telnet localhost 6800

?

6. 搜索是否安装某个应用程序

$ adb shell pm list packages | grep com.google.android.apps.proofer


其它adb或android自带命令请参考:

http://en.androidwiki.com/wiki/ADB_Shell_Command_Reference

http://developer.android.com/guide/developing/tools/adb.html

?

?

十二、Android数据共享手段:

http://developer.android.com/resources/faq/framework.html

?

http://stackoverflow.com/questions/1636500/are-static-fields-in-activity-classes-guaranteed-to-outlive-a-create-destroy-cyc

?

http://stackoverflow.com/questions/2114312/android-persistent-state-with-global-variables-when-system-kills-activities

?

方法有(性能和适用的数据类型不一样,根据情况选择):

1.?Intent.putExtras()

2.?Preferences

3. 单例类getInstance()

?

?

class EvilSingleton{    private static EvilSingleton instance;    //put your data as non static variables here    public static EvilSingleton getInstance()    {        if(instance == null)            instance = new EvilSingleton();        return instance;    }}
?

4.?public static字段/方法

5.?Long键WeakReference对象值的HashMap,传递Long键给另一个活动

6. 文件

7. 内容提供者

8. SQLite DB

9. 覆盖Application类

?

?

public class MyApplication extends Application{    private String thing = null;    public String getThing(){        return thing;    }    public void setThing( String thing ){        this.thing = thing;    }}public class MyActivity extends Activity {    private MyApplication app;    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        app = ((MyApplication)getApplication());        String thing = app.getThing();    }}

?

十三、在App中运行原生可执行文件(elf格式)

?

Run native executable in Android App

http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App

https://github.com/gimite/android-native-exe-demo

?

十四、ListView的一些问题

?

(1) ListView滚动时右侧快速滑块的启用方法

http://www.maxhis.info/archives/541

?

?

myListView.setFastScrollEnabled(true);

?

(2) 记录和恢复ListView滚动的位置

http://yes2.me/archives/567

?

?

//列表滚动private OnScrollListener ScrollLis = new OnScrollListener() {	@Override	public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {	}	@Override	public void onScrollStateChanged(AbsListView view, int scrollState) {		if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){                	ListPos=list.getFirstVisiblePosition();  //ListPos记录当前可见的List顶端的一行的位置         	}	}};
?

?

setOnScrollListener(ScrollLis);list.setSelection(ListPos);

?

十五、WebView的问题:

?

(1) JavaScript内定时器被触碰的输入事件阻塞

?

方法一:在JavaScript内解决。

参考:

http://www.html5rocks.com/en/mobile/touch/

?

?

clock();setInterval(clock, 1000);var touches = []document.body.addEventListener('touchmove', function(event) {	event.preventDefault();   //关键在这一句	console.log("touchmove");	touches = event.touches;}, false);
?

上面的touches数组可以传递给clock(),作为拖动信息读取。

?

方法二:在Java内屏蔽ACTION_MOVE,不过js端无法得到touchmove事件信息。

?

?

setOnTouchListener(new OnTouchListener() {			@Override			public boolean onTouch(View v, MotionEvent event) {				if (event.getAction() == MotionEvent.ACTION_MOVE) {					return true;				}				return false;			}        });

?

?

?

十六、用CDT?Indigo SR2创建main入口c工程

?

配置步骤:

(0) CDT和NDK:

假设我的NDK目录是:

C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\

CDT使用

Eclipse CDT Indigo Service Release 2(SR2支持创建交叉编译工程)

(1) 创建工程

Project name: test

File->New->C Project->

Executable->Cross-Compile Project->

Cross GCC

(2) 创建工程向导

Tool command prefix:?

arm-linux-androideabi-

Tool command path:

C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin

(3) 字符集

右键工程(注:在Project Explorer视图中,下同)->Properties->Resource

Text file encoding

选择Other: UTF-8

(4) make命令目录

Properties->C/C++ Build->

取消勾选Use default build command

Build command:

填入:

C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\prebuilt\windows\bin\make?

(5) gcc参数设置

Properties->C/C++ Build->Settings->

Tool Settings->Cross GCC Compiler->Includes->

Include paths (-I)

添加:(带引号)

"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include"

Tool Settings->Cross GCC Linker->Libraries->

Libraries (-l)

添加:

log

Library search path (-L)

添加:(带引号)

"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/lib"

Tool Settings->Cross GCC Linker->Miscellaneous->

Linker flags

填入:(带引号)

--sysroot="C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm"

(6) 检查是否头文件目录正确:

按OK退出Properties后目录下的Includes节点出现三个目录:

C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include

C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.4.3/include

C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.4.3/include-fixed

(7) 添加测试源文件

工程右键->New->Source File

Source file:填hello.c

Template:选择Default C source template

hello.c的内容如下:

?

?

/* * hello.c * *  Created on: 2012-4-13 *      Author: Administrator */#include <stdio.h>#include <android/log.h>#define TAG "HelloWorld"int main(int argc, char **argv) {	printf("Hello, world!\n");	__android_log_print(ANDROID_LOG_INFO, TAG, "Hello, world!\n");	return 0;}
?

?

(8) 开始编译:

工程右键->Build Project

弹出Build Project对话框,编译结束后消失。

出现Binaries节点和Debug目录

makefile文件生成在Debug目录下。

因为是调试版,所以Binaries节点中的"test - [arm/le]"可以展开

(9) 重新编译:

如果修改hello.c,但不编译,CDT仍然可以检查.c文件中的错误,

但Debug目录下的输出文件不会被修改。

重新编译可以有两种方法:

方法一、同(8),相当于执行make all

方法二、

Window->Show Views->Others->Make Target

打开Make Target视图

切换到test/Debug节点,然后按右上角加号按钮,

添加:clean all

然后双击clean all节点即可重新编译,

gcc编译器警告和错误信息输出在Problems视图中。

而make输出信息在Console视图的CDT Build Console中

(见视图右上角倒数第2个下拉菜单)

我的输出信息是:

?

?

?

?写道

**** Build of configuration Debug for project test ****

C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\prebuilt\windows\bin\make clean all
rm -rf ./hello.o ./hello.d test
' '
'Building file: ../hello.c'
'Invoking: Cross GCC Compiler'
arm-linux-androideabi-gcc -I"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"hello.d" -MT"hello.d" -o "hello.o" "../hello.c"
'Finished building: ../hello.c'
' '
'Building target: test'
'Invoking: Cross GCC Linker'
arm-linux-androideabi-gcc -L"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/lib" --sysroot="C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm" -o "test" ./hello.o -llog
'Finished building target: test'
' '

**** Build Finished ****

?

?

(10) gdbserver运行:

关于adb forward,上传二进制文件,gdbserver的运行的方法同前,略。

?

?写道
(以下命令可能不正确)
> start emulator -avd add2
> adb forward tcp:5039 tcp:5039
> adb shell
# mkdir /data/hello
> adb push test /data/hello
> adb shell
# cd /data/hello
# chmod 777 test
# gdbserver :5039 ./test
?

?

(11) gdb调试配置

Run->Debug Configurations

双击C/C++ Attach to Application添加一个配置

Main标签页设置

C/C++ Application: Debug\test

Project: test

Debugger标签页:

Debugger:

选择:

gdbserver

Debugger Options的Main页

GDB debugger:

填入:

C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe

GDB command file:

填入:

gdbinit.txt

Debugger Options的connection页

Type: TCP

Host name or IP address: localhost

Port number: 5039

工程右键->New->File

创建gdbinit.txt文件,内容如下:

?

?

file Debug/testb main
?

?

然后按Debug连接gdbserver调试。

如果成功,Console视图可以直接输入gdb指令(会显示为绿色,同前,略)。

暂时没有办法在编辑器中加断点,也没有办法关联地打开源文件。


十六、Error generating final archive: Debug Certificate expired on ...的错误(转)

?

see

http://www.cnblogs.com/yyangblog/archive/2011/01/07/1929657.html

?

解决方法:

?

?

?写道
解决方法:
进入C:\Documents and Settings\Administrator\.android 删除路径下的debug.keystore及 ddms.cfg。
(不同环境下的目录可能略有不同,可在eclipse中查找此路径:Window->Preferences->Android->Build下 Default debug keystore)
然后重新导入即可。
?

?

?

?

(20120616)

十七、刷新avd列表(重启adb服务器)

> adb kill-server

> adb start-server

?

十八、查看内存占用量(检查内存泄露)

> ddms

选择一个进程,

然后按左上角show heap updates按钮(在Eclipse中则为DDMS切面Devices视图中的update heap按钮)

然后切换到右面的VM Heap,按Cause GC开始监控堆大小的改变(数值自动更新)

注意:如果是程序是多进程的,只显示其中一个进程的堆大小。其它进程要选择另一行。

?

?

(TODO)

?

?

?

  相关解决方案