移植Android3.0 SDK到freescale imx51_bbg总结

移植Android3.0 SDK到freescale 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.rc、init.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/environment将Android的tools文件夹加入到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 mtd@system /system

    mount yaffs2 mtd@system /system ro remount

    mount yaffs2 mtd@userdata /data nosuid nodev

    mount yaffs2 mtd@cache /cache nosuid nodev

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

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

yaffs格式镜像解压方法为unyaffs system.img,unyaffs工具需要下载一个代码进行编译生成可执行文件,然后将它拷贝到/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下面的bin、xbin换掉后提示libc.so链接不上,而且还是进不了命令行,然后再将lib文件夹替换掉以后发现可以进入命令行了,但是还是不能进入界面。

然后就开始怀疑是交叉编译链的不同而导致的原因了,因为两种平台的服务器并不相同,模拟器用的是goldfish的虚拟处理器,是基于ARMv5架构的,而imx51_bbg是ARMv7架构的。这就要到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 mmap’s 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

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

       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,内核空间1G,kernel的配置中配置的是CONFIG_VMSPLIT_3G=y,由此可见这个是按照用户空间的虚拟内存大小来分配的。

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

 

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



-----------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/android_huber
交流邮箱:[email protected]
-----------------------------------------------

你可能感兴趣的:(android,脚本,System,Build,makefile,linker)