移植Android3.0 SDKfreescale imx51_bbg总结

因为以前没有接触过Android系统,所以刚开始的时候对Android系统做了些了解。

Android平台由应用、应用框架、Android运行时、库以及Linux内核五部分组成。

Android的代码结构如下:

|--Makefile 全局的Makefile

|--bionic Bionic含义为仿生,这里面是一些基础的库的源文件

|--bootloader 引导加载器

|--build build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具

|--dalvil java虚拟机

|--development 程序开发所需要的模板和工具

|--external 目标机器使用的一些库

|--frameworks 应用程序的框架层

|--hardware 与硬件相关的库

|--kernel_imx Linux2.6的源代码

|--packages Android的各种应用程序

|--prebuilt Android的各种平台下编译的预制脚本

|--system Android的底层的一些库

拿到代码后需要先对代码打补丁,打了r10的补丁。对照r10的文档对源码进行编译,依次编译出uboot、uImage然后还有Android系统的三个镜像ramdisk.img、system.img和userdata.img,下面的三个镜像构成了根文件系统。ramdisk中init程序和init.rcinit.xxxx.rc两个启动脚本,完成Android的初始化。

对代码进行编译的时候出现了错误

You are attempting to build on a 32-bit system.

Only 64-bit build environments are supported beyond froyo/2.2

在网上找到这是Android Froyo2.2版本基于32 bit系统的一个问题,默认需要64位机去编译,如果需要32位机去编译的话需要更改一些代码,更改情况如下:

(-表示删除行,+表示添加行)

1、修改build/core目录下的main.mk文件,修改策略为:

ifeq ($(BUILD_OS),linux)

build_arch := $(shell uname -m)

-ifneq (64,$(findstring 64,$(build_arch)))

+ifneq (i686,$(findstring i686,$(build_arch)))

$(warning ******************************************)

$(warning You are attempting to build on a 32-bit system.)

$(warning Only 64-bit build environments are supported beyond froyo/2.2.)

2、修改下列文件:

/external/clearsilver/cgi/Android.mk

/external/clearsilver/cs/Android.mk

/external/clearsilver/java-jni/Android.mk

/external/clearsilver/util/Android.mk

4个文件的修改策略相同,为:

# This forces a 64-bit build for Java6

-LOCAL_CFLAGS += -m64

-LOCAL_LDFLAGS += -m64

+LOCAL_CFLAGS += -m32

+LOCAL_LDFLAGS += -m32

有时候还会出现错误 ERROR:Could not load 'clearsilver-jni',解决方法如下

$make clean

$make update-api

$make

编译之前还需要设定ARCH和CROSS_COMPILE

在对源码进行编译的时候不能直接对源码进行make,需要设定product信息,这里有两种方法进行设置:

方法一:在源码根目录下

$ . build/envsetup.sh

$ lunch #这个时候将会出现源码中能够检测到的产品信息

选择一个编号,然后就可以make

$ make

上面第二步和第三步也可以合并成一步,假如对产品信息已经知道了的话

$ lunch imx51_bbg-eng #编译imx51_bbg的时候

$ lunch sdk-eng #编译sdk的时候

方法二:直接在make的时候设定产品信息

$ make PRODUCT-imx51_bbg-eng #编译imx51_bbg的时候

编译出SDK后,可以在emulator模拟器上模拟编译出来的Android系统。

这里有一些命令,使用下面的命令时需要对系统的环境变量进行设置, 修改/etc/environmentAndroidtools文件夹加入到PATH中。

1.android list target 查看有几个有效的target

2.android create avd -n name -t NO. 创建AVD

3.android list avd 查看是否创建成功

4.emulator @ name 启动模拟器

或者可以使用命令 emulator -avd name

emulator -avd name -skin QVGA 选择皮肤

对于新编译出来的sdk,使用android list target找不到会出现任何target的现象,解决方法是进入sdk目录,cp -a platform-tools platforms/android-2.3.1/tools

