当前位置: 代码迷 >> Android >> Android平台开发指点(Android Porting Guide)(一)
  详细解决方案

Android平台开发指点(Android Porting Guide)(一)

热度:169   发布时间:2016-05-01 18:17:48.0
Android平台开发指导(Android Porting Guide)(一)

Android平台开发指导(Android Porting Guide)(一)
2011年02月24日
  没有比这 http://www.netmite.com/android/mydroid/development /pdk/docs/index.html 更官方的android开发指导材料了,闲着无事就翻译了。
  本文为Android平台开发人员和Android设备制造商提供了底层开发指导。如果你对Android的上层应用开发很感兴趣,请访问Android Developers Site
  关于这份指导书
  这份指导书按照逻辑划分为几个部分(见目录)。在一个持续的开发过程中,Android是一个复杂的工程项目,随着版本和API的改变,这份指导书将会不断更新。
  至使用者
  对于精通嵌入式Linux的工程师而言,这本书非常有价值。但是,它的重点并不在普通的嵌入式Linux开发,而是更多提供Android平台的特色。
  初学Android
  对于初识Android的人而言,建议阅读以下文档:
  Android Develop site:这个网页提供了高版本的SDK文档;
  Android Open Source Project site:这个网页指导你如何获取源代码,建立开发环境和从事简单的工程开发。
  如果你准备在你的目标系统上定制和移植Android系统,请阅读系统编译概述。 Android用一个定制的编译系统产生一系列工具,编译文件和文档。这一小节概述了Android编译系统和如何建立一个简单的编译环境。
  Android的编译系统是以GNU Make为基础,并且要求最新的版本(注意:Android所使用的最新的GNU Make规则可能并不会出现在GNU Make的网页上)。在开始之前,首先通过"make  -v"检查下你的编译环境的版本。如果你不是3.80或者更高版本的话,你需要升级你的GNU Make版本。
  理解makefile
  makefile文件定义了如何去建立一个系统的编译规则。典型的makefile包含以下一些元素: 1. 名称:为你的编译目标取一个名称(LOCAL_MODULE := );
  2. 局部变量:用CLEAR_VARS清除局部变量(include $ (CLESR_VARS));
  3. 所需要编译的文件:注明你的目标需要链接哪些源文件(LOCAL_SRC_FILES := main.c);
  4. 标记:编译选项(LOCAL_MODULE_TAGS := eng development);
  5. 库:定义你的目标所需要链接的库文件(LOCAL_SHARED_LIBRARIES := cutils);
  6. 模板文件:所包含的这些模板文件定义了生成目标的类型,同时包含了生成此种目标的编译工具(include $(BUILD_EXECUTABLE))。
  下面一段代码举例说明一个典型的makefileLOCAL_PATH := $(my-dir) include $(CLEAR_VARS) LOCAL_MODULE :=  LOCAL_SRC_FILES := main.c LOCAL_MODULE_TAGS := eng development LOCAL_SHARED_LIBRARIES := cutils include $(BUILD_EXECUTABLE) (HOST_)EXECUTABLE,(HOST_)JAVA_LIBRARY,(HOST_)PREBU ILT, (HOST_)SHARED_LIBRARY,(HOST_)STATIC_LIBRARY,PACKAG E,JAVADOC, RAW_EXECUTABLE, RAW_STATIC_LIBRARY,COPY_HEADERS, KEY_CHAR_MAP 
  为了提高代码的可读性,上面这段代码中包含了一些的书写风格。
  Layers
  下表描述了编译系统所包含的抽象层。
  每一个抽象层都是以一对多的关系和上面一层相关。例如,一种处理器架构可以运行在很多种目标板上,而每一个目标板又有很多设备。你可以在给定的抽象层上定义一个元素作为同一层元素的一个特例,这样就避免了复制和简化了维护。 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系统。
  设备编码
  为了做一个普通Android编译过程,源码中build/envsetup.sh中包含了一些环境变量和函数定义。例如: 为了一个工程调试编译,你也可以用eng取代user
  这些编译变量随着调试选项和安装包的不同而不同。
    清除编译结果
  通过执行"m  clean"来清除你刚编译产生的目标文件。也可以通过"m clobber"来删除所有目标编译的输出文件,也就相当于将整个/out目录删除。
    加速重新编译
  每一个目标系统的编译输出文件都放在/out目录下,每一次编译都会快速的选择目标而不需要重新编译所有源码。
  但是如果编译系统没有将改动告诉环境变量或makefile,我们就有必要清除以往的编译结果。如果这种情况经常发生,你就需要定义一个环境变量:
  %make  j4 PRODUCT-generic-eng
    这样做是为了迫使编译系统使用ccache编译器,它能减少源码的重复编译。
  ccache编译器源码已经提供(/prebuilt),不需要再次安装。
    问题定位
  下面的错误很可能是由于JAVA版本过低所导致的: % 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(FixedSizeLi st.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内核编译,你就可以尝试着去配置你自己的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 "来选择下载的代码分支。
  分支鉴定
  要找出哪一个代码分支存在和哪一个代码分支是可用(标有asterisk),执行: % git branch -a android * android-mydevice origin/HEAD origin/android origin/android-mydevice origin/android-mychipset 编译内核
  执行:
  % make  j4 
    编译选项
  当我们需要针对目标系统编译时,我们希望在最终版本中如果有几种不同编译选项的镜像。下面有几个编译选项: 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.  创建makefile 如何为你的Android移动设备创建一个makefile?步骤如下: 1. 在//vendor/下,以产品的公司名字创建一个目录
  2. 在公司名字目录下再创建一个产品的目录
  3. 创建一个产品的makefile文件,至少包含以下代码
  4. 将产品特性的变量添加到产品定义文件中
  5. 在/products/目录下,创建一个AndroidProducts.mk文件,用于链接个别产品的makefile文件 mkdir vendor/ mkdir vendor//products/ $(call inherit-product, $(SRC_TARGET_DIR)/product/generic.mk) # # Overrides PRODUCT_NAME :=  PRODUCT_DEVICE :=   6. 在公司目录下在创建一个目标板的目录,这个目录下的makefile文件可以被运行在目标板的任何一个产品访问到:
  7. 在目标板目录下创建一个BoardConfig.mk文件: # 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. 如果你想改进系统属性,在[/b][b]目录下创建一个system.prop文件:
  9. 在products/AndroidProducts.mk中声明.mk
  10. 一个Anroid.mk文件(/vendor//)必须包含以下代码: 11. 对于同一个目标板的第二个产品,创建第二个makefile文件 vendor /companyname/product/.mkPRODUCT_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// include $(CLEAR_VARS) # include more board specific stuff here? Such as Audio parameters.   现在,你就有了两个产品,and。为了验证一个新的产品是否被成功配置,执行:
    编译后,你就会发现产生了一个新的目录/out/target/product/
  新产品的文件结构树
  在完成了上述步骤之后,在你的系统上你会看到如下目录:
  ||-- |-- Android.mk poduct_config.mk system.prop |-- AndroidProducts.mk .mk .mk 
    产品变量定义文件
  产品的属性变量就定义在产品变量定义文件中。一个产品的变量定义文件可以从其他产品继承,这样就可以减少不必要的复制和易于代码维护。 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 下面举例说明一个典型的产品变量定义文件:
  Android编译手册提供简单的实例代码帮助你很快的建立一些普通的编译任务。
  编译一个简单的APK文件
  编译一个依赖.jar库的APK文件
  $(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
  编译一个需要平台密钥文件签名的APK文件 编译一个需要定制代码密钥文件签名的APK文件
  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) 
  增加一个预编译的APK文件 增加一个静态的JAVAAndroid.mk变量 下面是一些Android.mk文件中常见的变量,按字母顺序罗列。首先,注意变量的命名:
  LOCAL_-这些变量被设置为单独的每个模块。以"include $(CLEAR_VARS)"为界限,可以通过它清空其他LOCAL_的声明。大多数模块中的变量都是LOCAL_变量;
  PRIVATE_-这些变量用来编译特定目标代码。即他们仅用在模块的命令当中。也意味着它不可能作用于定义在当前模块后面的模块;
  HOST_TARGET_-:这些变量包含对HOSTTARGET的说明和定义。在你的makefile文件中不要使用HOST_TARGET_
  BUILD_CLEAR_VARS-这些变量包含了模板makefile的名字。
  其它的名字你都可以任意使用在你自己的makefile文件中。但是,记住这是一个非递归的编译系统,很可能你的变量会被其它的Android.mk修改,导致你使用的时候它变得不同了。
  (表格见http://source.android.com/porting/build_cookbook.h tml介绍 Android平台要求每个应用程序有密钥文件签名以获取系统权限,这样应用程序就可以获得共享的用户ID或者运行在系统进程当中。Android平台使用四种密钥文件来维护系统的安全性:
  .Platform:关于package的平台密钥文件;
  .Shard:能分享/home/contacts进程的密钥文件;
  .Media:关于media/download中包的密钥文件;
  .Releasekey:除上面之外的缺省的密钥文件。
  这些密钥文件为发行的Image文件中的应用获取数字签名,他们并不是编译所需要的。编译系统使用测试密钥文件(build/target/product/security/)进行数字签名。这个测试密钥文件是标准的Android平台的一部分,所以不会被其他平台产品和设备所使用。相应的,设备制造商们会提供他们设备的产品密钥文件。
  创建一个密钥文件
  设备制造商的产品密钥文件应该放在/vendor//security/下面。为了创建一个简单的密钥文件,复制这个目录下的mkkey.sh的脚本。为了定制你自己的密钥文件,修改AUTH这一行,更正你公司的信息: mkkey.sh是一个产生密钥文件的脚本。注意:你输入的密码在你的终端上是可见的。另外,这些密码是用于数字签名的。
  为了产生四种密钥文件,需要运行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)
  这样你就有了自己的产品密钥文件。
  数字签名
  数字签名包含两个步骤: 1. 为需要编译的每个部分进行数字签名;
  2. 签名好后放回Image文件中。 应用程序数字签名
  build/tools/releasetools/sign_target_files_apkstarget_file进行数字签名。缺省情况下target_files不会编译的,所以当你编译是需要明确"dist":
  这条命令在out/dist目录下创建一个文件-target_files.zip。这就是脚本sign_target_files_apks所需要的文件。
  如果在编译过程中,有些apk你不想重新签名,你就要在你的命令行中为增加"-e Foo.apk="。
  Sign_target_files_apks有许多其他的命令选项,可以-h查看。
  创建Image文件
  一旦你有了signed-target-files.zip,就可以通过下面命令放到image中:
  Sign-img.zip包含了所有的image文件。
  启动画面定制
  在设备启动过程中,Android会显示一幅图片。如果你希望更改默认的图片: #!/bin/sh AUTH='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress= [email protected]' 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 网络定制平台
    网络配置
  Android的网络配置信息作为一种资源被编译到目标文件中。它的xml文件在//android/framework/base/core/res/res/xml/apns.xml。这个文件中不包括APNS配置。一般不需要修改,但是在编译的过程中你需要配置APNs
  编译时APN的配置
  为一个产品配置APN,你需要增加一个apns-conf.xml(不需要修改系统缺省的APNs)。这样就可以让不同的产品拥有不同的APNs配置。
  为了在产品层次上配置APNs,在vendor//products/ myphone-us.mk:
  系统运行时APN配置
  系统运行时,Androidsystem/etc/apns-conf.xml中读取配置。
  Android提供下面几种运行时的网络配置:
  自动配置:系统启动时,AndroidSIM卡的MCCMNC中获取的网络配置信心并且自动完成所有配置。
  手动配置:Android平台也支持运行时用户手动配置。
  WAP/SMS配置:网络配置是标准的Android资源。你可以通过安装一个新的系统资源APK包来更新网络配置。也可以通过添加一项服务,这项服务可以为SMS(包含网络配置信息)监听SMS端口。 
  定制预加载的应用程序
  为产品定制应用程序开发包(包括applicationinputmethodsprovidersservices等),需要在产品配置(product configuration)中设置PRODUCT_PACKAGES
  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.mkLOCAL_PACKAGE_NAME名字对应。
    例如:某个Android.mk文件: 注意:主屏幕(Launcher.apk)仅仅是一个Android的应用程序,可以通过修改源代码的方式定制自己的HomeScreen
  定制浏览器书签
  浏览器书签存储在Brower应用程序的string资源当中://android/packages/ apps/Brower/res/values/strings.xml。书签被定义为一个简单的字符串数组(bookmarks),第一部分代表他的书签名,第二部分代表他的URLAndroid在平台配置的基础上交替下载Like和应用程序资源。为了给一个特定的移动网络配置书签,请将你的strings.xml放在Mobile Network Code的资源文件夹下面。例如,Brower/res/values-mccXXX-mncYYY/strings.xml,其中XXXYYY就代表MCCMNC的值。
  EmailProvider定制
  缺省的email Provider设置存储在//android/packages/apps/Email/res/xml/ providers.xml: Android会在平台配置的基础上交替加载所有的应用程序资源。给一个特定的移动网络配置email Provider,你需要见provider.xml放在Mobile Network Code的资源文件下。例如,Email/res/xml-mccXXX-mnxYYY/providers.xml
   平台主题
  平台主题和风格在//android/framework/base/core/res/res/values/style s.xml中。
  动画
  Android提供了一些窗口和视图变换的动画。系统的动画放在:
  //android/framework/base/core/res/res/anim中。
  相关解决方案