如何修改AOSP以加入自己的设备,应用,工具等

觉得这个网文写得不错,英文的。虽然作者实验的版本有点低,但应该还是很有参考价值的。 http://my.safaribooksonline.com/book/programming/android/9781449327958/4dot-the-build-system/i_sect14_id404209_html

 

将原文拷贝如下。

Basic AOSP Hacks

You most likely bought this book with one thing in mind: to hack the AOSP to fit your needs. Over the next few pages, we’ll start looking into some of the most obvious hacks you’ll likely want to try. Of course we’re only setting the stage here with the parts that pertain to the build system, which is where you’ll likely want to start anyway.

NOTE

While the following explanations are based on 2.3/Gingerbread, they’ll work just the same on 4.2/Jelly Bean, and likely many versions after that one, too. The fact is, these mechanisms have been constant for quite some time. Still, where relevant, changes in 4.2/Jelly Bean are highlighted.

Adding a Device

Adding a custom device is most likely one of the topmost items (if not the topmost) on your list of reasons for reading this book. I’m about to show you how to do just that, so you’ll likely want to bookmark this section. Of course I’m actually only showing you the build aspects of the work. There are a lot more steps involved in porting Android to new hardware. Still, adding the new device to the build system will definitely be one of the first things you do. Fortunately, doing that is relatively straightforward.

For the purposes of the current exercise, assume you work for a company called ACME and that you’re tasked with delivering its latest gizmo: the CoyotePad, intended to be the best platform for playing all bird games. Let’s get started by creating an entry for our new device in device/:

$ cd ~/android/aosp-2.3.x
$ . build/envsetup.sh
$ mkdir -p device/acme/coyotepad
$ cd device/acme/coyotepad

The first thing we’ll need in here is an AndroidProducts.mk file to describe the various AOSP products that could be built for the CoyotePad:

PRODUCT_MAKEFILES := \
    $(LOCAL_DIR)/full_coyotepad.mk

While we could describe several products (see build/target/product/AndroidProducts.mk for an example), the typical case is to specify just one, as in this case, and it’s described in full_coyotepad.mk:

$(call inherit-product, $(SRC_TARGET_DIR)/product/languages_full.mk)
# If you're using 4.2/Jelly Bean, use full_base.mk instead of full.mk
$(call inherit-product, $(SRC_TARGET_DIR)/product/full.mk)

DEVICE_PACKAGE_OVERLAYS :=

PRODUCT_PACKAGES +=
PRODUCT_COPY_FILES +=

PRODUCT_NAME := full_coyotepad
PRODUCT_DEVICE := coyotepad
PRODUCT_MODEL := Full Android on CoyotePad, meep-meep

It’s worth taking a closer look at this makefile. First, we’re using the inherit-product function to tell the build system to pull in other product descriptions as the basis of ours. This allows us to build on other people’s work and not have to specify from scratch every bit and piece of the AOSP that we’d like to include.languages_full.mk will pull in a vast number of locales, and full.mk will make sure we get the same set of modules as if we had built using the full-eng combo.

With regard to the other variables:

DEVICE_PACKAGE_OVERLAYS

Allows us to specify a directory that will form the basis of an overlay that will be applied onto the AOSP’s sources, thereby allowing us to substitute default package resources with device-specific resources. You’ll find this useful if you’d like to set custom layouts or colors for Launcher2 or other apps, for instance. We’ll look at how to use this in the next section.

PRODUCT_PACKAGES

Allows us to specify packages we’d like to have this product include in addition to those specified in the products we’re already inheriting from. If you have custom apps, binaries, or libraries located within device/acme/coyotepad/, for instance, you’ll want to add them here so that they are included in the final images generated. Notice the use of the += sign. It allows us to append to the existing values in the variable instead of substituting its content.

PRODUCT_COPY_FILES

Allows us to list specific files we’d like to see copied to the target’s filesystem and the location where they need to be copied. Each source/destination pair is colon-separated, and pairs are space-separated among themselves. This is useful for configuration files and prebuilt binaries such as firmware images or kernel modules.

