Android平台开发指导(Android Porting Guide)
本文为Android平台开发人员和Android设备制造商提供了底层开发指导。如果你对Android的上层应用开发很感兴趣,请访问Android Developers Site。
关于这份指导书
这份指导书按照逻辑划分为几个部分(见目录)。在一个持续的开发过程中,Android是一个复杂的工程项目,随着版本和API的改变,这份指导书将会不断更新。
至使用者
对于精通嵌入式Linux的工程师而言,这本书非常有价值。但是,它的重点并不在普通的嵌入式Linux开发,而是更多提供Android平台的特色。
初学Android
对于初识Android的人而言,建议阅读以下文档:
Android Develop site:这个网页提供了高版本的SDK文档;
Android Open Source Project site:这个网页指导你如何获取源代码,建立开发环境和从事简单的工程开发。
如果你准备在你的目标系统上定制和移植Android系统,请阅读系统编译概述。
1.配置和编译
1.1系统编译
Android用一个定制的编译系统产生一系列工具,编译文件和文档。这一小节概述了Android编译系统和如何建立一个简单的编译环境。
makefile文件定义了如何去建立一个系统的编译规则。典型的makefile包含以下一些元素:
1. 名称:为你的编译目标取一个名称(LOCAL_MODULE := <build_name>);
2. 局部变量:用CLEAR_VARS清除局部变量(include $ (CLEAR_VARS));
3. 所需要编译的文件:注明你的目标需要链接哪些源文件(LOCAL_SRC_FILES := main.c);
4. 标记:编译选项(LOCAL_MODULE_TAGS := eng development);
5. 库:定义你的目标所需要链接的库文件(LOCAL_SHARED_LIBRARIES := cutils);
6. 模板文件:所包含的这些模板文件定义了生成目标的类型,同时包含了生成此种目标的编译工具(include $(BUILD_EXECUTABLE))。
- LOCAL_PATH := $(my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := <buil_name>
- LOCAL_SRC_FILES := main.c
- LOCAL_MODULE_TAGS := eng development
- LOCAL_SHARED_LIBRARIES := cutils
- include $(BUILD_EXECUTABLE)
- (HOST_)EXECUTABLE,(HOST_)JAVA_LIBRARY,(HOST_)PREBUILT, (HOST_)SHARED_LIBRARY,(HOST_)STATIC_LIBRARY,PACKAGE,JAVADOC, RAW_EXECUTABLE, RAW_STATIC_LIBRARY,COPY_HEADERS, KEY_CHAR_MAP
LOCAL_PATH := $(my-dir) include $(CLEAR_VARS)
LOCAL_MODULE := <buil_name> LOCAL_SRC_FILES := main.c
LOCAL_MODULE_TAGS := eng development
LOCAL_SHARED_LIBRARIES := cutils include $(BUILD_EXECUTABLE)
(HOST_)EXECUTABLE,(HOST_)JAVA_LIBRARY,(HOST_)PREBUILT,
(HOST_)SHARED_LIBRARY,(HOST_)STATIC_LIBRARY,PACKAGE,JAVADOC, RAW_EXECUTABLE,
RAW_STATIC_LIBRARY,COPY_HEADERS, KEY_CHAR_MAP
Layer |
Example |
Description |
Product |
myProduct, myProduct_eu, myProduct_eu_fr, j2, sdk |
产品层定义了一个产品的详细说明,包括编译的模块和配置。你可以基于一种特定的应用提供一种设备上的几种不同版本。例如,基于摄像技术。 |
Device |
myDevice, myDevice_eu, myDevice_eu_lite |
设备层代表了构建在设备上的物理层。例如,南美的可能包含QWERTY键盘而法国的可能包含AZERTY键盘。连接到设备层的典型外设。 |
Board |
sardine, trout, goldfish |
开发板层代表了一个产品的缩减版。当然你可以连接一些外设上去。 |
Arch |
arm (arm5te) (arm6), x86, 68k |
架构层描述了你目标系统的处理器架构 |
这部分说明如何编译缺省的Android版本。一旦你熟悉了普通的编译过程,你就可以尝试着编译一个能运行在你自己的设备上的Android系统。
为了做一个普通Android编译过程,源码中build/envsetup.sh中包含了一些环境变量和函数定义。例如:
view plain print ?
%cd $Top % . build/envsetup.sh #pick a configuration using choosecombo %choosecombo %make –j4 PRODUCT-generic-user |
通过执行”m clean”来清除你刚编译产生的目标文件。也可以通过”m clobber”来删除所有目标编译的输出文件,也就相当于将整个/out目录删除。
每一个目标系统的编译输出文件都放在/out目录下,每一次编译都会快速的选择目标而不需要重新编译所有源码。
但是如果编译系统没有将改动告诉环境变量或makefile,我们就有必要清除以往的编译结果。如果这种情况经常发生,你就需要定义一个环境变量:
这样做是为了迫使编译系统使用ccache编译器,它能减少源码的重复编译。
ccache编译器源码已经提供(/prebuilt),不需要再次安装。
- % export USE_CCACHE=1
- device Dex: core UNEXPECTED TOP-LEVEL ERROR:
- java.lang.NoSuchMethodError: method java.util.Arrays.hashCode with
- signature ([Ljava.lang.Object;)I was not found.
- at com.google.util.FixedSizeList.hashCode(FixedSizeList.java:66)
- at com.google.rop.code.Rop.hashCode(Rop.java:245)
- at java.util.HashMap.hash(libgcj.so.7)
Dx是一个Java工具,首次出现在java1.5版本中。通过”java -version’检查你的java版本。
如果你有java1.5或者更高版本,你还会遇到这样的错误,检查你的PATH变量。
这部分介绍如何编译Android缺省的内核。一旦你熟悉了普通的Android内核编译,你就可以尝试着去配置你自己的Android驱动。
为了编译内核,选择设备目录(/home/joe/android/device),建立环境变量并且运行:
% . envsetup.sh % partner_setup generic
然后选择内核目录/home/joe/android/kernel.
缺省的代码分支是Android。为了下载不同的分支代码,执行:
- % git checkout --track -b android-mydevice origin/android-mydevice
- //Branch android-mydevice set up to track remote branch
- % refs/remotes/origin/android-mydevice.
- //Switched to a new branch "android-mydevice"
为了简化代码的管理,让你的分支名字和它的主干名字相同。通过执行”git checkout <branchname>”来选择下载的代码分支。
要找出哪一个代码分支存在和哪一个代码分支是可用(标有asterisk),执行:
- % git branch -a
- android
- * android-mydevice
- origin/HEAD
- origin/android
- origin/android-mydevice
- origin/android-mychipset
当我们需要针对目标系统编译时,我们希望在最终版本中如果有几种不同编译选项的镜像。下面有几个编译选项:
eng |
This is the default flavor. A plain make is the same as make eng. Installs modules tagged with: eng, debug, user, and/or development. Installs non-APK modules that have no tags specified. Installs APKs according to the product definition files, in addition to tagged APKs. ro.secure=0 ro.debuggable=1 ro.kernel.android.checkjni=1 adb is enabled by default |
user |
make user This is the flavor intended to be the final release bits. Installs modules tagged with user. Installs non-APK modules that have no tags specified. Installs APKs according to the product definition files; tags are ignored for APK modules. ro.secure=1 ro.debuggable=0 adb is disabled by default. |
userdebug |
make userdebug The same as user, except: Also installs modules tagged with debug. ro.debuggable=1 adb is enabled by default. |
1.1.1配置新产品
如何为你的Android移动设备创建一个makefile?步骤如下:
5. 在/products/目录下,创建一个AndroidProducts.mk文件,用于链接个别产品的makefile文件
- mkdir vendor/<company_name>
- mkdir vendor/<company_name>/products/
- $(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk)
- #
- # Overrides
- PRODUCT_NAME := <first_product_name> k65v1_64_bsp
- PRODUCT_DEVICE := <board_name>
6. 在公司目录下在创建一个目标板的目录,这个目录下的makefile文件可以被运行在目标板的任何一个产品访问到:
7. 在目标板目录下创建一个BoardConfig.mk文件:
view plain print ?
# This file should set PRODUCT_MAKEFILES to a list of product makefiles # to expose to the build system. LOCAL_DIR will already be set to # the directory containing this file. # # This file may not rely on the value of any variable other than # LOCAL_DIR; do not use any conditionals, and do not look up the # value of any variable that isn't set in this file or in a file that # it includes. PRODUCT_MAKEFILES := / $(LOCAL_DIR)/first_product_name.mk / |
8. 如果你想改进系统属性,在<board_name>目录下创建一个system.prop文件:
9. 在products/AndroidProducts.mk中声明<second_product_name>.mk
10. 一个Android.mk文件(/vendor/<company_name>/<board_name>)必须包含以下代码:
view plain print ?
mkdir vendor/<company_name>/<board_name> # These definitions override the defaults in config/config.make for <board_name> # TARGET_NO_BOOTLOADER := false TARGET_USE_GENERIC_AUDIO := true # system.prop for # This overrides settings in the products/generic/system.prop file # rild.libpath=/system/lib/libreference-ril.so # rild.libargs=-d /dev/ttyS0 |
11. 对于同一个目标板的第二个产品,创建第二个makefile文件 vendor /companyname/product/<second_product_name>.mk:
view plain print ?
PRODUCT_MAKEFILES := / $(LOCAL_DIR)/first_product_name.mk / $(LOCAL_DIR)/second_product_name.mk # make file for new hardware from LOCAL_PATH := $(call my-dir) # this is here to use the pre-built kernel ifeq ($(TARGET_PREBUILT_KERNEL),) TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel endif file := $(INSTALLED_KERNEL_TARGET) ALL_PREBUILT += $(file) $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP) $(transform-prebuilt-to-target) # no boot loader, so we don't need any of that stuff.. LOCAL_PATH := vendor/<company_name>/<board_name> include $(CLEAR_VARS) # include more board specific stuff here? Such as Audio parameters. |
现在,你就有了两个产品,<first_product_name>and<second_product_name>。为了验证一个新的产品是否被成功配置,执行:
编译后,你就会发现产生了一个新的目录/out/target/product/<board_name>。
- ||--<company_name>
- |--<board_name>
- Android.mk
- poduct_config.mk
- system.prop
- |--<products>
- AndroidProducts.mk
- <first_product_name>.mk
- <second_product_name>.mk
产品的属性变量就定义在产品变量定义文件中。一个产品的变量定义文件可以从其他产品继承,这样就可以减少不必要的复制和易于代码维护。
view plain print ?
$(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk) # # Overrides PRODUCT_NAME := <second_product_name> PRODUCT_DEVICE := <board_name> . build/envsetup.sh make PRODUCT-<first_product_name>-user |
Parameter |
Description |
Example |
PRODUCT_NAME |
End-user-visible name for the overall product. Appears in the "About the phone" info |
|
PRODUCT_MODEL |
End-user-visible name for the end product |
|
PRODUCT_LOCALS |
A space-separated list of two-letter language code, two-letter country code pairs that describe several settings for the user, such as the UI language and time, date and currency formatting. The first locale listed in PRODUCT_LOCALES is is used if the locale has never been set before. |
en_GB de_DE es_ES fr_CA |
PRODUCT_PACKAGES |
Lists the APKs to install. |
Calendar Contacts |
PRODUCT_DEVICE |
Name of the industrial design |
dream |
PRODUCT_MANUFACTUER |
Name of the manufacturer |
acme |
PRODUCT_BRAND |
The brand (e.g., carrier) the software is customized for, if any |
|
PRODUCT_PROPERTY_OVERRIDES |
List of property assignments in the format "key=value" |
|
PRODUCT_COPY_FILES |
List of words like source_path:destination_path. The file at the source path should be copied to the destination path when building this product. The rules for the copy steps are defined in config/Makefile |
|
PRODUCT_OTA_PUBLIC_KEYS |
List of OTA public keys for the product |
|
PRODUCT_POLICY |
Indicate which policy this product should use |
|
PRODUCT_PACKAGE_OVERLAYS |
Indicate whether to use default resources or add any product specific overlays |
vendor/acme/overlay |
PRODUCT_CONTRIBUTORS_FILE |
HTML file containing the contributors to the project. |
|
PRODUCT_TAGS |
list of space-separated words for a given productb |
1.1.2编译手册
Android编译手册提供简单的实例代码帮助你很快的建立一些普通的编译任务。
- $(call inherit-product, build/target/product/generic.mk)
- #Overrides
- PRODUCT_NAME := MyDevice
- PRODUCT_MANUFACTURER := acme
- PRODUCT_BRAND := acme_us
- PRODUCT_LOCALES := en_GB es_ES fr_FR
- PRODUCT_PACKAGE_OVERLAYS := vendor/acme/overlay
view plain print ?
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage # Tell it to build an APK include $(BUILD_PACKAGE) |
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- # List of static libraries to include in the package
- LOCAL_STATIC_JAVA_LIBRARIES := static-library
- # Build all java files in the java subdirectory
- LOCAL_SRC_FILES := $(call all-subdir-java-files)
- # Name of the APK to build
- LOCAL_PACKAGE_NAME := LocalPackage
- # Tell it to build an APK
- include $(BUILD_PACKAGE)
view plain print ?
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := platform # Tell it to build an APK include $(BUILD_PACKAGE) |
view plain print ?
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Build all java files in the java subdirectory LOCAL_SRC_FILES := $(call all-subdir-java-files) # Name of the APK to build LOCAL_PACKAGE_NAME := LocalPackage LOCAL_CERTIFICATE := vendor/example/certs/app # Tell it to build an APK include $(BUILD_PACKAGE) |
下面是一些Android.mk文件中常见的变量,按字母顺序罗列。首先,注意变量的命名:
LOCAL_-这些变量被设置为单独的每个模块。以”include $(CLEAR_VARS)”为界限,可以通过它清空其他LOCAL_的声明。大多数模块中的变量都是LOCAL_变量;
PRIVATE_-这些变量用来编译特定目标代码。即他们仅用在模块的命令当中。也意味着它不可能作用于定义在当前模块后面的模块;
HOST_和TARGET_-:这些变量包含对HOST和TARGET的说明和定义。在你的makefile文件中不要使用HOST_和TARGET_;
BUILD_和CLEAR_VARS-这些变量包含了模板makefile的名字。
其它的名字你都可以任意使用在你自己的makefile文件中。但是,记住这是一个非递归的编译系统,很可能你的变量会被其它的Android.mk修改,导致你使用的时候它变得不同了。
(表格见http://source.android.com/porting/build_cookbook.html)
1.2密钥文件和数字签名
Android平台要求每个应用程序有密钥文件签名以获取系统权限,这样应用程序就可以获得共享的用户ID或者运行在系统进程当中。Android平台使用四种密钥文件来维护系统的安全性:
·Shard:能分享/home/contacts进程的密钥文件;
·Media:关于media/download中包的密钥文件;
view plain print ?
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # Module name should match apk name to be installed. LOCAL_MODULE := LocalModuleName LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_MODULE_CLASS := APPS LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) include $(BUILD_PREBUILT) |
mkkey.sh是一个产生密钥文件的脚本。注意:你输入的密码在你的终端上是可见的。另外,这些密码是用于数字签名的。
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- # Build all java files in the java subdirectory
- LOCAL_SRC_FILES := $(call all-subdir-java-files)
- # Any libraries that this library depends on
- LOCAL_JAVA_LIBRARIES := android.test.runner
- # The name of the jar file to create
- LOCAL_MODULE := sample
- # Build a static jar file.
- include $(BUILD_STATIC_JAVA_LIBRARY)
这条命令在out/dist目录下创建一个文件<product_name>-target_files.zip。这就是脚本sign_target_files_apks所需要的文件。
如果在编译过程中,有些apk你不想重新签名,你就要在你的命令行中为增加”-e Foo.apk=”。
Sign_target_files_apks有许多其他的命令选项,可以-h查看。
一旦你有了signed-target-files.zip,就可以通过下面命令放到image中:
2.定制
在设备启动过程中,Android会显示一幅图片。如果你希望更改默认的图片:
1. 创建一个320*480的图片(splashscreen.jpg);
- #!/bin/sh
- AUTH='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
- if [ "$1" == "" ]; then
- echo "Create a test certificate key."
- echo "Usage: $0 NAME"
- echo "Will generate NAME.pk8 and NAME.x509.pem"
- echo " $AUTH"
- exit
- fi
- openssl genrsa -3 -out $1.pem 2048
- openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 /
- -subj "$AUTH"
- echo "Please enter the password for this key:"
- openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -passout stdin
为一个产品配置APN,你需要增加一个apns-conf.xml(不需要修改系统缺省的APNs)。这样就可以让不同的产品拥有不同的APNs配置。
为了在产品层次上配置APNs,在vendor/<vendor_name>/products/ myphone-us.mk:
系统运行时,Android从system/etc/apns-conf.xml中读取配置。
自动配置:系统启动时,Android从SIM卡的MCC和MNC中获取的网络配置信心并且自动完成所有配置。
WAP/SMS配置:网络配置是标准的Android资源。你可以通过安装一个新的系统资源APK包来更新网络配置。也可以通过添加一项服务,这项服务可以为SMS(包含网络配置信息)监听SMS端口。
- sh mkkey.sh platform # enter password
- sh mkkey.sh media # enter password
- sh mkkey.sh shared # enter password
- sh mkkey.sh release # enter password
程序包名应该和Android.mk中LOCAL_PACKAGE_NAME名字对应。
view plain print ?
make -j4 PRODUCT-<product_name>-user dist ./build/tools/releasetools/sign_target_files_apks -d vendor/<vendor_name>/security/<product_name> <product_name>-target_files.zip signed-target-files.zip build/tools/releasetools/img_from_target_files signed-target-files.zip signed-img.zip convert screen.jpg screen.r Rgb2565 <sceen.rgb> screen.565 |
注意:主屏幕(Launcher.apk)仅仅是一个Android的应用程序,可以通过修改源代码的方式定制自己的HomeScreen。
- Fastboot flash splash1 screen.565
- <apn carrier="T-Mobile US"
- mcc="310"
- mnc="260"
- apn=" wap.voicestream.com"
- user="none"
- server="*"
- password="none"
- proxy=" 216.155.165.50"
- port="8080"
- mmsc="http://216.155.174.84/servlets/mms"
- />
缺省的email Provider设置存储在//android/packages/apps/Email/res/xml/ providers.xml:
- PRODUCT_COPY_FILES := vendor/acme/etc/apns-conf-us.xml:system/etc/apns-conf.xml
- PRODUCT_PACKAGES := /
- <company_name>Mail /
- <company_name>IM /
- <company_name>HomeScreen /
- <company_name>Maps /
- <company_name>SystemUpdater
平台主题和风格在//android/framework/base/core/res/res/values/styles.xml中。
Android提供了一些窗口和视图变换的动画。系统的动画放在:
//android/framework/base/core/res/res/anim中。
Android平台开发指导(Android Porting Guide)相关推荐
- 基于Android平台开发的手电筒Light
基于Android平台开发的手电筒Light 1. 需求分析: 在现代社会中,手机的功能越来越完善,手电筒就是这些功能中必不可少的一种.当行走在漆黑的道路上,当你在黑暗狭小的地方寻找物品,当你 ...
- 【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )
文章目录 I . CMake 简介 II . Android Studio 中 CMake 引入静态库流程 III . 指定 CMake 最小版本号 IV . 导入函数库 ( 静态库 / 动态库 ) ...
- 【Android FFMPEG 开发】Android 中使用 FFMPEG 对 MP3 文件进行混音操作
文章目录 一.前置操作 ( 移植 FFMPEG ) 二.FFMPEG 混音命令 三.Android FFMPEG 混音源代码完整示例 四.博客源码 一.前置操作 ( 移植 FFMPEG ) 参考 [A ...
- 【Android FFMPEG 开发】Android Studio 工程配置 FFMPEG ( 动态库打包 | 头文件与函数库拷贝 | CMake 脚本配置 )
文章目录 I . FFMPEG 交叉编译后的函数库及头文件 II . FFMPEG 静态库打包动态库 ( 仅做参考 ) III . 创建 Android Studio 工程 IV . FFMPEG 头 ...
- 【Android NDK 开发】Android Studio 使用 CMake 导入动态库 ( 构建脚本路径配置 | 指定动态库查找路径 | 链接动态库 )
文章目录 I . CMake 引入动态库与静态库区别 II . Android Studio 中 CMake 引入动态库流程 III . 指定动态库查找路径 IV . 链接函数库 V . 完整代码示例 ...
- 【Android NDK 开发】Android.mk 配置静态库 ( Android Studio 配置静态库 | 配置动态库与静态库区别 | 动态库与静态库打包对比 )
文章目录 I . Android Studio 中使用 Android.mk 配置静态库 总结 II . 第三方动态库来源 III . 配置 Android.mk 构建脚本路径 IV . 预编译 第三 ...
- 【Android NDK 开发】Android.mk 配置动态库 ( Android Studio 配置动态库 | 动态库加载版本限制 | 本章仅做参考推荐使用 CMake 配置动态库 )
文章目录 I . Android Studio 中使用 Android.mk 配置动态库 总结 II . 第三方动态库来源 III . 配置 Android.mk 构建脚本路径 IV . 预编译 第三 ...
- 【Android NDK 开发】Android Studio 的 NDK 配置 ( 源码编译配置 | 构建脚本配置 | 打包配置 | CMake 配置 | ndkBuild 配置 )
文章目录 I . 源码编译配置 II . 构建脚本配置 III . NDK 函数库打包配置 IV . Java 与 C 代码示例 V . CMake 配置 ( CMakeLists.txt ) VI ...
- android基础开发 书,Android 开发基础
(一)认识Android Studio Android Studio 是谷歌推出的一个Android集成开发工具,Android Studio 提供了集成的 Android 开发工具用于开发和调试. ...
最新文章
- python之multiprocessing创建进程
- git http仓库账号密码缓存至本地:不用每次git push都需要输入密码的方法(类似于windows的凭据管理)
- 118. Pascal's Triangle
- [Codeforces702F]T-Shirts——非旋转treap+贪心
- 光纤收发器相比其他数据交换器有哪些优势?
- 菜鸟读jQuery 2.0.3 源码分析系列(1)
- python导入文件-如何导入其他Python文件?
- MySQL默认库可以删_个人总结:Sql(一:创建删除修改库表||附:mysql数据类型及默认值)...
- eclipse 改java版本_修改eclipse工程jdk版本
- 利用PLC1200和elmo驱动器对maxon RE40电机的两种控制方式(PWM(PTO)或者模拟量控制)
- 深入FM和FFM原理与实践
- word封面下划线对齐
- php 连接新浪云mysql_将php代码部署到新浪云测试(简单方法,包含数据库的连接)...
- 开机提示grub可咋办啊
- 手机参数中的4+64G到底是什么?
- 苹果屏幕尺寸_iPhone 12屏幕维修价格出炉,买得起伤不起?
- parted扩展磁盘分区(实践篇)
- 物联网概念火热,靠技术如何落地?
- 显示商品分类列表页面
- html圆角边框怎么做,CSS圆角边框制作指南与实例