利用BLCR加速android的启动(android4.2)

BOSS要求提高安卓系统的启动速度,优化bootloader和kernel后,发现还是达不到要求,没办法才打起zygote的注意。

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.2.2
TARGET_PRODUCT=sabresd_6dq
TARGET_BUILD_VARIANT=user
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.5.0-41-generic-x86_64-with-Ubuntu-12.04-precise
HOST_BUILD_TYPE=release
BUILD_ID=1.0.0-rc3
OUT_DIR=out
============================================

以下参考shuaiff同学的部分研究成果:http://blog.csdn.net/shuaiff/article/details/5894646,感谢shuaiff同学的研究成果。

摘要:介绍了利用blcr对android启动速度进行优化的原理、实施步骤和注意点,在虚拟机上验证获得缩短10秒以上启动时间。

关键词:blcr  android  启动速度   zygote   类加载

引言 随着google的android操作系统在手机、平板电脑等领域大量使用,android的启动速度慢也成为许多使用者抱怨的缺点。相比手机这类平时较少开关机的设备,平板电脑在实际使用中开关的频率相对频繁,开机速度是影响客户感受的一个重要因素。Android启动过程分为linux内核载入,文件系统挂接,zygote进程启动和软件包扫描几个主要过程。其中耗时大户发生在zygote的类载入和软件包扫描过程两处,只要减少这两处的时间,启动速度就会发生明显的改变。如何有效加快启动速度是众多android产品制造者都感兴趣的技术。本文就缩短android 启动过程中公用类加载部分的一种技术做介绍,利用该方法,在虚拟机实际测试获得良好的结果。

背景知识 Zygote是android中的核心进程,其负责android其他应用和服务的孵化,zygote启动过程慢的一个原因在于

启动过程中需要提前加载公用类(由文件preloaded-classes定义),这种加载是android设计人员特意根据linux和嵌入式系统特性设计的,网络上有人尝试将这些类的加载去除以加快开机速度,这种违背设计者初衷的方法被否决(参考1)。对于单个进程而言,如果使用到这些公共类,都必须完成对应类的载入并初始化,由于zygote是后续所有android的父进程,采用Class.forName处理的公共类会被载入到内存并完成静态初始化,提前加载可以避免每个子进程调用时候需要生成公用类的副本(linux Copy-on-write特点),进而减少内存占用量以及后续启动其他程序的花销。这个加载过程关系到后续的性能,所以不能简单的跳过。载入的过程主要是对内存的操作过程,其中包括了大量的内存分配释放过程,该过程由于有上千个类需要操作而变得耗时较长。在实际应用中,由于framework部分较少升级,故这些公共类是不会被动态删减,考虑到这些特点,采用check point方式每次直接将zygote还原到完成类加载的阶段避开频繁的类操作显然可以提高速度。

BLCR (BerkeleyLab Checkpoint/Restart)是应用于linux下的check point/restore软件,它可以将正在运行于linux上的应用当前的运行点保存成为一个文件并且在以后的时间可以按照需要将该程序直接恢复到保存时候的状态。该软件官方网站在:http://ftg.lbl.gov/checkpoint。根据其FAQ介绍BLCR对保存和恢复的程序有部分限制:1 无法保存和恢复打开的sockets(TCP/IP,Unix domain等)2 无法保存和恢复Sys V IPC对象。3 在处理还没有回收僵尸子进程的父进程是需要注意。尽管有部分限制,只要在使用时候注意这些限制,利用其保存和恢复程序运行点和内存的能力完全可以避免程序每次不必要的初始化动作。Zygote在加载公共类前时候除了堆外其他资源使用很少,通过仔细的调整/恢复BLCR无法恢复的一些状态,是可以用check point形式来跳过类加载以缩短启动时间。 BLCR 包括内核驱动和应用库两部分,外部应用通过链接应用库和内核驱动进行交换实现应用的保存和恢复。下面就针对内核为3.0.35的android4.2介绍实现blcr的具体过程

实施过程:

1.需要的软件和工具:

blcr-0.8.5,截止目前最新的版本是这个

A machine that is running a supported architecture (x86 and x86_64 are fully supported and PPC/PPC64 and ARM are "Experimental") and Linux kernel 2.6.x or 3.x.y. 

android源代码,我的机器是freescale的imx6系列,android4.2,内核版本为3.0.35.

i.MX 6系列处理器推出了业界首个具有真正扩展性的多核平台,包括基于ARM® Cortex™-A9架构的单核、双核和四核系列产品。 在强大的生态体系支持下,i.MX 6系列成为开发一系列基于单一硬件设计的终端产品的理想平台。

 http://sourceforge.net/projects/android-dfb/pthread的补丁

 编译android和内核在这里不详述,需要指出的有两点。

1 编译内核时候注意加入可加载模块支持(Enable loadablemodule support),缺省的goldfish内核配置是不支持的。

2 需要对android的bionic的线程库进行扩展,扩展方法是采用上述软件的pthread文件替换相应线程库文件。

 在做所有工作之前,请在blcr的解压根目录下面新建一个shell文件,名字随便起,你可以起“cross-configure.sh”。至于为什么要这么做,因为官方文档推荐,也因为直接使用源码目录中的configure文件会带来很多麻烦,听好的没错。cross-configure.sh文件一开始的样子,你可以这样写:

1 #!/bin/bash
2 curpath=`pwd`
3 rm -rf `find ./ -name Makefile`

在做下面所有工作之前,请提前编译好kernel,切记!

以下参考yihui8同学的部分研究成果,再次表示感谢:http://blog.csdn.net/yihui8/article/details/6101224