PRODUCT_NAME

The TARGET_PRODUCT, which you can set either by selecting a lunch combo or passing it as part of the combo parameter to lunch, as in:

$ lunch full_coyotepad-eng
PRODUCT_DEVICE

The name of the actual finished product shipped to the customer. TARGET_DEVICE derives from this variable. PRODUCT_DEVICE has to match an entry in device/acme/, since that’s where the build looks for the corresponding BoardConfig.mk. In this case, the variable is the same as the name of the directory we’re already in.

PRODUCT_MODEL

The name of this product as provided in the “Model number” in the “About the phone” section of the settings. This variable actually gets stored as the ro.product.model global property accessible on the device.

Version 4.2/Jelly Bean also includes a PRODUCT_BRAND that is typically set to Android. The value of this variable is then available as the ro.product.brand global property. The latter is used by some parts of the stack that take action based on the device’s vendor.

Now that we’ve described the product, we must also provide some information regarding the board the device is using through a BoardConfig.mk file:

TARGET_NO_KERNEL := true
TARGET_NO_BOOTLOADER := true
TARGET_CPU_ABI := armeabi
BOARD_USES_GENERIC_AUDIO := true

USE_CAMERA_STUB := true

This is a very skinny BoardConfig.mk and ensures that we actually build successfully. For a real-life version of that file, have a look at device/samsung/crespo/BoardConfigCommon.mk in 2.3/Gingerbread, and also at device/asus/grouper/BoardConfigCommon.mk in 4.2/Jelly Bean.

You’ll also need to provide a conventional Android.mk in order to build all the modules that you might have included in this device’s directory:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

ifneq ($(filter coyotepad,$(TARGET_DEVICE)),)
include $(call all-makefiles-under,$(LOCAL_PATH))
endif

It’s in fact the preferred modus operandi to put all device-specific apps, binaries, and libraries within the device’s directory instead of globally within the rest of the AOSP. If you do add modules here, don’t forget to also add them to PRODUCT_PACKAGES as I explained earlier. If you just put them here and provide them validAndroid.mk files, they’ll build, but they won’t be in the final images.

If you have several products sharing the same set of packages, you may want to create a device/acme/common/ directory containing the shared packages. You can see an example of this in 4.2/Jelly Bean’s device/generic/ directory. In that same version, you can also check how device/samsung/maguro/device.mk inherits fromdevice/samsung/tuna/device.mk for an example of how one device can be based on another device.

Lastly, let’s close the loop by making the device we just added visible to envsetup.sh and lunch. To do so, you’ll need to add a vendorsetup.sh in your device’s directory:

add_lunch_combo full_coyotepad-eng

You also need to make sure that it’s executable if it’s to be operational:

$ chmod 755 vendorsetup.sh

We can now go back to the AOSP’s root and take our brand-new ACME CoyotePad for a runchase:

$ croot
$ . build/envsetup.sh
$ lunch

You're building on Linux

Lunch menu... pick a combo:
     1. generic-eng
     2. simulator
     3. full_coyotepad-eng
     4. full_passion-userdebug
     5. full_crespo4g-userdebug
     6. full_crespo-userdebug

Which would you like? [generic-eng] 3

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.3.4
TARGET_PRODUCT=full_coyotepad
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=GINGERBREAD
============================================

$ make -j16

As you can see, the AOSP now recognizes our new device and prints the information correspondingly. When the build is done, we’ll also have the same type of output provided in any other AOSP build, except that it will be a product-specific directory:

