Android源码编译与调试
2012.09
系统环境
ubuntu-11.10-desktop-i386
on
VMware Workstation 8.0.0 build-471780
on
WindowsXP
[64bit]
ubuntu-10.10-beta-desktop-amd64 [注:为了编译mtk提供的代码]
http://mirrors.163.com/ubuntu-releases/
on
V VMware Workstation 9.0
http://bbs.pcbeta.com/viewthread-1119365-1-1.html
on
window 7 64bit
默认安装后执行 sudo apt-get install xxxx 会出错,解决办法见以下链接:
http://hi.baidu.com/lozard/item/03b854f5a8630015e2e3bd0a
源码编译
软件环境
基本按照http://source.android.com/source/initializing.html,未设置ccache。
下载源码
http://source.android.com/source/downloading.html,版本:android-4.0.3_r1
下载3、4天的时间才最终完成。
编译
make –j4
出现错误,发现ubuntu-11.10默认安装的是gcc4.6,但编译android需要gcc4.4。重新安装gcc4.4后执行 make –j4,顺利完成编译。
2012-9-19 注:今天在同样环境下编译 android-4.1.1_r6.1,发现已经无法在32bit系统上编译
执行
emulator
出现错误,发现是由于之前安装了android sdk的缘故。
在 ~/.bashrc中将android sdk的路径从PATH中移除,同时增加:
export ANDROID_PRODUCT_OUT=/home/joeyyin/android_4.0.3_r1/out/target/product/generic
export ANDROID_PRODUCT_OUT_BIN=/home/joeyyin/android_4.0.3_r1/out/host/linux-x86/bin
export PATH=$ANDROID_PRODUCT_OUT:$ANDROID_PRODUCT_OUT_BIN:$PATH
编译生成的emulator等其他bin工具在/home/joeyyin/android_4.0.3_r1/out/host/linux-x86/bin目录。
System.img, userdata.img, ramdis.img在/home/joeyyin/android_4.0.3_r1/out/target/product/generic
其中
Ramdisk.img是emulator的文件系统。
System.img包括主要的包、库等文件。
Userdata.img包括了一些用户数据,emulator负责加载3个映像文件后,会把system.img,userdata.img分别加载到ramdisk文件系统的system和userdata目录下。
再执行emulator,模拟器顺利启动。
cd ~/android_4.0.3_r1/out/target/product/generic
emulator -system system.img -data userdata.img -ramdisk ramdisk.img
编译模块
android中的一个应用程序可以单独编译,编译后要重新生成system.img
在源码目录下执行
$ . build/envsetup.sh (.后面有空格)
就多出一些命令:
- croot: Changes directory to the top of the tree.
- m: Makes from the top of the tree.
- mm: Builds all of the modules in the current directory.
- mmm: Builds all of the modules in the supplied directories.
- cgrep: Greps on all local C/C++ files.
- jgrep: Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir: Go to the directory containing a file.
可以加—help查看用法
我们可以使用mmm来编译指定目录的模块,如编译联系人:
$ mmm packages/apps/Browsers/
编完之后生成两个文件:
out/target/product/generic/data/app/Browser.apk
out/target/product/generic/system/app/Browser.apk
可以使用
$ make snod
重新生成system.img,再运行模拟器
编译SDK
$make sdk
悲剧的出现以下错误:
解决:
查找alarmprovider模块,没有发现
搜索build目录下含alarmprovider的项目
去掉这两个文件中的PRODUCT_PACKAGES中alarmprovider。
网上也有关于这个问题的解答:
“Indeed there is no a module with name AlarmProvider in the source tree now.
To fix it, remove AlarmProvider from the product definition in the
following files:
./build/target/product/large_emu_hw.mk:25: AlarmProvider
./build/target/product/generic_no_telephony.mk:24: AlarmProvider “
$ make sdk
又先后出现和以上类似的针对’Sync’, ‘Updater’, ‘SyncProvider’,…
看了网上的信息,也可以使用 make PRODUCT-sdk-sdk进行编译
将generic_no_telephony.mk, large_emu_hw.mk恢复
$ make PRODUCT-sdk-sdk
半小时候顺利完成编译。
make SDK和make PRODUCT -sdk-sdk有何异同???
编译后生成的SDK存放在out/host/linux-x86/sdk/,此目录下有android-sdk_eng.joeyyin_linux- x86.zip和android-sdk_eng.joeyyin_linux-x86目录。android-sdk_eng.joeyyin_linux-x86就是 SDK目录
实际上,当用mmm命令编译模块时,一样会把SDK的输出文件清除,因此,最好把android-sdk_eng.joeyyin_linux-x86移出来
此后的应用开发,就在该SDK上进行,所以把在~/.bashrc中增加sdk tools/platform_tools到PATH中:
export ANDROID_SDK_HOME=/home/joeyyin/android_4.0.3_r1/out/host/linux-x86/sdk/android-sdk_eng.joeyyin_linux-x86
export PATH=$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform_tools: $PATH
创建Android Virtual Device
编译出来的SDK是没有AVD(Android Virtual Device)的,我们可以通过android工具查看:
$ android list
创建AVD:
$ android create avd -t 1 -n myavd –s 320x480
可以android –help来查看上面命令选项的用法。创建中有一些选项,默认就行了
再执行android list,可以看到AVD存放的位置
以后每次运行emulator都要加-avd myavd或@myavd选项:
$ emulator -avd myavd
源码编译分析
首先需要理解makefile的编写规则
推荐一篇介绍文章http://www.cnblogs.com/dskit/archive/2010/02/09/1666771.html。
Makefile -> build/core/main.mk
Eclipse+adt
Eclipse 安装
下载eclipse from http://www.eclipse.org/downloads/?osType=linux
这个版本在后面编译安装adt时会有错误,建议下载下面的版本:
$ tar zxvf eclipse-jee-indigo-SR2-linux-gtk.tar.gz
$ tar zxvf eclipse-SDK-3.7.2-linux-gtk.tar.gz
$ sudo mv eclipse /opt
$ cd /opt
$ sudo chown -R root:root eclipse
$ sudo chmod -R +r eclipse
$ sudo touch /usr/bin/eclipse
$ sudo chmod 755 /usr/bin/eclipse
$ sudo vim /usr/bin/eclipse
文件内容如下:
#!/bin/sh #export MOZILLA_FIVE_HOME="/usr/lib/mozilla/" export ECLIPSE_HOME="/opt/eclipse"
$ECLIPSE_HOME/eclipse $* |
$ sudo vim /usr/share/applications/eclipse.desktop
文件内容如下:
[Desktop Entry] Encoding=UTF-8 Name=Eclipse Comment=Eclipse IDE Exec=eclipse Icon=/opt/eclipse/icon.xpm Terminal=false Type=Application Categories=GNOME;Application;Development; StartupNotify=true |
Start eclipse firsttime:
$ /opt/eclipse/eclipse -clean &
编译安装adt
$ cd ~/android_4.0.3_r1/out/host/linux-x86
$ mkdir adt
$ cd ~/android_4.0.3_r1/sdk/eclipse/scripts
$ export ECLIPSE_HOME=/opt/eclipse
$ ./build_server.sh ~/android_4.0.3_r1/out/host/linux-x86/adt
处理失败,出现很多类似以下依赖错误,据说要下载安装JavaEE版eclipse。
Missing required plug-in com.android.ide.eclipse.adt_0.0.0.
直接启动eclipse -> help ->install new software ->add -> https://dl-ssl.google.com/android/eclipse/
天煞的,这个地址居然无法连接【难道又被天朝封了?】
下载javaee版本eclipse安装后,重新编译adt成功。
运行eclipse
$ eclipse
help ->install new software ->add -> 选择archive,刚刚编译生成adt zip包
安装完成后重启eclipse, 配置sdk信息
悲剧的是这个编译会删除之前编译的sdk,所以这一步最好在make sdk之前做。
创建应用
Helloandroid:
http://developer.android.com/resources/tutorials/hello-world.html
导入android源码到eclipse
1、将 源码目录\development\ide\eclipse 中的.classpath复制到源码根目录下。
$ cd ~/android_4.0.3_r1
$ cp /home/joeyyin/android_4.0.3_r1/development/ide/eclipse/.classpath .
$ chmod u+w .classpath
2、更改eclipse缓存设置
在eclipse安装根目录下修改eclipse.ini
-Xms128m
-Xmx512m
-XX:MaxPermSize=256m
3、将 源码目录\development\ide\eclipse 中的android-formatting.xml和android.importorder导入eclipse
android-formatting.xml用来配置eclipse编辑器的代码风格;android.importorder用来配置eclipse的import的顺序和结构。
window->preferences->java->Code style->Formatter中导入android-formatting.xml
window->preferences->java->Code style->Organize Imports中导入android.importorder。
4、导入源码
新建Java Project [非android project],指定一个name[android_4.0.3_r1],接着将use default location勾掉,指定到你源码的目录下[/home/joeyyin/android_4.0.3_r1],finish。
出现两个miss required library的错误。反正不在eclipse中编译,不管这个错误了。
Workspace中的其他project可设置android.jar attach到之前导入的android源码工程(android_4.0.3_r1)
Properties -> java build path ->libraries -> 设置android.jar的source attachment到workspace -> android_4.0.3._r1
[在windows下类似操作]
在eclipse中调试android系统应用/服务:
按以下说明,使用browser测试过,可以断点跟踪调试。
http://wenku.baidu.com/view/cbc4773410661ed9ad51f3e8.html
windows_eclipse下调试
- 导入android源码到windows环境下eclipse
- 将Linux下编译好的/home/joeyyin/android_4.0.3_r1/out/target/product/generic 目录下system.img、userdata.img、ramdisk.img复制到window->androidsdk对应版本的images中
- Debug http://wenku.baidu.com/view/cbc4773410661ed9ad51f3e8.html
使用GDB调试native code
调试webkit
1. 进入android系统源码根目录,然后执行
source build/envsetup.sh
2. 启动模拟器,并打开浏览器
Emulator –avd myavd
3. 在终端中执行
adb forward tcp:5039 tcp:5039
4. 打开另一个终端,执行
adb shell ps
找到 com.android.browser 进程号
5. 执行
adb shell gdbserver :5039 --attach pid
pid为 com.android.browser 进行号
正常反馈:
Attached; pid = ****
Listening on port 5039
6. 回到第一个终端,导出环境变量,adb, arm-eabi-gdb等的路径,在执行gdbclient报错时,可将相应的命令 的路径导出
export PATH=/home/joeyyin/android_4.0.3_r1/out/host/linux-x86/sdk/android-sdk_eng.joeyyin_linux-x86/platform-tools:$PATH
export PATH=/home/joeyyin/android_4.0.3_r1/prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin:$PATH
现在执行命令
gdb client
成功的话就会加载一系列的符号表。试了一下设置断点,成功地在代码中中断了下来。下面要做的就 是熟悉GDB调试命令了。
7. 在gdb中设置断点
b FrameLoaderClientAndroid.cpp:888
c ---- continue
8. 在模拟中用浏览器打开任一网页,就会进入断点了。
另有一简化方法:http://mogoweb.net/archives/309
源码结构
http://wenku.baidu.com/view/0816dc232f60ddccda38a04d.html
附录
Linux环境变量设置
http://www.360doc.com/content/11/1206/14/6828497_170097352.shtml
shell
/etc/passwd
查看当前系统中可用的shell
cat /etc/shells
查看当前使用的shell
echo $SHELL
检查用户(joeyyin)的默认shell
cat /etc/passwd | grep joeyyin
切换shell(到/bin/sh)
/bin/sh
退出
Exit
共享文件夹设置
http://www.net130.com/CMS/Pub/special/special_virtual/special_virtual_js/2010_04_12_92762.htm
预制APK到Android系统
http://blog.youkuaiyun.com/sergeycao/article/details/8198205
一、如何将带源码的APK预置进系统?
1) 在 packages/apps 下面以需要预置的 APK的 名字创建一个新文件夹,以预制一个名为Test的APK 为例
2) 将 Test APK的Source code 拷贝到 Test 文件夹下,删除 /bin 和 /gen 目录
3) 在 Test 目录下创建一个名为 Android.mk的文件,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Test
include $(BUILD_PACKAGE)
4) 打开文件 build/target/product/${Project}.mk (其中 ${Project} 表示工程名)
将 Test 添加到 PRODUCT_PACKAGES 里面。
5) 重新 build 整个工程
二、如何将无源码的 APK 预置进系统?
1) 在 packages/apps 下面以需要预置的 APK 名字创建文件夹,以预制一个名为Test的APK为例
2) 将 Test.apk 放到 packages/apps/Test 下面
3) 在 packages/apps/Test 下面创建文件 Android.mk,文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#PRESIGNED不再重新签名, platform使用系统签名
LOCAL_CERTIFICATE := PRESIGNED
include $(BUILD_PREBUILT)
4) 打开文件 build/target/product/${Project}.mk (其中 ${Project} 表示工程名)
将 Test 添加到 PRODUCT_PACKAGES 里面。
5) 将从Test.apk解压出来的 so库拷贝到alps/vendor/mediatek/${Project}/artifacts/out/target/product/${Project}/system/lib/目录下,若无 so 库,则去掉此步;
6) 重新 build 整个工程
三、如何预置APK使得用户可以卸载?
有两种方法:
方法一:
7) 在 packages/apps 下面以需要预置的 APK 名字创建文件夹,以 预制一个名为Test的APK为例
8) 将 Test.apk 放到 packages/apps/Test 下面;
9) 在 packages/apps/Test 下面创建文件 Android.mk,文件内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
include $(BUILD_PREBUILT)
10) 打开文件 build/target/product/${Project}.mk (其中 ${Project} 表示工程名)
将 Test 添加到 PRODUCT_PACKAGES 里面。
11) 将从Test.apk解压出来的 so库拷贝到alps/vendor/mediatek/${Project}/artifacts/out/target/product/${Project}/system/lib/目录下,若无 so 库,则去掉此步;
12) 重新 build 整个工程
注意:这个比不能卸载的多了一句
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
方法二:
4) 将需要预置的 apk 拷贝到:
vendor/mediatek/${Project}/artifacts/out/target/product/${Project}/data/app/
5) 重新 build 整个工程
注意:如果没有相应目录则需手动创建。
四、如何使得用户在将预置的 APK 卸载后,恢复出厂设置时能恢复?
为了让用户在将预置的 APK 卸载后,恢复出厂设置时能恢复,敝司做了一个 Feature,但在ALPS.GB.TDFD.MP.V1.7和 ALPS.GB.FDD2.MP.V4.7版本后支持,若贵司版本低于此版本,请申请 Patch ALPS00092543;
大致的做法是:
- 在vendor/mediatek/project_name/artifacts/out/target/product/project_name/system目录下新建一个名为appbackup的文件夹,将该应用的apk文件copy到appbackup文件夹下
- 在mediatek/config/project_name/ProjectConfig.mk文件中添加定义:MTK_SPECIAL_FACTORY_RESET=yes
-在vendor/mediatek/project_name/artifacts/out/target/product/project_name/data/app下创建一个.restore_list,并且在其中添加语句:
/system/appbackup/xxx.apk(注意,.restore_list中的每一行都要以"/system” 开头)
当卸载了data/app下的apk后,再恢复出厂设置,系统会从 .restore_list 中读取apk的名字,然后从 appbackup 文件中把apk重新拷贝到data/app下,从而恢复data/app下已经卸载了的apk。