直接使用android内建的编译器即可对内核驱动进行编译。编译过程只要指定正确的编译器路径和内核路径即可顺利编译。

编译不出blcr的两个内核文件的同学,大多数都是因为arm工具链没有设置正确,导致blcr的编译工程不能正确识别要生成的目标平台。出现下面的configue错误都是如此

1.LinuxThreads是kernel2.6之前的多线程库,而2.6以后的内核都换成POSIX实现的NPTL(Native POSIX Thread Library),有什么区别,为什么要这么做,大家自己google。

checking whether default pthreads library is LinuxThreads... configure: error: When cross-compiling, variable cross_linuxthreads must be set.

因为android4.2的内核版本是3.0.35,故我们要去掉对LinuxThreads的支持,现在请打开你的cross-configure.sh文件,在后面加入一下代码,现在它的样子,应该是这样:

1 #!/bin/bash
2 curpath=`pwd`
3 rm -rf `find ./ -name Makefile`
4 
5 export TARGET_TYPE=%MISSING%
6 export cross_stack_direction=-1
7 export cross_signum=64
8 export cross_linuxthreads=0

2.下面两个configure错误都是arm工具链设置错误导致,在这里我走了相当多的弯路,曾经怀疑过工具链问题,也曾经怀疑后目标平台设置问题,总之蛋都碎了一地...

 1 checking for parameters to interface GNU automake with Linux kbuild... KBUILD_EXTMOD=$(builddir)
 2 checking for flags to compile Linux kernel probes... FAILED
 3 make: Entering directory `/home/inuyasha/SDB/myandroid/kernel_imx'
 4 test -e include/generated/autoconf.h -a -e include/config/auto.conf || (        
 5     echo;                                
 6     echo "  ERROR: Kernel configuration is invalid.";        
 7     echo "         include/generated/autoconf.h or include/config/auto.conf are missing.";
 8     echo "         Run 'make oldconfig && make prepare' on kernel src to fix it.";    
 9     echo;                                
10     /bin/false)

 和

1 checking size of void *... (cached) 8
2 configure: error: CC='gcc' yields sizeof(void *) = 8 when expecting 4.

第一个error是你指定了正确的arm工具链,但是没有设置目标文件的平台。第二个error比较隐蔽,表面上看不出任何问题,实际上问题出在:configure: error: CC='gcc',这个什么意思呢?说明你的autotool根本不认识你的arm工具链,虽然你正确的指出了目标文件。具体原因不做熬述。其实你仔细观察会发现在开头有这么几行:

1 checking host system type... arm-unknown-linux-gnu
 1 checking for arm-linux-g++... no
 2 checking for arm-linux-c++... no
 3 checking for arm-linux-gpp... no
 4 checking for arm-linux-aCC... no
 5 checking for arm-linux-CC... no
 6 checking for arm-linux-cxx... no
 7 checking for arm-linux-cc++... no
 8 checking for arm-linux-cl.exe... no
 9 checking for arm-linux-FCC... no
10 checking for arm-linux-KCC... no
11 checking for arm-linux-RCC... no
12 checking for arm-linux-xlC_r... no
13 checking for arm-linux-xlC... no

这写错误信息,都说明你指定的工具链不正确导致识别不了host system和找不到你指定的工具链,所以说遇到问题,还是要静下心来,自己看看出错信息,别一味的指望google。

怎么改:

目前测试来看,gnu的arm工具链是可以用的,android源代码中自带的和其他第三方的,autotool都识别不出来,现在你的cross-configure.sh应该是这个样子:

 1 #!/bin/bash
 2 curpath=`pwd`
 3 rm -rf `find ./ -name Makefile`
 4 
 5 export TARGET_TYPE=%MISSING%
 6 export cross_stack_direction=-1
 7 export cross_signum=64
 8 export cross_linuxthreads=0
 9 export ARCH=arm
10 
11 export PATH=$PATH:.../arm-none-linux-gnueabi/bin      ---->这里请指定你的arm工具链目录
12 TOOLCHAIN=.../arm-none-linux-gnueabi/bin               ----->同上
13 
14 ./configure KCC=$TOOLCHAIN/arm-none-linux-gnueabi-gcc  LD=$TOOLCHAIN/arm-none-linux-gnueabi-ld --with-linux-src=$curpath/../../kernel_imx --with-linux=$curpath/../../kernel_imx --host=arm-none-linux-gnueabi

 最后在上面的文件后面加入:

1 cd blcr_imports/
2 make all
3 echo generated kernel module:`ls kbuild/*.ko`
4 cd ../cr_module/
5 make all
6 echo generated kernel module:`ls kbuild/*.ko`

生成blcr的两个内核模块。

 1   Building modules, stage 2.
 2   MODPOST 1 modules
 3   LD [M]  /home/inuyasha/SDB/myandroid/external/blcr-0.8.5/cr_module/kbuild/blcr.ko
 4 gmake[2]:正在离开目录 `/home/inuyasha/SDB/myandroid/kernel_imx'
 5 gmake[1]:正在离开目录 `/home/inuyasha/SDB/myandroid/external/blcr-0.8.5/cr_module/kbuild'
 6 Making all in .
 7 gmake[1]: 正在进入目录 `/home/inuyasha/SDB/myandroid/external/blcr-0.8.5/cr_module'
 8 gmake[1]: 没有什么可以做的为 `all-am'
 9 gmake[1]:正在离开目录 `/home/inuyasha/SDB/myandroid/external/blcr-0.8.5/cr_module'
10 generated kernel module:kbuild/blcr.ko

 zygote加入checkpoint 支持准备放在下一章来写,敬请期待。

  

知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

原文地址:https://www.cnblogs.com/tangdoudou/p/3369249.html