$ ls -al out/target/product/coyotepad/
total 89356
drwxr-xr-x  7 karim karim     4096 2011-09-21 19:20 .
drwxr-xr-x  4 karim karim     4096 2011-09-21 19:08 ..
-rw-r--r--  1 karim karim        7 2011-09-21 19:10 android-info.txt
-rw-r--r--  1 karim karim     4021 2011-09-21 19:41 clean_steps.mk
drwxr-xr-x  3 karim karim     4096 2011-09-21 19:11 data
-rw-r--r--  1 karim karim    20366 2011-09-21 19:20 installed-files.txt
drwxr-xr-x 14 karim karim     4096 2011-09-21 19:20 obj
-rw-r--r--  1 karim karim      327 2011-09-21 19:41 previous_build_config.mk
-rw-r--r--  1 karim karim  2649750 2011-09-21 19:43 ramdisk.img
drwxr-xr-x 11 karim karim     4096 2011-09-21 19:43 root
drwxr-xr-x  5 karim karim     4096 2011-09-21 19:19 symbols
drwxr-xr-x 12 karim karim     4096 2011-09-21 19:19 system
-rw-------  1 karim karim 87280512 2011-09-21 19:20 system.img
-rw-------  1 karim karim  1505856 2011-09-21 19:14 userdata.img

Also, have a look at the build.prop file in system/. It contains various global properties that will be available at runtime on the target and that relate to our configuration and build:

# begin build properties
# autogenerated by buildinfo.sh
ro.build.id=GINGERBREAD
ro.build.display.id=full_coyotepad-eng 2.3.4 GINGERBREAD eng.karim.20110921.1908
49 test-keys
ro.build.version.incremental=eng.karim.20110921.190849
ro.build.version.sdk=10
ro.build.version.codename=REL
ro.build.version.release=2.3.4
ro.build.date=Wed Sep 21 19:10:04 EDT 2011
ro.build.date.utc=1316646604
ro.build.type=eng
ro.build.user=karim
ro.build.host=w520
ro.build.tags=test-keys
ro.product.model=Full Android on CoyotePad, meep-meep
ro.product.brand=generic
ro.product.name=full_coyotepad
ro.product.device=coyotepad
ro.product.board=
ro.product.cpu.abi=armeabi
ro.product.manufacturer=unknown
ro.product.locale.language=en
ro.product.locale.region=US
ro.wifi.channels=
ro.board.platform=
# ro.build.product is obsolete; use ro.product.device
ro.build.product=coyotepad
# Do not try to parse ro.build.description or .fingerprint
ro.build.description=full_coyotepad-eng 2.3.4 GINGERBREAD eng.karim.20110921.190
849 test-keys
ro.build.fingerprint=generic/full_coyotepad/coyotepad:2.3.4/GINGERBREAD/eng.kari
m.20110921.190849:eng/test-keys
# end build properties
...

WARNING

You may want to carefully vet the default properties before using the build on a real device. Some developers have encountered some severe issues due to default values. In both 2.3/Gingerbread and 4.2/Jelly Bean, for instance, ro.com.android.dataroaming is set to true in some builds. Hence, if you’re doing development on a device connected to a live cell network, changing the value to false might save you some money.

As you can imagine, there’s a lot more to be done here to make sure the AOSP runs on our hardware. But the preceding steps give us the starting point. However, by isolating the board-specific changes in a single directory, this configuration will simplify adding support for the CoyotePad to the next version of the AOSP that gets released. Indeed, it’ll just be a matter of copying the corresponding directory to the new AOSP’s device/ directory and adjusting the code therein to use the new APIs.

Adding an App

Adding an app to your board is relatively straightforward. As a starter, try creating a HelloWorld! app with Eclipse and the default SDK; all new Android projects in Eclipse are a HelloWorld! by default. Then copy that app from the Eclipse workspace to its destination:

$ cp -a ~/workspace/HelloWorld ~/android/aosp-2.3.x/device/acme/coyotepad/

You’ll then have to create an Android.mk file in aosp-root/device/acme/coyotepad/HelloWorld/ to build that app:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := HelloWorld

include $(BUILD_PACKAGE)

Given that we’re tagging this module as optional, it won’t be included by default in the AOSP build. To include it, you’ll need to add it to the PRODUCT_PACKAGES listed in the CoyotePad’s full_coyotepad.mk.