对于生成的镜像到底里面是什么呢,这个可以从编译输出来的log得到结果,可以看到systrm.img是对同一目录下的system文件夹进行打包的,ramdisk.img是对同一目录下的randisk进行打包的。ramdisk里面只有一些初始化用到的可执行文件和脚本。通过执行init文件来执行对系统的初始化,init的执行即创建了init进程,init进程是由内核启动的一个用户级进程,内核自行启动之后就通过启动一个用户级程序init的方式,来完成引导进程,init始终是第一个进程。

init程序的代码是system/core/init/init.c,在这个进程中首先会解析初始化脚本init.rc [init_parse_config_file("/init.rc");],然后通过get_hardware_name(hardware, &revision); 读取硬件信息,这个函数的定义在system/core/init/util.c中,可以发现它是通过读取"/proc/cpuinfo"中的硬件信息来判断所用平台的。接着解析"/init.%s.rc",这个脚本是解析与硬件平台相关的,模拟器是用的init.goldfish.rc脚本。

init.rc中会启动一系列service,它是通过将service放入service_list中实现的。对分区的挂载也是在init.rc中完成的,这里需要注意挂载分区的格式。

下载镜像有多种方式,可以下到nandflash中,也可以下载sd卡中,让系统从sd卡进行执行,这里我使用的是下载到sd卡方式。需要对镜像进行重定位处理,将地址信息加入到镜像中。同时还需要对sd卡进行正确的分区,并进行格式化,格式化成预定的格式。要使系统能够正常工作,还有一个地方需要注意的,需要在uboot命令行中查看环境变量的设置,设置正确的启动参数。

下面就开始移植了,首先将系统所有镜像下载到板子里面,确保能够正常启动,然后替换成HoneyComb system.img,会发现启动不了,同时出现了错误

EXT4-fs (mmcblk0p2): VFS: Can't find ext4 filesystem

EXT4-fs (mmcblk0p5): recovery complete

EXT4-fs (mmcblk0p5): mounted filesystem with ordered data mode. Opts: (null)

EXT4-fs (mmcblk0p6): recovery complete

EXT4-fs (mmcblk0p6): mounted filesystem with ordered data mode. Opts: (null)

init: cannot find '/system/bin/servicemanager', disabling 'servicemanager'

init: cannot find '/system/bin/vold', disabling 'vold'

init: cannot find '/system/bin/netd', disabling 'netd'

init: cannot find '/system/bin/dispd', disabling 'dispd'

init: cannot find '/system/bin/debuggerd', disabling 'debuggerd'

init: cannot find '/system/bin/app_process', disabling 'zygote'

init: cannot find '/system/bin/mediaserver', disabling 'media'

init: cannot find '/system/bin/dbus-daemon', disabling 'dbus'

init: cannot find '/system/bin/installd', disabling 'installd'

init: cannot find '/system/etc/install-recovery.sh', disabling 'flash_recovery'

init: cannot find '/system/bin/keystore', disabling 'keystore'

init: cannot find '/system/bin/logwrapper', disabling 'wpa_supplicant'

init: cannot find '/system/bin/rild', disabling 'ril-daemon'

init: cannot find '/system/bin/sh', disabling 'console'

出现这样的原因是system并没有挂载上,查看了下init.rc启动脚本,发现是格式问题,sdk生成的镜像是yaffs格式的,而imx51_bbg使用的是ext4格式的镜像,在init.rc中是按照ext4的格式挂载的,挂载脚本如下:

on fs

mount ext4 /dev/block/mmcblk0p2 /system

mount ext4 /dev/block/mmcblk0p2 /system ro remount

mount ext4 /dev/block/mmcblk0p5 /data nosuid nodev

mount ext4 /dev/block/mmcblk0p6 /cache nosuid nodev

sdk中的挂载脚本如下:

on fs

mount yaffs2 [email protected] /system

mount yaffs2 [email protected] /system ro remount

mount yaffs2 [email protected] /data nosuid nodev

mount yaffs2 [email protected] /cache nosuid nodev

对于system.img的打包需要使用make_ext4fs工具,这个工具在out/host目录下生成了,将它拷贝到/usr/bin/目录下以后就可以直接使用了。

$ make_ext4fs -l 128M -a system system.img 目录

