标签:security 编译选项 unlock 开发人员 lex exec release launcher 驱动开发
Android的编译系统涉及面极广,包含编译工具、印像文件编译、SDK编译、NDK编译、目标系统配置等多个方面。尽管这些方面的内容烦琐而晦涩,能够參考的资料不多,可是系统设计尤其是系统架构人员必须熟悉它们。
1.源码编译
基于源码的方式进行开发,一般会依据目标环境的不同,对系统配置进行调整,如採用不同的引导器、特定的驱动、不同的文件系统、特定的属性配置等,这就要求开发人员必须熟练掌握源码的编译方法和配置。
(1)映像文件
在编译完源码后。须要将生成的文件等打包成对应的文件系统。然后烧写到移动终端。
在Android中,默认的文件系统为YAFFS2。当然OEM厂商能够依据自己的须要,选择其它的文件系统。
在源码中。YAFFS2文件系统的实现位于external\yaffs2\yaffs2文件夹下。它针对大容量的NAND flash进行了优化。具有挂载时间短等长处。在当前的智能终端中,还有一个比較经常使用的文件系统是UBIFS,它是由IBM和Nokia公司的project师于2006年开发的一款高效的嵌入式文件系统。
在external\yaffs2\yaffs2\utils文件夹下包括了mkyaffsimage和mkyaffs2image两种工具,前者用于生成YAFFS格式的映像文件。后者用于生成YAFFS2格式的映像文件。
生成YAFFS2格式的映像文件的方法例如以下:
#mkyaffs2image dir imagename
在启动系统时,通过init.rc脚本会将文件系统挂载到特定的文件夹,方法例如以下:
#mount mtd partitions //分区格式为MTD
#Mount /system rw first to give the filesystem a chance to save a checkpoint
mount yaffs2 mtd@system /system
mount yaffs2 mtd@system /system ro remount
mount yaffs2 mtd@userdata /data no suid nodev
mount yaffs2 mtd@cache /cache no suid nodev
须要说明的是,文件系统涉及的概念包含挂载点、映像文件、MTD分区名等。
Android系统基本的挂载点\system、\data、\cache、\sdcard等,映像格式默认支持yaffs2、ext4、vfat等。
在Android中,映像文件包含boot.img、ramdisk.img、system,img、userdata.img等。
依据硬件平台的不同。还有其它的映像文件。
映像文件的生成配置位于build\core\Makefile中。开发人员能够依据自己的须要,配置映像文件。在build\core\Makefile中,除了定义映像文件外,还涉及源码和SDK编译的配置等内容。
在编译完毕后,自然要启动模拟器,假设是商业开发。那么可能须要自己定义模拟器。在Linux编译环境中显式启动一个模拟器。须要创建一个脚本。
以下是一个演示样例:
#!/bin/sh
ANDROID_HOME=.
ANDROID_EMULATOR=$ANDROID_HOME/out/host/linux-x86/bin/emulator
ANDROID_SYSTEM=$ANDROID_HOME/out/target/product/generic/
ANDROID_KERNEL=$ANDROID_HOME/prebuilt/android-arm/kernel/kernel-qemu
ANDROID_SKIN=$ANDROID_HOME/sdk/emulator/skins
$ANDROID_EMULATOR -kernel $ANDROID_KERNEL -sysdir $ANDROID_SYSTEM -show-kernel -shell -data $ANDROID_SYSTEM/userdata.img \
-partition-size 128 -skindir $ANDROID_SKIN -skin CUSTOM1000 \ //自己定义模拟器
-sdcard $ANDROID_SYSTEM/sdcard.img -wipe-data
(2)编译方法
Android中的编译很easy。除了主要的全系统编译外,Android还提供了几种快捷方式供编译和查找使用。
1)编译环境
Android的版本号众多。随着时间的迁移,其编译环境也发生了一些变化,最大的变化是在Froyo版本号后,Android对Java的要求从Java 5提升到Java 6。同一时候对驻留的操作系统的要求从32位升级到64位。另外要求具备的Python2.4、Git 1.5.4或更高的版本号。
眼下。Android要求源码的编译在Linux或Mac OS下进行,推荐的操作系统为Ubuntu 10.04LTS(64位)或更高版本号。
以下以Ubuntu 10.04LTS为例介绍编译环境的搭建。
(1)获取Java
对于Gingerbread或更高的版本号,Android要求支持Java 6,採用Sun Java 6或者Open JDK 6均可。以下是安装sun-java6-jdk的过程:
#add-apt-repository "deb http://archive.canonical.com/ lucid partner"
#add-apt-repository "deb-src http://archive.canonical.com/ubuntu lucid partner"
#apt-get update
#apt-get install sun-java6-jdk
#update-java-allternatives -s java-6-sun
对于Froyo及更低的版本号,Android要求支持Java 5,这主要与当时Android无法兼容Java 6的overide属性有关。以下是安装sun-java5-jdk的安装过程:
#add-apt-repository "deb http://archive.ubuntu.com/ubuntu dapper main multiverse"
#add-apt-repository "deb http://archive.ubuntu.com/ubuntu dapper-updates main multiverse"
#apt-get update
#apt-get install sun-java5-jdk
#update-java-allternatives -s java-1.5.0-sun
(2)基本开发包
另外,对于64位的Ubuntu 10.04 LTS,还须要进行例如以下的安装:
#apt-get install git-core gnupg flex bison gperf build-essential zip curl zliblg-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncureses5-dev is32-libs xllproto-core-dev libxll-dev lib32readline5-dev lib32z-dev
对于32位的Ubuntu 10.04 LTS,则须要进行例如以下安装:
#apt-get install git-core gnupg flex bison gperf build-essential zip curl zliblg-dev gcc-multilib g++-multilib libc6-dev-i386 ncurses5-dev xllproto-core-dev libxll-dev readline5-dev
假设希望进行原生代码的内存泄露方面的检測,那么须要安装Valgrind包。
(3)安装repo
为了获取Android的源码。必须安装repo。
repo是Google对git的封装,使对git的操作更加方便。
以下是安装repo的方法:
#medir ~/bin
#PATH=-/bin:$PATH
#curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo>~/bin/repo
#chmod a+x ~/bin/repo
注意:repo也是不断升级的,并对驻留的操作系统的配置有依赖性,比方对Python就有要求,偶尔会发生更新后无法操作repo的情况。
2)源码获取
获得源码的方式很easy,依据笔者的经验。建议创建两个目录。分别用于获取开发版本号和最新版本号。假设开发的目标环境是Froyo,则创建froyo和android两个目录。当中froyo目录用于获取froyo分支,而android目录用于获取主分支(master)。
获取主分支的方法例如以下:
#repo init -u https://android.googlesoutce.com/platform/manifest
获取特定分支的方法例如以下:
#repo init -u https://android.googlesource.com/platform/manifest -b froyo
在初始化完毕过程中,须要设置开发人员的名字、邮箱地址,以及一些状态显示,通常建议使用Gmail邮箱。在初始化完毕后,就可以下载源码。下载源码的方法例如以下:
#repo sync
注意:repo不支持端点续传,repo的下载是基于单个project进行的,在Android中。眼下包括了170个左右的project,其列表位于.repo\project.list中。处于开发阶段的project和内核project不会被下载。在下载完毕前,源码会被隐藏,直到下载完毕后。开发人员才干看到下载的源码。
假设基于源码的方式进行开发,内核的代码是必须的,通常能够从硬件厂商哪里获得最新的代码。
当前Android源码树中已经包括了Qualcomm、TI、Qernu(模拟器)、Sansung、NVIDIA等厂商的代码。
对于普通开发人员而言,不须要向Android仓库提交代码,且其对repo的使用方法要求较低。假设希望了解repo的很多其它信息。请參考http://soutce.android.com。
3)基本编译过程
Android的基本编译过程主要包含3部分:环境变量设置、设置编译属性配置、运行编译。首先通过终端切换到Android的根文件夹下,然后运行例如以下操作:
#.build/envsetup.sh
#lunch 1 //设置目标环境,lunch菜单选项为full -eng
上述代码中,lunch的语法规则为:lunch<product><variant>。眼下Android通过LUNCH_MENU_CHOICES数组提供了4种默认的lunch菜单选项(simulator仅存在于驻留操作系统为Linux的环境中),例如以下所看到的:
LUNCH_MENU_CHOICES[4]={full-eng, full_x86-eng, vbox_x86-eng, simulator}
为了运行full-eng目标环境编译,需声明lunch 1;为了运行full_x86-eng目标环境编译。需声明lunch 2;对于其它lunch菜单选项。则需显示声明,如为了编译SDK,其方法为lunch sdk-eng。
另外,Android还支持多CPU的编译,比如运行make -j4,意味着编译工作能够同一时候在最多4个CPU上同一时候进行,这在CPU普遍为多核架构的今天。是个不错的设计。遗憾的是,Android没有公布官方的基于分布式编译的工具,无法有效地利用局域网内部的空暇计算能力。
对于一台高性能的PC而言,完毕整个编译过程需1.5h左右,之后会在out文件夹下发现3个文件夹:host、target、tmp。当中host文件夹放置的是工具信息,target文件夹放置的是帮助文档,中间生成文件、输出的文件系统和映像文件等,tmp文件夹放置的是Apache的harmony的一些測试信息。比如,out\target\product\generic\installed-files.txt记录了输出的文件系统的信息。
4)快捷方式
眼下Android支持的快捷方式包含croot、m、mm、mmm、cgrep、jgrep、resgrep、godir等。
croot:用于改变当前路径到Android根文件夹。
m:用于从Android根文件夹開始编译。
mm:用于编译当前文件夹下的全部模块。
mmm:用于编译特定文件夹下的全部模块。
cgrep:用于在C/C++文件里查找。
jgrep:用于在Java文件里查找。
resgrep:用于在资源文件里查找。
godir:用于跳转到某个文件夹。
(3)主要脚本
Android中的脚本类文件主要用来配置产品、目标板。以及依据开发人员的Host和Target来选择对应的工具并设定对应的编译选项。
编译系统的主要脚本包含envsetup.sh、config.mk、envsetup.mk、product_config.mk、BoardConfig.mk、version_defaults.mk、product.mk、build_id.mk、AndroidProducts.mk、Makefile等。Android运行编译所涉及的主要脚本之间的调用关系例如以下图所看到的:
AndroidProducts.mk包括了详细的应用配置脚本,如在Passion目标环境中,HTC引用的是full_passion.mk脚本;product_config.mk主要定义了AAPT、产品制造商、WIFI、OTA等相关信息:product.mk定义可产品的一些变量信息。
对模块编译进行控制,主要是通过core.mk、generic.mk、sdk.mk等脚本及特定目标环境的脚本进行的;对于单个模块进行控制。主要是通过Android.mk和CleanSpec.mk等脚本进行的。以下对主要脚本进行具体的介绍:
1)envsetup.sh
envsetup.sh脚本的主要功能包含定义环境变量信息、载入系统配置信息(软件信息、硬件配置)、定义编译快捷方式(如mm、mmm等)、调试、冒烟測试、GDB调试等。
若编译代码,就要涉及代码的编译工具。眼下Android支持的原生代码编译工具链位于prebuild文件夹下,包含交叉编译工具链和普通编译工具链。眼下交叉编译工具链为arm-eabi。
其当前版本号为4.4.3。所谓EABI。即应用程序二进制接口(Embedded Application Binary Interface)。又称为GUN EABI。EABI和早期的OABI(old ABI)均是针对ARM架构的CPU的,EABI支持软件浮点和硬件实现浮点功能混用,其系统调用的效率更高。兼容性更好,对软件浮点的支持效率比OABI高非常多。
普通编译工具链包含i686-linux-glibc2.7-4.4.3、i686-unknown-linux-gnu-4.2.1和sh-4.3.3等。设置交叉编译工具链的步骤例如以下:
export ANDROID_EABI_TOOLCHAIN=$prebuiltdir/toolchain/arm-eabi-4.4.3/bin
export ANDROID_TOOLCHAIN=$ANDROID_EABI_TOOLCHAIN
export ANDROID_QTOOLS=$T/development/emulator/qtools
设置java编译工具的方法例如以下:
function set_java_home(){
if[!"$JAVA_HOME"]; then
case ‘uname -s‘ in
Darwin(export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home;;)
export JAVA_HOME=/usr/lib/jvm/java-6-sun;;
esac
fi
}
眼下Android的Makefile文件名称为Android.mk,与标准的Makefile同样。
2)config.mk
config.mk用于定义系统相关的配置信息和编译变量等,是Android编译系统中很重要的一个脚本。以下是config.mk中对输出包后缀的设置:
COMMON_PACKAGE_SUFFIX:=.zip
COMMON_JAVA_PACKAGE_SUFFIX:=.jar
COMMON_ANDROID_PACKAGE_SUFFIX:=.apk
以下是config.mk中载入目标环境的过程:
board_config_mk:=$(strip $(wildcard$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk\
device/*/$(TARGET_DEVICE)/BoardConfig.mk vendor/*/$(TARGET_DEVICE)/BoardConfig.mk))
在默认情况下,目标环境信息位于SRC_TARGET_DIR、device、vendor下。
开发人员能够将自己定义的目标环境文件夹放置在这些文件夹下。
比較重要的编译变量包含CLEAR_VARS、BUILD_STATIC_LIBRARY、BUILD_SHARED_LIBRARY和BUILD_PACKAGE等。这些变量在构建应用的android.mk脚本中会用到。开发人员必须掌握其含义。
3)envsetup.mk
envsetup.mk主要用于推断驻留的操作系统环境下、环境变量设置。比較重要的环境变量包含TARGET_PRODUCT、TARGET_BUILD_VARIANT、HOST_OS、BUILD_OS、BUILD_ARCH、HOST_BUILD_TYPE、OUT_DIR等。
(1)TARGET_PRODUCT表示编译的目标环境
TARGET_PRODCT的定义详细有OEM厂商决定。相应于特定的目标环境,须要在build\target或device文件夹下存在特定的目标环境配置文件夹,比方相应generic目标环境,在build\target\board\generic下定义了generic目标环境的详细配置(如系统属性、键盘配置等)。而对于Samsung的crespo目标环境,配置文件文件夹为device\Samsung\crespo。
(2)TARGET_BUILD_VARIANT表示目标编译变量
说明有哪些文件被纳入编译控制。眼下TARGET_BUILD_VARIANT的值包含eng、user、debug、tests等。
(3)HOST_OS用于设置驻留的操作系统
眼下Android仅支持在Linux或Mac下编译源码,而在Windows下需借组于Linux仿真环境Cygwin才干编译源码。
眼下Android支持的HOST_OS的值包含linux、Darwin(用于Darwin、Mac等操作系统)、windows等。推断操作系统的方法例如以下:
UNAME:=$(shell uname-sm) //UNAME包括了操作系统和CPU架构的信息
ifneq(,$(findstring Linux,$(UNAME)))
HOST_OS := linux
endif
(4)BUILD_OS表示正真运行编译的操作系统,眼下BUILD_OS与HOST_OS等同。
(5)BUILD_ARCH表示主流处理器架构,眼下Android仅支持x86和PPC两种架构。
(6)HOST_BUILD_TYPE表示编译的类型,眼下Android支持release和debug两种类型。debug用于调试。
(7)OUT_DIR表示输出文件的路径
眼下输出文件位于out文件夹下,主要由target、host和common 3部分构成。
以下是定义OUT_DIR的实现:
ifeq(,$(strip $(OUT_DIR)))
OUT_DIR := $(TOPDIR)out
endif
4)BroadConfig.mk
BroadConfig.mk用于设置硬件相关的信息。是构建目标环境配置的重要脚本。眼下Android定义的目标环境包含Emulator、Generic、Generic_x86、Sim。除了以上目标环境外,Android源码还包含了HTC的passion与dream,以及Samsung的crespo等目标环境,能够作为驱动开发者进行目标环境配置的參考。
build\target\board\generic\文件夹下BoardConfig.mk的实现例如以下。当中定义了引导器、内核、编译器、驱动、分区配置等方面的信息。
TARGET_NO_BOOTLOADER:=true
TARGET_NO_KERNEL:=true
TARGET_CPU_ABI:=armeabi
HAVE_HTC_AUDIO_DRIVER:=true
BOARD_USES_GENERIC_AUDIO:=true
TARGET_SHELL:=mksh
crespo目标环境在BoardConfig.mk中对分区配置的定义例如以下:
BOARD_NAND_PAGE_SIZE:=4096 -s 128
BOARD_KERNEL_BASE:=0x30000000
BOARD_KERNEL_PAGESIZE:=4096
BOARD_KERNEL_CMDLINE:=console=ttyFIQ0 no_console_suspend
TARGET_RECOVERY_UI_LIB:=librecovery_ui_crespo
TARGET_RELEASETOOLS_EXTENDIONS:=device/samsung/crespo
TARGET_USERIMAGES_USE_EXT4:=true
BOARD_SYSTEMIMAGE_PARTITION_SIZE:=536870912
BOARD_USERDATAIMAGE_PARTITION_SIZE:=1073741824
BOARD_FLASH_BLOCK_SIZE:=4096
在目标环境中。还有一个比較重要的脚本是AndroidBoard.mk。通经常使用于定义按键布局等信息,与键盘有关的信息定义在tuttle2.ki和tuttle2.kcm等文件里。
build\target\board\generic\文件夹下AndroidBoard.mk的实现例如以下:
LOCAL_PATH:=$(call my-dir)
file:=$(TARGET_OUT_KEYLAYOUT)/tuttle2.k1
ALL_PREBUILT+=$(file)
$(file):$(LOCAL_PATH)/tuttle2.k1|$(ACP)
$(transform-prebuilt-to-target)
include $(CLEAR_VARS)
LOCAL_SRC_FILES :=tuttle2.kcm
include $(BUILD_KEY_CHAR_MAP)
当然在实际实现中。关于目标环境的配置比較复杂,开发人员须要依据自身的实际情况灵活配置。
5)version_defaults.mk
version_defaults.mk用于处理各种编译版本号信息,如PLATFORM_VERSION、PLATFORM_SDK_VERSION、BUILD_ID、BUILD_NUMBER等。
对于主分支的源码,其PLATFORM_VERSION的值为AOSP。PLATFORM_SDK_VERSION的值为数字,BUILD_ID的值为OPENMASTER、BUILD_NUMBER的值是依据编译日期生成的。
对于Gingerbread分支的代码,其PLATFORM_VERSION当前的值为2.3.7。开发人员假设希望获取当前执行环境的版本号信息,那么能够通过build.java来实现。方法例如以下:
Build.DISPLAY //BUILD_ID,如“OPENMASTER”
Build.VERSION.RELEASE //公布版本号,如“3.4b5”
Build.VERSION.SDK_INT //SDK版本号,如“8”
6)build_id.mk
build_id.mk用于定义版本号分支信息。其应用方法例如以下:
BUILD_ID:=OPENMASTER //编译分支
DISPLAY_BUILD_NUMBER:=true //是否显示版本
7)Makefile
除以上脚本外。还有一个很重要的脚本为build\core\Makefike,它用于定义生成各种映像文件的配置,包括boot.img、ramdisk.ing、userdata.ing、syetem.img、recovery.img等。以下是定义system.img包括内容的过程:
systemimage_intermediates:=$(call intermediates-dir-for, PACKAGING, systemimage)
BUILT_SYSTEMIMAGE:=$(systemimage_intermdiates)/system.img
INTERNAL_SYSTEMIMAGE_FILES:=$(filter $(TARGET_OUT)/%, $(ALL_PREBUILT) $(ALL_COPIED_HEADERS) $(ALL_GENERATED_SOURCES)
$(ALL_DEFAULT_INSTALLED_MODULES))
以下是生成system.img的过程:
define build-systemimage-target
@echo "Target system fs image: $(1)"
@mkdir -p $(dir $(1))
$(hide) $(MKYAFFS2) -f $(mkyaffs2_extra_flags) $(TARGET_OUT) $(1)
endef
endif #INTERNAL_USERIMAGES_USE_EXT
$(BUILT_SYSTEMIMAGE): $(INTENAL_SYSTEMIMAGE_FILES)
$(INTENAL_USERIMAGES_DEPS)
$(call build-systemimage-target, $@)
INSTALLED_SYSTEMIMAGE:=$(PRODUCT_OUT)/system.img
SYSTEMIMAGE_SOURCE_DIR:=$(TARGET_OUT)
其它映像文件的生成方法和system.img类似。
8)core.mk
core.mk中定义了产品的一些基本信息和核心包。基本信息主要包含产品的BRAND、DEVICE及产品属性(如提示音、振铃音、多媒体框架配置等)。
9)generic.mk
generic.mk定义了generic目标环境的应用编译控制脚本,主要側重将哪些应用增加到编译系统中,假设开发人员希望将实现的某一应用增加到编译系统中。应在generic.mk中增加对应的配置是该应用的LOCAL_PACKAGE_NAME纳入PRODUCT_PACKAGES变量的控制中。当然,针对不同的目标环境,对应的应用编译控制脚本并不同样。
比如,希望将Calendar应用增加编译系统,通过查看package\apps\Calendar\文件夹下Android.mk中相关的配置。获悉其LOCAL_PACKAGE_NAME为Calendar,将应用增加编译系统的方法例如以下:
PRODUCT_PACKAGE:= \
...
Calender \
...
10)sdk.mk
假设是在编译SDK,则应注意sdk.mk脚本,其和generic.mk一样具有编译控制功能。
可是除了对普通应用进行控制外,依据SDK的特点。sdk.mk还将Android工具、资源相关的信息纳入到编译系统中。
11)Android.mk
对于单个project,Android是通过Android.mk来进行编译控制的。定义的信息一般包含LOCAL_SRC_FILES、LOCAL_PACKAGE_NAME等本地环境变量。一个简单的HelloActivity的Android.mk实现例如以下:
LOCAL_PATH:=$(call my-dir) //设置路径为当前路径
include $(CLEAR_VARS) //清空LOCAL_SRC_FILES等设置环境变量
LOCAL_MODULE_TAGS:=samples //设置模块表示
LOCAL_SRC_RILES:=$(call all-java-files-under, src) //设置源码路径为\src
LOCAL_PACKAGE_NAME:=HelloActivity //设置包名
LOCAL_SDK_VERSION:=current //设置SDK版本号
include $(BUILD_PACKAGE) //调用编译脚本
include $(call all-makefiles-under, $(LOCAL_PATH)) //引入当前路径下的全部编译脚本
清空本地环境变量实际上是调用build\core\文件夹下的Clear_vars.mk完毕的;LOCAL_MODULE_TAGS的可选值包含samples、optional、eng、debug、tests、cts、user等。其默认值为optional,对于普通应用,LOCAL_MODULE_TAGS的值为optional。LOCAL_SDK_VERSION的默认值为current,可是假设希望在Gingerbread源码环境中编译基于Froyo的应用,则应设置LOCAL_SDK_VERSION的值为8.调用编译脚本实际上是调用了build\core\文件夹下的package.mk的内容。
假设应用代码中包括AIDL文件,那么僵AIDL文件加入到源码树中的方法例如以下:
LOCAL_SRC_FILES:=$(call all-java-files-under, src)
LOCAL_SRC_FILES+=src/com/example/android/apis/app/IRemoteService.aidl \
src/com/example/android/apis/app/IRemoteServiceCallback.aidl \
src/com/example/android/apis/app/ISecondary.aidl \
(1)载入共享库
其实,android.mk还支持更复杂的配置。如载入Java库和原生库,同一时候运行多个编译任务等。以下以Calculator为例介绍复杂的Android.mk实现。
Calculator的Android.mk运行了两个编译任务,除了编译应用外。还载入了一个JAR库。一个相关的示比例如以下:
LOCAL_PATH:=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS:=optional
LOCAL_STATIC_JAVA_LIBRARIES:=libarity //载入静态库
LOCAL_SRC_FILES:=$(call all-java-files-underm src)
LOCAL_SDK_VERSION:=current
LOCAL_PACKAGE_NAME:=Calculator
include $(BUILD_PACKAGE)
include $(CLEAR_VARS) //编译静态库
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=libarity:arity-2.1.2.jar
include $(BUILD_MULTI_PREBUILT) //引入预处理脚本
include $(call all-makefiles-under, $(LOCAL_PATH))
为了载入JAR库,须要重点了解LOCAL_STATIC_JAVA_LIBRARIES和LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES两个本地环境变量。
前者表示应用载入的库名,后者用于设置与库名相应的详细的JAR库。假设希望载入多个JAR库,那么能够按下面方法设置本地环境变量:
LOCAL_STATIC_JAVA_LIBRARIES:=lib1 lib2
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES:=lib1:1.jar lib2:2.jar
除了JAR库外,部分应用可能还包括了基于JNI的原生代码实现。这些原生代码通常被编译成共享库的形式。如果生成的共享库为libnative.so,那么在应用的Android.mk文件里载入共享库的方法例如以下:
LOCAL_JNI_SHARED_LIBRARIES:=libnative
假设是在SDK下进行开发,那么对JAR库和原生共享库均不须要进行配置,通常将JAR库放置在应用的根文件夹或libs文件夹下,将原生共享库放置在libs\armeabi文件夹下。
(2)应用权限
要进行限制级的操作,如查看电话簿。拨打电话等,就涉及权限问题。
Android.mk支持设置本地证书,方法例如以下:
LOCAL_CERTIFICATE:=platform
眼下LOCAL_CERTIFICATE的可选值包含platform、shared、media、testkey、cts/tests/appsecurity-tests/certs/cts-testkey1、cts/tests/appsecurity/certs/cts-testkey2等。当中。platform便是系统证书。通常和在AndroidManifest.xml中增加的android:sharedUserId="android.uid.system"属性结合使用。
(3)混淆器设置
Java的解释性编译的特性,注定了在保护开发人员的知识产权方面会存在风险。在当前强大的反编译技术下,假设不进行混淆。那么应用的Java代码对全部人来说都差点儿是一目了然的。为了保护开发人员的知识产权和企业的商业机密,Android引入了proguard混淆器。
在Android中载入groguard混淆器的方法例如以下:
LOCAL_PROGUARD_FLAG_FILES:=proguard.flags
以Launcher2为例。其proguard.flags实现例如以下:
-keep class com.android.launcher2.Launcher{
public void previousScreen(android.view.View);
public void nextScreen(android.view.View);
}
-keep class com.android.launcher2.AllApps3D$Defines{
*;
}
-keep class com.android.launcher2.ClippedImageView{
*;
}
假设不希望进行Java混淆,则能够进行例如以下设置:
LOCAL_PROGUARD_ENABLED:=disabled
假设是基于SDK进行开发,那么Eclipse会自己主动帮组应用进行混淆。
(4)安装到特定文件夹下
在开发某些特定应用时。须要将特定的数据安装到映像文件的特定文件夹下,如会考虑将配置文件安装到etc文件夹下等。
以下是将android.software.live_wallpaper.xml安装到\system\etc\permissions文件夹下的方法:
include $(CLEAR_VARS)
LOCAL_MODULE:=android.software.live_wallpaper.xml
LOCAL_MODULE:=ETC
LOCAL_MODULE_PATH:=$(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES:=$(LOCAL_MODULE)
LOCAL_MODULE_CALSS的可选值有EXECUTABLES、ETC、DATA、STATIC_LIBRARIES、JAVA_LIBRARIES、SHARED_LIBRARIES等。
12)CleanSpec.mk
CleanSpec.mk用于在编译时清除遗留的中间文件和数据文件,通常不须要进行设置。以下是CleanSpec.mk中的部分实现:
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
$(call add-clean-step, rm -rf (OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
$(call add-clean-step, rm -rf find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
(4)环境变量
在Android编译系统中。有几个重要的环境变量须要注意,以下进行简单的介绍。
1)ANDROID_TOOLCHAIN
ANDROID_TOOLCHAIN主要用于设置交叉编译工具链,眼下Android的交叉编译工具链为arm-eabi-4.4.3。须要注意。工具链的工具包含ar、as、c++、g++、gcc、ld、nm、objcopy、objdump、ranlib、strip等。查看模块间依赖关系的工具ldd并不在当中。
2)ANDROID_PRODUCT_OUT
ANDROID_PRODUCT_OUT定义了编译目标环境输出的绝对路径。对于generic文件夹环境而言,其ANDROID_PRODUCT_OUT的值为ANDROIDROOT/out/target/product/generic,由TARGET_PRODUCT_OUT_ROOT和TARGET_DEVICE组成。
3)TARGET_PRODUCT
TARGET_PRODUCT表示编译的目标环境,这是Android编译系统中最重要的环境变量。眼下Android提供了多个目标环境。包含sdk、sim、full、full_x86、generic、full_crespo等。另外。HTC、Samsung等厂商的部分机型的目标环境也进行了开源。
须要说明的是。generic表示最低配置;full表示集成全部语言、应用、输入法的配置;full_crespo表示针对Nexus S的配置。
4)TARGET_BUILD_VARIANT
TARGET_BUILD_VARIANT定义了编译变量。眼下Android支持的编译环境包含eng、user、debug、tests等。
5)TARGET_BUILD_TYPE
TARGET_BUILD_TYPE表示编译的类型。指定编译的是debug还是release类型。debug表示包括调试信息。TARGET_BUILD_TYPE能够帮组开发人员进行GDB调试。
6)TARGET_SIMULATOR
TRAGET_SIMULATOR为一个布尔型的变量。用于推断输出目标环境的是真实的设备还是模拟器。
(5)目标环境
目标环境由TARGET_PRODUCT和TARGET_BUILD_VARIANT共同定义。眼下Android自带的编译模式有full-eng、full_x86-eng和simulator等。
在进行源码编译时,通过例如以下方式能够指定目标环境:#lunch "TARGET_PRODUCT" -"TARGET_BUILD_VARIAN",接着直接运行make就可以运行对应的目标环境编译。
2.SDK编译
在OEM开发中,常常须要公布SDK供应用开发者使用。依据驻留操作系统的不同。Android的SDK编译分为Linux和Windows两种环境下的编译。当然假设在开发过程中,对ADT相关的内容也做了改动。则还需编译ADT插件。通常ADT插件採用Android官方公布的版本号就可以。
关于SDK的编译,在sdk\docs\文件夹下的howto_build_SDK.txt文档中有很具体的介绍。
(1)Linux下的SDK编译
编译SDK和编译源码的Android中没有本质的不同,设置好目标环境就可以。编译Linux下的SDK的步骤例如以下:
#.build/envsetup.sh
#lunch sdk-eng
#make sdk
假设驻留的操作系统为基于x86架构的Linux,则输出文件为out\host\linux-x86\sdk\android-sdk_eng.<build-id>-x86.zip。假设驻留的操作系统为基于x86构架的Mac OS,则输出文件为out\host\darwin-x86\sdk\android-sdk_eng.<build-id>_mac-x86.zip。
(2)Windows下的SDK编译
Windows下的SDK的生成依赖于Linux、Mac下的SDK。这意味着为了编译Windows下的SDK。必须先编译Linux或Mac下的SDK。生成Windows下的SDK意味着将Linux或Mac下的SDK中与操作系统相关的UNIX二进制文件替换为Windows下的二进制文件。
在生成Linux或Mac下的SDK后,为了生成Windows下的SDK。需切换到XP或者Vista版本号的Windows操作系统下。另外还须要安装Cygwin仿真环境。可是。Android尚不支持最新的Cygwin1.7,开发人员必须安装Cygwin 1.5。
Cygwin 1.5的下载地址为http://cygwin.org/win-9x.html。
安装Cygwin须要下载的软件安装包包含autoconf、bison、curl、flex、gcc、g++、git、gnupg、make、mingw-zlib、python、zip、unzip等;建议下载的软件包包含diffutils、emacs、openssh、rsync、vim、wget等。不应下载readline软件包。然后在Cygwin环境下下载android源码。接着才干開始正真的Windows下的SDK编译。
其步骤例如以下:
#mkdir ~/mysdk
#export SDK_NUMBER=$(USER)-‘data+%Y%m%d-%H%M%S‘
#development/build/tools/make_windows_sdk.sh /path/to/macos/or/linux/sdk.zip ~/mysdk
运行完毕以上过程后就可以在mysdk文件夹下看到生成的Windows下的SDK了。
(3)ADT插件的编译
为了编译ADT插件,须要先从Eclipse的官方站点上下载Eclipse 3.4或以上的Java版本号。这里下载eclipse-rcp-ganymede-SR2-linux-gtk.tar.gz。然后将其解压到~/eclipse-3.4文件夹下,设置ECLIPSE_HOME例如以下:
#export ECLIPSE_HOME=~/eclipse-3.4/eclipse
然后为Eclipse创建桌面的启动器,将其作为开发应用的开发环境。接着就可以编译ADT插件了。
#mkdir ~/mysdk
#development/tools/eclipse/scripts/build_server.sh ~/mysdk $USER
稍等片刻就可以在~/mysdk文件夹下看到ADT插件android-eclipse-<buildnumber>.zip了。
3.NDK编译
因为性能的原因。非常多的开发人员希望可以利用C/C++等原生代码在Android平台上开发应用,尤其是当基于OpenGl和OpenCore开发的游戏、信息安全和多媒体方面的应用会涉及一些性能敏感或复杂的算法时。另外,一些基于原生代码开发的应用也有向Android移植的需求。假设是在源码环境下开发,那么直接将原生代码在源码环境下进行组织就可以。
Android NDK编译的应用能够在Android 1.5及以上版本号的Android上执行。对于本地调用涉及的JNI,须要注意的是JNI调用的开销不小。
因此。简单的操作不必採用JNI调用,且基于原生代码开发的代码还可能带来安全性的问题。另外。NDK提供的原生方法仅仅是Android源码能力的一个子集。
眼下最新版的NDK为Android NDK r6b。在该版本号中。Android提供了对很多其它原生代码能力(如C++异常处理、RTTI、STLport、FNU libstdc++等)的支持。
在通常情况下,在Android中,原生代码并非编写界面代码的最佳方式。
为了处理Android系统时间。避免ANR(Application Not Responding)情况的出现,界面代码最后通过Java来编写。原生代码通常以动态共享库的方式出如今Androidproject中。通过NDK编译出来的动态共享库的名字一般为libFileName.so,当中lib为动态共享库的前缀。为了在Java代码中载入动态共享库,可运行例如以下操作:
static{ System.loadLibrary(FileName); }
在Java代码中引用原生代码的方法例如以下: native byte[] loadFile(String parm);
有时希望在原生代码章加入在Logcat中能够看到的log信息。实现方法例如以下:
__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
上述代码中,ANDROID_LOG_DEBUG为log登记,相关的log等级定义位于$NDK_ROOT/platforms/android-9/arch-arm/usr/include/android/log.g中。
将NDK压缩包解压,会发现其根文件夹下有3个可运行脚本:ndk-build、ndk-gdb、GNUmakefile。
另外还会发现NDK主要由编译脚本、文档、部分源码、例子、測试、工具链、平台共享库等组成。
NDK中有几个重要的宏变量须要了解。
NDK_ROOT:NDK的安装根文件夹。
LOCAL_CPP_EXTENSION:用于显示定义C++文件的后缀,默认C++代码的后缀为.cpp。
TARGET_ARCH:用于指明CPU的架构。如arm指的是ARM兼容性架构。
TARGET_ARCH_ABI:用于指明CPU+ABI的目标平台。若armeabi值的是Armv5TE,armeabi-v7a指的是基于ARM v7指令集的Cortex-A8等。
TARGET_PLATFROM:用于指明Android版本号的目标平台。如希望目标环境为Froyo,则可将TARGET_PLATFORM的值设置为android-8。
另外Android NDK还提供了一个环境变量TARGET_ABI。其格式为$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)。如希望目标环境为基于Armv5TE的Froyo。可直接设置TARGET_ABI为android-8-armeabi。
为了开发一个包括原生代码的应用,如果project所在的文件夹有PROJECT宏定义。过程例如以下:
将原生代码放置在$(PROJECT\jni下,并编写JNI接口代码。
编写$(PROJECT\jni\Android.mk以描写叙述编译过程,如须要编译的源文件、模块名等。
在同一个Android.mk中能够定义多个模块。
编译$(PROJECT\jni\Application.mk来描写叙述project情况,如模块列表、CPU架构、是公布模式还是调试模式等。
在$PROJECT\jni文件夹下调用$NDK\ndk-build来生成动态共享库。假设NDK无法发现project路径,那么通过NDK_PROJECT_PATH变量来指明project路径就可以。
(1)编译脚本
Android NDK的编译很easy。其编译脚本主要由ndk-build和ndk-gdb等构成,NDK_ROOT/build/core/init.mk和NDK_ROOT/build/core/main.mk也是比較重要的编译脚本。NDK要求为GNU Make3.81及以上版本号。
1)ndk-build
ndk-build是一个很重要的脚本,通常在设置APP_PROJECT_PATH后直接调用ndk-build就可以编译project。如果要编译的project为samples/hello-jni。编译步骤例如以下:
#cd NDK_ROOT
#export APP_PROJECT_PATH=samples/hello-jni
#ndk-build
清除编译出的中间文件的方法例如以下:
#ndk-build clean
强制编译的方法例如以下:
#ndk-build -B V=1 //“B”表示强制又一次编译,“V=1”表示显示编译命令
默认编译出来的二进制代码为Release版本号,假设希望调试代码,则运行例如以下方法:
#ndk-build NDK_DEBUG=1 //NDK_DEBUG=1表示Debug版本号,NDK__DEBUG=0表示Release版本号
假设希望採用特定的Application.mk,则显示声明就可以。方法例如以下:
#ndk-build NDK_APP_APPLICATION_MK=<file>
2)ndk-gdb
ndk-gdb调试和GDB调试一样。均通过C/S模式进行调试。在Host端支持gdbclient,在target端放置gdbserver作为服务器端。
(2)配置脚本
NDK的配置脚本主要有Android.mk和Application.mk两种。
1)Android.mk
通过Android.mk,NDK能够编译静态库和动态库等两种输出文件。可是仅仅有动态库能够被加入到应用中,静态库通经常使用于生成动态库。NDK_ROOT/samples/hello-jni/jni下的Android.mk定义例如以下:
LOCAL_PATH:=$(call my-dir) //设置LOCAL_PATH为当前路径
include $(CLEAR-VARS) //清除LOCAL_PATH外的全部本地变量
LOCAL_MODULE:=hello-jni //定义模块名
LOCAL_SRC_FILES:=hello-jni.c //定义欲编译的源码
include $(BUILD_SHARED_LIBRARY) //编译我动态库
当生成动态库时。输出文件为lib$(LOCAL_MODULE).so,当生成静态库时,输出文件为lib$(LOCAL_MODULE).a。另外,LOCAL_MODULE名必须唯一,必须在编译过程開始制定。通过LOCAL_MODULE_FILENAME能够覆盖LOCAL_MODULE。比如要覆盖hello-jni为hello,方法例如以下:
LOCAL_MODULE:=hello-jni
注意:在LOCAL_MODULE_FILENAME中不应指定路径和后缀名。Android NDK会自己主动处理LOCAL_MODULE_FILENAME:=libhello
(1)编译配置
其实NDK还支持更复杂的配置。如设置编译选项、载入共享库、引入头文件等。为了在编译原生代码时将全部错误视为警告。可运行例如以下方法:
LOCAL_CFLAGS:= -Werror
通过LOCAL_LDLIBS能够载入共享库。为了设置日志输出,须要载入liblog.so,方法例如以下:
LOCAL_C_INCLUDES=<path>
LOCAL_CFLAGS+=-I<path>
(2)处理器配置
眼下NDK支持的CPU架构包含armeabi、armeabi-v7a、x86等。
为了改啥多媒体和信号处理算法(如视频编解码、2D/3D图形、游戏、音频和语音处理、图像处理、电话和语音合成等)的性能,通常希望打开NEON以支持ARM的高级单指令多数据流(SIMD。Single Instruction Multiple Data)引擎。NEON自ARMv6引入,打开NEON方法例如以下:
LOCAL_ARM_NEON:=true //要求设置TARGET_ARCH_ABI
在默认情况下。编译出来的ARM架构的二进制文件时thumb模式的,其指令集是16位的,假设希望编译出来的指令集是32位的,则能够进行例如以下设置:
LOCAL_ARM_MODE:=arm
另外通过在Application.mk中设置APP_OPTIM:=debug也能够使编译出来的指令为32位。这是由于在thumb模式下。调试器无法非常好地执行。
在输出共享库时,其路径和CPU‘架构密切相关。结构为lib/<abi>/lib<name>.so。
(3)C++高级特性
假设希望应用C++异常,能够进行例如以下设置:LOCAL_CPPFLAGS+=-fexceptions
假设希望应用RTTI,能够进行例如以下设置:LOCAL_CPPFLAGS+=-frtti
NDK的部分特性。在Android.mk和Application.mk中均可设置
2)Application.mk
Application.mk实际上是一个MakeFile文件,当中定义了欲编译的模块,主要变量包含APP_PROJECT、APP_BUILD_SCRICP、APP_MODULES、APP_OPTIM和APP_STL等。
(1)编译配置
通过APP_PROJECT_PATH定义project的绝对路径。
在默认情况下,Android NDK会到$(APP_PROJECT_PATH)\jni文件夹下寻找Android.mk文件并运行编译,假设希望通过特定的Android.mk进行编译,则需覆盖APP_BUILD_SCRIPT。
APP_MODULES定义了由LOCAL_MODULE定义的模块构成的模块列表。
APP_OPTIM定义了编译模式是release还是debug。
(2)处理器配置
在默认情况下,NDK支持的CPU架构为ARMv5TE,假设希望支持其它CPU结构。那么需显式设置APP_ABI。比如,为了利用ARMv7的硬件浮点运算,应做例如以下配置:
APP_ABI:=armeabi-v7a
armeabi-v7a在Android NDK R3时引入,其支持Thumb-2和VFPv两种指令集扩展,假设希望同一时候支持ARMv5TE和ARMv7,可运行下面操作:
APP_ABI:=armeabi armeabi-v7a
(3)C++高级特性
在默认情况下。尽管Android NDK仅包括了C++执行库的一个最小子集(libstdc++.so)。可是开发人员能够通过APP_STL来显示载入STL实现。Android採用的STL实现为在SGI STL基础上进行的一次封装和针对各平台和编译器优化后的STLport。方法例如以下:
APP_STL:=stlport_static //静态的STLport库
APP_STL:=stlport_shared //动态的STLport库
APP_STL:=system //默认C++库
载入STLport动态库,通经常使用在project中有多个动态库需用到STL特性的场景。这意味着在Java中,必须显式载入STLport动态库。
如果有libfoo.so和libbar.so都用到了STLport动态库,事实上现例如以下:
static{
System.loadLibrary("stlport_shared");
System.loadLibrary("foo");
System.loadLibrary("bar");
}
尽管Android NDK提供了STLport库供载入,可是在少数场景中。依旧须要又一次编译STLport库。其方法例如以下:STLPORT_FORCE_REBUILD:=true
假设希望应用C++异常。能够进行例如以下设置:APP_CPPFLAGS+=-fexceptions
假设希望应用RTTI,能够进行例如以下设置:APP_CPPFLAGS+=-frtti
(3)GDB调试
为了进行原生代码的调试,NDK提供了远程GDB调试手段,其主要调试脚本为ndk-gdb。ndk-gdb仅在Foryo及以上版本号中收到支持。
为了进行GDB调试,要求project处于debug模式下,这须要在AndroidManifest.xml文件里声明android:debuggable属性为true。同一时候在进行NDK编译时生成的动态库也是debug模式的。
进行GDB调试的过程例如以下:
确保project处于debug模式。
通过ndk_build来编译project,然后生成的APK安装到模拟器中。
执行应用。
在应用的project路径下执行ndk-gdb。
ndk-gdb有非常多的选项。能够支持执行应用中的特定Activity、指定ADB等。
(4)NativeActivity实现
在Android SDK中,提供了一个NativeActivity类。能够与Android框架和原生代码进行通信。实现NativeActivity有两种方法,一是通过native_activity.h头文件,二是通过android_native_glue.h头文件。
从本质上讲,NativeActivity的实现仍是基于JNI进行的。
1)通过native_activity.h头文件实现
在native_activity.h中定义创建NativeActivity(即ANativeActivity)所需的回调函数和数据结构,当中。回调函数会由应用程序的主线程进行处理,其側重Activity在生命周期的管理。当然和普通Activity一样,假设设计欠妥,也会发生堵塞。这时会抛出ANR异常。
除了Activity的生命周期管理外。NativeActivity还支持输入法的显示和隐藏。还能够通过AAssetManager支持断言等。
2)通过android_native_app_glue.h头文件实现
Android通过android_native_app_glue.h提供了对NativeActivity的再封装,还提供了构建NativeActivity所需的静态助手函数,下图是android_native_app_glue.h提供的NativeActivity封装的结构。其主接入点为android_main()函数。
ALooper用于Activity生命周期事件和输入事件;输入事件的队列有AInputQueue维护;AConfiguration表示应用程序执行配置。ANativeWindow表示渲染所需的surface。至于通过android_native_app_glue.h头文件实现NavtiveActivity的详细过程。
4.应用程序编译
应用程序的编译主要基于Android.mk文件进行。为了在编译前清除遗留的中间文件,须要实现CleanSpec.mk。
另外一个比較重要的配置文件为default.properties,其用于定义自己定义的配置。通常default.progerties由Android工具自己主动产生。不需开发人员干涉。当遗失default.properties文件时,工程会提示“Project has no default.properfies file! Edit the project properties to set one”,将无法编译。Android的应用层代码主要遵循APACHE2许可文件。
(1)本地环境变量
Android中存在大量的本地环境变量。
LOCAL_MODULE:表示本地模块名,通经常使用于编译源码的模块,在应用层开发中,多出如今JNI场景中。用于编译动态库、静态库。
LOCAL_PATH:表示本地路径。通常在编译模块时表示当前编译过程的根路径,事实上现多为当前路径,详细应用例如以下:LOCAL_PATH:=$(call my-dir)
LOCAL_MODULE_TAGS:表示编译的标签,其可选值包含optional、eng、debug、tests、samples、user等。通常其值为optional。
LOCAL_MODULE_PATH:表示编译输出文件放置的位置。关于TARGET_OUT等的定义位于\build\core\文件夹下的ensetup.mk文件里。
LOCAL_MODULE_CALSS:表示模块的类型,其可选值包含STATIC_LIBRARIES、EXECUTABLES、JAVA_LIBRARIES、ETC、SHARED_LIBRARIES等。
LOCAL_SRC_FILES:表示编译的源文件。是主要的编译变量。
LOCAL_SDK_VERSION:表示编译的模块的SDK版本号,默认值为current。假设希望编译特定的SDK版本号的模块。需显式声明SDK版本号。
LOCAL_PACKAGE_NAME:表示编译的模块名。在源码下编译应用时须要注意LOCAL_PACKAGE_NAME充当了编译的开关的角色。
LOCAL_CERTIFICATE:表示採用的系统证书。可选值包含platform、shared、cts/tests/appsecurity-tests/certs/cts-testkey2、cts/tests/appsecurity-tests/certs/cts-testkey1、media等。当中platform表示系统证书。LOCAL_CERTIFICATE通常与AndroidManifest.xml中的android:shareduserId属性同一时候使用。
LOCAL_SHARED_LIBRARIES:表示须要载入的动态库,对于libstlport.so动态库,载入方式为:LCOAL_SHARED_LIBRARIES:=libstlport
LOCAL_STATIC_LIBRARIES:表示须要载入的静态库,对于libc.a。其载入方式为:LOCAL_STATIC_LIBRARIES:=libc
LOCAL_PRELINK_MODULE:假设希望将模块链接到系统中,则应设置LOCAL_PRELINK_MODULE为true。否则应设置LOCAL_PRELINK_MODULE为false。
CLEAR_VARS:有Android系统定义,用于清除除LOCAL_PATH外的全部本地变量。如LOCAL_SRC_FILES等。
(2)Eclipse下编译
基于SDK在Eclipse下编译应用程序,这是最主要的应用开发方法,相比基于源码进行开发,这样的开发调试起来更方便,也可充分利用IDE提供的自己主动完毕功能。可以有效地提高开发效率。
5.目标系统配置
基于源码开发,除了须要定义上层的目标环境配置外,针对不同的硬件,还需自己定义不同的目标板配置。目标板配置更側重底层的细节。
(1)自己定义模拟器配置
在商业开发中,依据产品的形态,自己定义模拟器是一个必须的过程,自己定义模拟器主要包含连个方面,自己定义皮肤和选项配置。
对于QEMU和映像文件。在SDK环境下,假设创建AVD时选择了Android 2.2平台,默认的QEMU为platforms/android-2.2/images/kernel-qemu,默认的映像文件为platforms\android-8\images\system.img;在源码环境下。默认的QEMU为.\prebuilt\android0-arm\kernel\kernel-qemu。默认的映像文件为.\out\target\product\generic\system.img。
须要注意的是随着Android版本号的不断升级,system.img已日趋庞大,在Foryo中个,system.img已经接近80MB,模拟器的启动速度也越来越慢。
例如以下是加快模拟器启动的方法:
使用RAID 0或RAMDISK等软件来提高系统的I/O性能。
定期使用=wipe-data參数启动emulator来重置模拟器数据。
假设基于SDK开发,那么不必每次都重新启动模拟器。直接编译应用,模拟器会自己主动更新应用的APK并启动应用。
加大模拟器的config.ini文件里RAM的大小。
1)自己定义皮肤
眼下Android已经提供多个分辨率下的皮肤,如HVGA、QVGA、WQVGA400、WQVGA432、WVGA800、WVGQ854等。
为了创建自己定义皮肤,首先须要搞清楚皮肤的构成。
通过观察系统自带的皮肤能够知道。除了构建皮肤须要的图片外。有两个关键的配置文件,即hardware.ing和layout。当中hardware.int文件定义了模拟器相关的硬件信息。layout文件定义了模拟器相关的结构信息。
皮肤主要包含parts、layouts、keyboard、network等几部分,当中还具体规定了背景图和坐标,假设不须要某一部分,则直接从模拟器中去除就可以,对于横竖屏处理,默认依据解析的第一中状态进行载入,比如,当前产品为横屏模式时。将portrait与landscape位置颠倒一下就可以。
在模拟器启动后,通过“Ctrl+F11”快捷键就可以实现横竖屏的切换。
假设高分辨率是HVGA,那么在所建project右击。在弹出的快捷 菜单中运行Run as --- Run Confugurations 命令,可打开Android配置对话框选择Target选项。在Additional Rmulator Command Line Options输入框输入參数 -skin HVGA-L也能够实现竖屏启动。
在自己定义皮肤时,依据目标设备的特征,能够对系统皮肤进行相关的取舍和改动。
对于键盘,眼下Android默认支持qwerty、qwerty2两种模式。并同意用户自己定义键盘模式。假设希望自己定义键盘模式,则须要定义external/qemu/android/Charmap.c中的android_custom_charmap变量。
对于网络速度,眼下Android支持full、GSM、HSCSD、GPRS、EDGE、UMTS、HSDPA等。
对于网路延迟,眼下Android提供了none、GPRS、EDGE、UMTS等。
2)选项配置
模拟器的选项配置主要在模拟器皮肤的hardware.ini中定义,这是商业开发中重要一环,真实地模拟环境有助于降低开发中的隐患。
开发人员能够依据自己的须要在创建AVD虚拟设备时定义选项配置,或者在hardware.ini中改动选项配置。
(2)目标板配置
目标板配置根详细的硬件密切相关。通常芯片厂商会给出对应的參考实现,在generic目标环境中。目标板配置主要位于android\build\target\board\generic文件夹下。
目标板配置可分为系统属性、键盘布局、分区配置、板级配置等。
1)系统属性
在generic中。系统属性主要分布在system.prop、device.mk等两个文件里。system.prop中属性的配置例如以下:
rild.libpath=/system/lib/libreference-ril.so
rild.libargs= -d /dev/ttyS0
device.mk中系统属性的配置例如以下:
PRODUCT_PROPERTY_OVERRIDES :=ro.ril.hsxpa=1 ro.ril.gprsclass=10
PRODUCT_COPY_FILES:=development/data/etc/apns-conf.xml:system/etc/apns-conf.xml development/data/etc/vold.conf:system/etc/vold.conf
2)键盘布局
键盘的布局分布在目标环境的tuttle2.kcm、tuttle2.kl中。KCM文件表示按键字符集的映射。KL文件表示按键布局的映射。键盘文件的编译工作由AndroidBoard.mk完毕。
KL文件里的内容是UTF-8类型的。格式为key SCANCODE KEYCODE[FLAGS...],当中SCANCODE表示按键扫描码,KEYCODE表示键值,FLAGS可选项有SHIFT、ALT、ACPS、WAKE、WAKE_DROPPED等。
tuttle2.kl中的一个键值映射的示比例如以下:
key 158 BACK WAKE_DROPPED
为了节省空间。在编译过程中会用工具makecharmap将KCM‘文件转化为二进制文件*.bin。详细的编译情况能够參考android/build/core/key_char_map.mk。
3)分区配置
分区配置包含SD卡的挂载和设备内置的闪存分区配置。在generic中,没有给出实际的闪存分区配置。
以下是vold.conf中关于SD卡的挂载配置
volume_sdcard{
emu_media_path /devices/platform/goldfish_mmc.o/mmc_host/mmc0
media_type mmc
mount_point /sdcard
ums_path /device/platform/usb_mass_storage/lun0
}
在实际研发中。闪存分区配置多位于BoardConfigCommon.mk中。正常的分区的挂载则在init.rc中实现。
4)板级配置
所谓板级配置主要指与设备相关的编译期配置,其主要分布在BoardConfig.mk中。
(3)目标环境配置
Android默认支持的目标环境包含sim、full、generic等。另外,Android还给出了一些OEM厂商的目标环境演示样例,如HTC的passion和Samsung的crespo。
目标环境在源码中的位置能够分布在android\device、android\build\target等文件夹下,当中OEM’厂商的实现多位于android\device文件夹下。
目标环境的制定是通过在build\core\文件夹下的envsetup.mk中声明TARGET_PRODUCT来确定的。实际的目标环境配置会涉及非常多方面。OEM厂商能够依据芯片厂商的參开设计进行调整。
6.文件系统配置
在System\core\rootdir\文件夹下的Android.mk中会载入外部文件系统的挂载信息,相关信息定在vold.fstab文件里。
挂载文件系统的格式例如以下:
dev_mount <label> <mount_point> <part> <sysfs_path1...>
以下是vold.fstab的一个实现:
dev_mount sdcard /mnt/sdcard 3 /devices/platform/s3c-sdhci.0/mmc_host/mmc0/mmc:0001/block/mmcblk0
7.编译工具
对于Android而言,包含Java、C/C++等源码的编译和帮组文档的生成,整个编译系统都是基于make进行的。
(1)Java的编译
Java编译涉及的工具比較简单,编译过程主要是基于Java进行的。在Froyo及曾经版本号中。採用的是Java5,在Gingerbread及以后的版本号中,採用的是Java 6,也能够採用Open JDK 6。
查看当前Java版本号的方法例如以下: #java -version
在Linux中,假设同一时候安装了Java 5和java 6,配置Java的工具update-java-alternatives。
查看安装Java的列表的方法例如以下: #update-java-alternatives -1
设置当前Java的方法例如以下:#update-java-alternatives -s java-6-sun
(2)C/C++的编译
为了使驻留的x86架构的操作系统上编译的C/C++代码的输出文件可以在ARM架构的移动终端上执行,必须进行交叉编译。通常编译工具链由编译器、连接器和解释器构成,详细到组件上,是由Binutils、GCC、Glibc和GDB构成的。在Android中。C库採用的是Google优化自BSD的Bionic,而非标准的Glic。
在Android中。原生代码採用的交叉编译工具链为arm-eabi-4.4.3,其可以将原生代码编译为ARM架构的二进制文件,其包含的主要工具有ar、as、c++、g++、ld、nm、objcopy、objdump、ranlib、strip等。
以下是交叉编译工具链中主要工具的含义:
在通过NDK编译一些移植过来的代码时须要注意,arm-eabi-4.4.3对代码的要求更加严格,在低版本号编译器下编译通过的代码在arm-eabi-4.4.3下并不一定能顺利编译通过。
当然在编译模拟器部分的原生代码时,并不须要进行交叉编译,採用的编译器为i686-unknown-linux-gnu-4.2.1。
在ARM架构下,编译出的可运行文件的格式为ELF。假设希望构建自己的交叉编译环境。则须要用到Crosstool工具。
假设希望检測实现的原生代码是否存在内存泄露,则会用到Valgrind工具。Valgrind是一个很强大的内存调试和代码分析工具。
(3)帮组文档的生成
对于大型软件,尤其是接口对外开放的软件,帮组文档尤为重要。所幸业界已经有专门的工具能够帮组生成帮组文档。当然在编写帮组文档时,须要依照相关的规定和要求进行。在Android中,採用的帮组文档工具是javadoc。除了javadoc以外,眼下业界常常採用的帮组文档工具还有Doxygen。
8.fastBoot模式
fastboot即高速启动。通经常使用于刷机、解锁等操作中。一般特定的组合键来进入fastboot模式。因为fastboot跟硬件密切相关。故并不是全部的OEM厂商都遵循Android的规范。本节介绍的内容并不适合全部设备,仅供參考。
在Froyo及以后版本号中,通过adb reboot bootloader能够重新启动物理Android设备。
对于Nexus One、Nexus S、Nexus S 4G,在默认情况下设备时锁住的,通过例如以下方法能够解锁:#fastboot oem unlock
在Nexus S、Nexus S 4G中,通过fastboot还能够锁住设备,方法例如以下:#fastboot oem lock
在升级系统后。可能会存在旧用户数据和新系统不兼容的文件,解决方法例如以下: #fastboot erase cache #fastboot erase userdata
以下为升级系统的方法,这样的方法导致引导分区、恢复分区、系统分区的重写。在写入过程完毕后重新启动系统。 #fastboot flashall
须要单独编译fastboot和adb时,运行的方法例如以下: #make fastboot adb
标签:security 编译选项 unlock 开发人员 lex exec release launcher 驱动开发
原文地址:http://www.cnblogs.com/jzdwajue/p/6863763.html