If, instead of adding your app for your board only, you would like to add a default app globally to all products generated by the AOSP alongside the existing stock apps, you’ll need to put it in packages/apps/ instead of your board’s directory. You’ll also need to modify one of the built-in .mk files, such as aosp-root/build/target/product/core.mk, to have your app built by default. This is not recommended, though, as it’s not very portable since it will require you to make this modification to every new AOSP release. As I stated earlier, it’s best to keep your custom modifications in device/acme/coyotepad/ in as much as possible.

Adding an App Overlay

Sometimes you don’t actually want to add an app but would rather modify existing ones included by default in the AOSP. That’s what app overlays are for. Overlays are a mechanism included in the AOSP to allow device manufacturers to change the resources provided (such as for apps), without actually modifying the original resources included in the AOSP. To use this capability, you must create an overlay tree and tell the build system about it. The easiest location for an overlay is within a device-specific directory such as the one we created in the previous section:

$ cd device/acme/coyotepad/
$ mkdir overlay

To tell the build system to take this overlay into account, we need to modify our full_coyotepad.mk such that:

DEVICE_PACKAGE_OVERLAYS := device/acme/coyotepad/overlay

At this point, though, our overlay isn’t doing much. Let’s say we want to modify some of Launcher2’s default strings. We could then do something like this:

$ mkdir -p overlay/packages/apps/Launcher2/res/values
$ cp aosp-root/packages/apps/Launcher2/res/values/strings.xml \
> overlay/packages/apps/Launcher2/res/values/

You can then trim your local strings.xml to override only those strings that you need. Most importantly, your device will have a Launcher2 that has your custom strings, but the default Launcher2 will still have its original strings. So if someone relies on the same AOSP sources you’re using to build for another product, they’ll still get the original strings. You can, of course, replace most resources like this, including images and XML files. So long as you put the files in the same hierarchy as they are found in the AOSP but within device/acme/coyotepad/overlay/, they’ll be taken into account by the build system.

WARNING

Overlays can be used only for resources. You can’t overlay source code. If you want to customize parts of Android’s internals, for instance, you’ll still have to make those modifications in situ. There’s no way, currently at least, to isolate those changes to your board.

Adding a Native Tool or Daemon

Like the example above of adding an app for your board, you can add your custom native tools and daemons as subdirectories of device/acme/coyotepad/. Obviously, you’ll need to provide an Android.mk in the directory containing the code to build that module:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := hello-world
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := hello-world.cpp
LOCAL_SHARED_LIBRARIES := liblog

include $(BUILD_EXECUTABLE)

As in the app’s case, you’ll also need to make sure hello-world is part of the CoyotePad’s PRODUCT_PACKAGES.

If you intend to add your binary globally for all product builds instead of just locally to your board, you need to know that there are a number of locations in the tree where native tools and daemons are located. Here are the most important ones:

system/core/ and system/

Custom Android binaries that are meant to be used outside the Android Framework or are standalone pieces.

frameworks/base/cmds/

Binaries that are tightly coupled to the Android Framework. This is where the Service Manager and installd are found, for example.

external/

Binaries that are generated by an external project that is imported into the AOSP. strace, for instance, is here.

Having identified from the list above where the code generating your binary should go, you’ll also need to add it as part of one of the global .mk files such as aosp-root/build/target/product/core.mk. As I said above, however, such global additions are not recommended since they can’t be transferred as easily to newer AOSP versions.

Adding a Native Library

Like apps and binaries, you can also add native libraries for your board. Assuming, as above, that the sources to build the library are in a subdirectory of device/acme/coyotepad/, you’ll need an Android.mk to build your library:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := libmylib
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_SRC_FILES := $(call all-c-files-under,.)

include $(BUILD_SHARED_LIBRARY)

NOTE

Note that LOCAL_PRELINK_MODULE has been removed and is no longer necessary as of 4.0/Ice-Cream Sandwich.

To use this library, you must add it to the libraries listed by the Android.mk file of whichever binaries depend on it:

LOCAL_SHARED_LIBRARIES := libmylib