yaffs格式镜像解压方法为unyaffs system.imgunyaffs工具需要下载一个代码进行编译生成可执行文件,然后将它拷贝到/usr/bin/下面。

对于ramdisk.img解包和打包的方法有很多种,其中一种比较快捷的方法是

解包 $mkdir ramdisk && cd ramdisk && { zcat ../ramdisk.img |cpio -iv; cd -; }

打包 $cd ramdisk && { find . |cpio -ov -H newc |gzip > ../ramdisk.img; cd -; }

直接转换成uramdisk.img

$cd ramdisk && { find . |cpio -ov -H newc |gzip > ../ramdisk.img; cd -; } && mkimage -A arm -O linux -T ramdisk -C none -a 0x90308000 -n "Android Root Filesystem" -d ./ramdisk.img ./uramdisk.img

将文件格式改变后发现还是不行,一直出现进程挂掉,

untracked pid ** exited

尝试将system下面的binxbin换掉后提示libc.so链接不上,而且还是进不了命令行,然后再将lib文件夹替换掉以后发现可以进入命令行了,但是还是不能进入界面。

然后就开始怀疑是交叉编译链的不同而导致的原因了,因为两种平台的服务器并不相同,模拟器用的是goldfish的虚拟处理器,是基于ARMv5架构的,而imx51_bbgARMv7架构的。这就要到Android的编译系统去查找原因了。

Android的编译系统由build 目录下的代码和其他目录下的Android.mk一起组成,Android Makefile 的引用关系是这样的Makefile -> build/core/main.mk -> build/core/config.mk -> build/core/envsetup.mk -> build/core/product_config.mk,在build/core/product_config.mk 中编译系统首先调用 build/core/product.mk中定义的函数get-all-product-makefiles,来遍历所有的AndroidProducts.mk,不同子目录下的AndroidProducts.mk中定义了不同的 PRODUCT_NAME, PRODUCT_DEVICE 等信息,接着build/core/product_config.mk 会调用resolve-short-product-name TARGET_PRODUCT匹配的AndroidProducts.mk 中定义的 PRODUCT_DEVICE 赋值给TARGET_DEVICE

有了这个TARGET_DEVICE,再回到build/core/config.mk中,有

include $(TARGET_DEVICE)/BoardConfig.mk

board_config_mk:=

$(strip $widcard $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)BoardConfig.mk