You’ll also likely need to add relevant headers to an include/ directory located in about the same location as you put your library, so that the code that needs to link against your library can find those headers, such as device/acme/coyotepad/include/.

Should you want to make your library apply globally to all AOSP builds, not just your device, you’ll need a little bit more information regarding the various locations where libraries are typically found in the tree. First, you should know that, unlike binaries, a lot of libraries are used within a single module but nowhere else. Hence, these libraries will typically be placed within that module’s code and not in the usual locations where libraries used systemwide are found. The latter are typically in the following locations:

system/core/

Libraries used by many parts of the system, including some outside the Android Framework. This is where liblog is, for instance.

frameworks/base/libs/

Libraries intimately tied to the framework. This is where libbinder is.

frameworks/native/libs/

In 4.2/Jelly Bean, many libraries that were in frameworks/base/libs/ in 2.3/Gingerbread have been moved out and into frameworks/native/libs/.

external/

Libraries generated by external projects imported into the AOSP. OpenSSL’s libssl is here.

Similarly, instead of using a CoyotePad-specific include directory, you’d use a global directory such as system/core/include/ or frameworks/base/include/ or, in 4.2/Jelly Bean, frameworks/base/include/. Again, as stated earlier, you should carefully review whether such global additions are truly required, as they’ll represent additional work when you try to port for your device to the next version of Android.

LIBRARY PRELINKING

If you look closely at the example Android.mk we provide for the library, you’ll notice a LOCAL_PRELINK_MODULE variable. To reduce the time it takes to load libraries, Android versions up to 2.3/Gingerbread used to prelink most of their libraries. Prelinking is done by specifying ahead of time the address location where the library will be loaded instead of letting it be figured out at runtime. The file where the addresses are specified in 2.3/Gingerbread is build/core/prelink-linux-arm.map, and the tool that does the mapping is called apriori. It contains entries such as these:

# core system libraries
libdl.so                0xAFF00000 # [<64K]
libc.so                 0xAFD00000 # [~2M]
libstdc++.so            0xAFC00000 # [<64K]
libm.so                 0xAFB00000 # [~1M]
liblog.so               0xAFA00000 # [<64K]
libcutils.so            0xAF900000 # [~1M]
libthread_db.so         0xAF800000 # [<64K]
libz.so                 0xAF700000 # [~1M]
libevent.so             0xAF600000 # [???]
libssl.so               0xAF400000 # [~2M]
...
# assorted system libraries
libsqlite.so            0xA8B00000 # [~2M]
libexpat.so             0xA8A00000 # [~1M]
libwebcore.so           0xA8300000 # [~7M]
libbinder.so            0xA8200000 # [~1M]
libutils.so             0xA8100000 # [~1M]
libcameraservice.so     0xA8000000 # [~1M]
libhardware.so          0xA7F00000 # [<64K]
libhardware_legacy.so   0xA7E00000 # [~1M]
...

If you want to add a custom native library to 2.3/Gingerbread, you need to either add it to the list of libraries in prelink-linux-arm.map or set the LOCAL_PRELINK_MODULE to false. The build will fail if you forget to do one of these.

Library prelinking was dropped starting in 4.0/Ice-Cream Sandwich.



[18If you do not provide a value, defaults will be used. For instance, all apps are set to optional by default. Also, some modules are part of GRANDFATHERED_USER_MODULES in user_tags.mk. No LOCAL_MODULE_TAGS need be specified for those; they’re always included.

[19This file contains a set list of variables starting with the string LOCAL_. If a variable isn’t specifically listed in this file, it won’t be taken into account by CLEAR_VARS.

[20This version is cleaned up a little (removed commented code, for instance) and slightly reformatted.

[21Also slightly modified to remove white space and comments.

[22This assumes you had already run envsetup.sh and lunch.

[23This makefile is inspired by a blog post by Row Boat developer Amit Pundir and is based on the example makefile provided in Chapter 4 of Building Embedded Linux Systems, 2nd ed. (O’Reilly).

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值