Vendor/*/$(TARGET_DEVICE)/BoardConfig.mk))

include $(board_config_mk)

BoardConfig.mk文件决定了目标系统编译属性,而且上面的TARGET_DEVICE还决定了TARGET_DEVICE_DIR

TARGET_DEVICE_DIR:= $(patsubst %/,%,$(dir $board_config_mk)))

Android的目标输出目录也是由由TARGET_DEVICE决定的,在build/core/

envsetup.mk中,设定了各种文件的存放目录。再回到main.mk中,编译系统接着会做的一件事情就是会遍历所有子目录下的Android.mk文件,并且把它们都include进来。

config.mk中,有如下设置

combo_target := HOST_

include $(BUILD_SYSTEM)/combo/select.mk

combo_target := TARGET_

include $(BUILD_SYSTEM)/combo/select.mk

分别对两个平台进行设置,build/core/combo/sselect.mk中有

ifeq ($(TARGET_KERNEL_2G),true)

$(combo_target)PRELINKER_MAP

:= $(BUILD_SYSTEM)/prelink-$(combo_os_arch)-2g.map --------2G/2G方式

else

$(combo_target)PRELINKER_MAP

:= $(BUILD_SYSTEM)/prelink-$(combo_os_arch).map --------3G/1G方式

endif

这边可以看出在这个代码中有两种内存分配方式,一种是2G/2G方式,一种是3G/1G方式,是按照(user/kernel)设置的,这边是对TARGET_KERNEL_2G变量进行判断来分配的,默认是使用3G/1G的方式的。

device/fsl/imx5x/BoardConfigCommon.mk的结尾处有

TARGET_KERNEL_2G := true 设置了BBG用的是2G/2G的内存模型,而SDK中并没有这个设置。

map文件中分别将各种内存地址分配好了,将需要预链接的动态库也映射好了。

如在prelink-linux-arm.map

0xC0000000 - 0xFFFFFFFF Kernel 内核空间1G

0xB0100000 - 0xBFFFFFFF Thread 0 static

0xB0000000 - 0xB00FFFFF Linker

0xA0000000 - 0xBFFFFFFF Prelinked System Libraries

0x90000000 - 0x9FFFFFFF Prelinked App Libraries

0x80000000 - 0x8FFFFFFF Non-prelinked Libraries

0x40000000 - 0x7FFFFFFF mmaps stuff

0x10000000 - 0x3FFFFFFF Thread Stacks

0x00000000 - 0x0FFFFFFF .text / .data / heap

下面还有需要预链接的每个lib库的加载基地址

........................................

所有的动态库默认是需要预链接的,如果一个动态库不需要预链接,需要对其进行设置 LOCAL_PRELINK_MODULE := false,如果新添一个动态库,需要进行预链接,而map文件中没有这个文件的映射关系的话,编译的时候会出错,解决的方法是将其加入到map文件中,而且还要注意内存对齐,分配的内存不能与其它的重叠。

在编译系统总还有一个与TARGET_KERNEL_2G有关系的地方在bionic\linker\

Android.mk

ifeq ($(TARGET_ARCH),sh) ------这个不成立,进入else

LINKER_TEXT_BASE := 0x70000100

else

ifeq ($(TARGET_KERNEL_2G),true)

LINKER_TEXT_BASE := 0x70001000

else

LINKER_TEXT_BASE := 0xB0001000

endif

endif

下面一些linkerFLAGS也就相应的不同了

ifeq ($(TARGET_KERNEL_2G),true)

LOCAL_CFLAGS += -DKERNEL_IS_2G

endif

LINKER_AREA_SIZE := 0x01000000

LOCAL_LDFLAGS := -Wl,-Ttext,$(LINKER_TEXT_BASE)

LOCAL_CFLAGS += -DPRELINK

LOCAL_CFLAGS += -DLINKER_TEXT_BASE=$(LINKER_TEXT_BASE)

LOCAL_CFLAGS += -DLINKER_AREA_SIZE=$(LINKER_AREA_SIZE)

将原本2G/2G模型换成3G/1G模型后,编译,下载生成的Android 系统镜像,发现不能进入命令行,查看kernel的配置文件,发现kernel中也有关于虚拟内存的配置选项

# CONFIG_VMSPLIT_3G is not set

CONFIG_VMSPLIT_2G =y

# CONFIG_VMSPLIT_1G is not set

原本是2G的,VMSPLIT是虚拟内存分配的意思,这个配置选项有点不够明确,不知道是用户空间还是内核空间分配的内存,通过查看huashe的配置文件发现,huashe的编译系统中设置的是用户空间3G,内核空间1Gkernel的配置中配置的是CONFIG_VMSPLIT_3G=y,由此可见这个是按照用户空间的虚拟内存大小来分配的。

重新编译内核后,下载后,系统恢复正常。

在整个移植过程中最常出现的问题就是netdmediaservice两个服务不能起来。这个可能是基于不同的服务器架构而引起的。通过替换lib文件夹能够使系统进入命令行。

更多相关文章

  1. Android学习笔记(六)-文件操作与SDCard读写访问
  2. Android实现在xml文件中引用自定义View的方法分析
  3. Logcat__查看Android系统日志
  4. AndroidStudioSDK下tools下各个文件(夹)的用处
  5. Android保存图片到系统图库
  6. android 存储数据与文件

随机推荐

  1. Android.DebugTools.Traceview & dmtrace
  2. android studio AppCompatActivity中onCr
  3. linux命令之ps源码,支持linux和android
  4. Android显示GIF动画完整示例(二)
  5. Android 在程序中重启APP的方法
  6. 【Android】广播的写法
  7. Android 相册选择照片或拍照获取图片系统
  8. android studio生成签名文件,以及SHA1和MD
  9. [置顶] Android(安卓)AutoLayout全新的适
  10. cocos2d-x 跨平台特性之ios向android移植